본문 바로가기

Data Analysis/visualization

[Python] y축 2개를 이용한 산점도 + 추세선 그리기(그룹별 색상 옵션 추가)

728x90
반응형


이번 포스팅에서는 지난 포스팅에 이어서
x축과 y축 2개(2개 변수) 를 기준으로 산점도를 그리고,
산점도 위에 변수 별로 추세선을 그리는 스크립트를 공유하고자 합니다.


사실 지난 글에서 그룹별 색상을 표현하는 코드를 먼저 만든 후에
그룹별로 모두 색깔을 나눠서 볼 경우 그래프 가독성이 떨어지는 문제가 생기더라구요.

그래서 이제 그룹별 색깔 구분을 없애고, y축 2개에 표현되는 변수만 2개의 색깔로 구분하도록
스크립트를 수정해서 다시 공유해요~!



https://woomii.tistory.com/18

 

[Python] y축 2개를 이용한 산점도 + 추세선 그리기(&그룹별 색상)

이번 코드는 위의 산점도와 같이 X축을 중심으로 좌측에 y1, 우측에 y2 2개의 y축을 그리고, 각 그룹별로 색상을 다르게 해서 산점도를 그린 후 산점도 위에 그룹+변수별 추세선을 그리고, 가독성

woomii.tistory.com

 

함수 설명

def ScatterPlotting_2yaxis

  • x, y1, y2 : 그래프에 나타내고자 하는 수치 데이터
  • group : 그래프에 나타내고자 하는 그룹(카데고리)
  • save_path='C:/' : 그래프 그림 파일 저장 경로
  • input_figsize=(7, 6) : 그림 크기 설정
  • ssize_setting = 30 : 산점도의 점 크기 설정
  • alpha_setting = 0.5 : 산점도의 점 투명도 설정
  • fontsize_setting = 8 : 그래프 축, 제목 등 텍스트 폰트 크기 설정
  • axis_labels=('x', 'y1', 'y2') : x축, y축(좌측), y축(우측) 라벨 설정
  • group_coloring = True : 그룹별 색상 구분 True 일 경우 반영, False일 경우 그룹별 색상 동일

 


전체 코드

def ScatterPlotting_2yaxis(x, y1, y2, group, save_path='C:/', 
			input_figsize=(7, 6), ssize_setting = 30, alpha_setting = 0.5, fontsize_setting = 8,
            axis_labels=('x', 'y1', 'y2'), group_coloring = True):
    os.chdir(save_path)
    fig, ax1 = plt.subplots()
    ax2 = ax1.twinx()
    ax1.set_ylim(0, max(y1)*1.1)
    ax2.set_ylim(0, max(y2)*1.1)
    ax1.grid(True)
    ax1.set_xlabel(axis_labels[0], fontsize=fontsize_setting)
 
    if group_coloring == True:
        df = pd.concat([x, y1, y2, group], axis=1)
        df.columns = ['x', 'y1', 'y2', 'group']
        c_lst = [plt.cm.Paired(a) for a in np.linspace(0.0, 1.0, 2 * len(set(df['group'])))]
 
        group_lst = df.groupby('group', as_index=False).mean().group.tolist()
        print(df, group_lst)

        # y1
        for i, g in enumerate(df.groupby('group')):
            # calc the trendline
            z = np.polyfit(g[1]['x'].tolist(), g[1]['y1'].tolist(), 1)
            p = np.poly1d(z)

            ax1.scatter(x=g[1]['x'], y=g[1]['y1'], color=c_lst[i], label='{}_{}'.format(group_lst[i], axis_labels[1]),
                        s=ssize_setting, alpha=alpha_setting)
            ax1.set_ylabel(axis_labels[1], fontsize = fontsize_setting)
            ax1.plot(g[1]['x'], p(g[1]['x']), color = c_lst[i], linestyle = "-.", label='{}_{}_line'.format(group_lst[i], axis_labels[1]))
 
        # y2
        for i, g in enumerate(df.groupby('group')):
            # calc the trendline
            z2 = np.polyfit(g[1]['x'].tolist(), g[1]['y2'].tolist(), 1)
            p2 = np.poly1d(z2)
            ax2.scatter(x=g[1]['x'], y=g[1]['y2'], color = c_lst[len(set(df['group'])) + i], label='{}_{}'.format(group_lst[i], axis_labels[2]),
                        s=ssize_setting, alpha=alpha_setting)
            ax2.set_ylabel(axis_labels[2], fontsize = fontsize_setting)
            ax2.plot(g[1]['x'], p2(g[1]['x']), color = c_lst[len(set(df['group'])) + i]
                                      , linestyle = ":", label='{}_{}_line'.format(group_lst[i], axis_labels[2]))

        # ask matplotlib for the plotted objects and their labels
        sct1, labels1 = ax1.get_legend_handles_labels()
        sct2, labels2 = ax2.get_legend_handles_labels()
        ax2.legend(sct1 + sct2, labels1 + labels2, fontsize = 'small', loc='center left', bbox_to_anchor=(1.1, 0.5))
 
        plt.title(axis_labels[0] + '_' + axis_labels[1] + '/' + axis_labels[2] +
                      "[" + str(len(group_lst)) + "groups_" + str(len(x)) + "])", fontsize=fontsize_setting*1.2)
 
        saveNm_fig = '{}_{}_{}_{}groups_scatterplot_{}.png'.format(axis_labels[0], axis_labels[1], axis_labels[2], str(len(group_lst)), str(len(x)))

    else:  # 전체 데이터를 동일 색깔로 표시
        # calc the trendline
        z = np.polyfit(x, y1, 1)
        p = np.poly1d(z)
        ax1.scatter(x = x, y = y1, s=ssize_setting, alpha=alpha_setting, color = 'red', label = axis_labels[1])
        ax1.set_ylabel(axis_labels[1], fontsize = fontsize_setting)
        ax1.plot(x, p(x), "r:", label='{}_line'.format(axis_labels[1]))

        z = np.polyfit(x, y2, 1)
        p = np.poly1d(z)

        ax2.scatter(x = x, y = y2, s=ssize_setting, alpha=alpha_setting, color = 'green', label = axis_labels[2])
        ax2.set_ylabel(axis_labels[2], fontsize = fontsize_setting)
        ax2.plot(x, p(x), "g:", label='{}_line'.format(axis_labels[2]))
 
        # ask matplotlib for the plotted objects and their labels
        sct1, labels1 = ax1.get_legend_handles_labels()
        sct2, labels2 = ax2.get_legend_handles_labels()
        ax2.legend(sct1 + sct2, labels1 + labels2, fontsize = 'small', loc='center left', bbox_to_anchor=(1.1, 0.5))
 
        plt.title(axis_labels[0] + '_' + axis_labels[1] + '/' + axis_labels[2] +
                      "[" + str(len(x)) + "])", fontsize=fontsize_setting*1.2)

        saveNm_fig = '{}_{}_{}_scatterplot_{}.png'.format(axis_labels[0], axis_labels[1], axis_labels[2], str(len(x)))

    plt.savefig(fname=saveNm_fig, dpi=300, bbox_inches='tight')
    plt.show()


출력 결과

ScatterPlotting_2yaxis(
    x = df.sepal_length, y1 = df.sepal_width, y2 = df.petal_length, group = df.group, 
    save_path='D:/', input_figsize=(7, 6), ssize_setting = 20, alpha_setting = 0.5, fontsize_setting = 11, 
    axis_labels=('sepal_length', 'sepal_width', 'petal_length'),
    group_coloring = True)

ScatterPlotting_2yaxis(
    x = df.sepal_length, y1 = df.sepal_width, y2 = df.petal_length, group = df.group, 
    save_path='D:/', input_figsize=(7, 6), ssize_setting = 20, alpha_setting = 0.5, fontsize_setting = 11, 
    axis_labels=('sepal_length', 'sepal_width', 'petal_length'),
    group_coloring = False)

 

y축이 2개인 산점도(그룹별 색상 구분)

 

y축이 2개인 산점도(그룹별 색상 구분 X)

 

반응형