Python/Plot

[Python] matplotlib 으로 pandas data 그래프 그리기 :: multiple plots, Customizing Figure Layouts, scatter, boxplot

슈퍼짱짱 2021. 6. 10. 16:46
반응형

최종적으로 다음과 같이 group별로 Scatter 혹은 boxplot의 색상도 다르고, layout이 자유분방한 그래프를 그릴 것이다.

 

 

데이터는 numpy와 pandas를 활용하고, scatter와 boxplot은 matplotlib을 활용하며, Layout은 matplotlib의 gridspec를 활용한다.


1. Import Library

위에서 언급했듯, numpy, pandas, matplotlib 등 필요한 라이브러리를 불러온다.

 

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import gridspec

2. Create Data Set

x와 y, group으로 이루어진 50개의 dataframe을 생성했다.

group은 25개씩 A와 B로 나누어 주었다.

(이후 group에 따라 다른 색을 가진 scatter, boxplot을 그리기 위해 생성한 컬럼이다.)

 

data = pd.DataFrame({'x':range(0,50),
                    'y':np.random.rand(50),
                    'group':np.repeat(['A','B'], [25, 25], axis=0)})

 


3. Drawing Graph

먼저, group에 상관없이, Scatter Plot을 그리는 방법은 다음과 같다.

 

x와 y를 넣어주고, figsize는 생략가능하다.

 

data.plot(kind = "scatter",
         x = 'x',
         y = 'y',
         figsize = (10,5))

 

 

kind="scatter"를 빼주면 기본적으로 line으로 연결된 그래프가 생성된다.

 

data.plot(x = 'x',
          y = 'y',
         figsize = (10,5))

 

 

이를 group에 따라 다른 색상으로 그려주는 방법은 다음과 같다.

 

처음에 size 등 그래프의 기본적인 parameter들을 설정해준다.

group별로 지정해주고 싶은 색을 정의해주고, for 문으로 group별로 scatter plot을 그려준다.

 

fig,ax = plt.subplots(figsize=(10,5)) # size
colors = ['#F8766D',"gray"] # group별 color 지정
for i, (name,group) in enumerate(data.groupby('group')):
    group.plot(ax=ax,## Scatter by Group
               kind='scatter', 
               x="x", y="y",
               color=colors[i], 
               label = name)

 

 


다음으로, boxplot 그리는 방법이다.

 

그리고 싶은 컬럼을 지정한 후 boxplot()으로 바로 그려준다.

 

data[['y']].boxplot()

 

 

box 안의 color, line color 등 각각의 색상을 지정해주는 코드는 다음과 같다.

 

fig, ax = plt.subplots(figsize = (7,5)) # size
bp = ax.boxplot(data.y, patch_artist=True) # boxplot

for box in bp['boxes']: # box colors
    box.set(color='#F8766D') # box line color
    box.set(facecolor='Pink') # box color

for whisker in bp['whiskers']:
    whisker.set(color="DarkOrange")

for cap in bp['caps']:
    cap.set(color="Gray")

for median in bp['medians']:
    median.set(color="white")

 

 

각 컬러들을 설정해 줄 때 이름의 의미는 다음과 같다.

 

group별로 boxplot을 그리고, 색상도 설정해주는 방법은 다음과 같다.

 

fig,ax = plt.subplots(figsize=(10,5)) # size
colors = ['#F8766D',"gray"] # color

bp_dict = data[['y','group']].boxplot( # drawing boxplot by group
    ax = ax,
    by="group",
    return_type='both',
    patch_artist = True,
)

plt.suptitle("")

for row_key, (ax_,row) in bp_dict.iteritems(): # set colors
    ax_.set_xlabel('')
    for i,box in enumerate(row['boxes']):
        box.set_facecolor(colors[i])

 

 

참고로, 색상 지정 없이 그냥 group 별로만 그려줄 수도 있다.

 

data[['y','group']].boxplot(
    by="group",figsize=(10,5),
    return_type='both',
    patch_artist = True,
)

 

 


이번에는 matplotlibgridspec을 활용하여 한 번에 여러개의 그래프를 그리고, layout을 변경하는 방법을 알아보겠다.

 

먼저, figsize와 몇 개의 그래프를 하나에 그릴지 설정해준다.

몇 개의 row와 몇 개의 column으로 이루어진 그래프를 그릴 것인지, 각각 nrowsncols에 입력해주고,

만약, 비율을 다르게 그려주고 싶다면 heigth_ratioswidth_ratios도 입력해준다.(생략 가능)

 

fig = plt.figure(figsize=(18, 7)) # fig size
gs = gridspec.GridSpec(nrows=3, # row 몇 개 
                       ncols=2, # col 몇 개 
                       height_ratios=[1,2,3], # ratio of heithg
                       width_ratios=[3,1] # ratio of width
                      )

 

다음으로, 각각의 그래프를 채워준다.

 

가장 왼쪽 위부터 0, 오른쪽 위가 1,

그 아래가 2, 3

그 아래가 4, 5 순서이다.

 

ax1 = plt.subplot(gs[0])
myScatter(ax1)
ax1.set_title('[0]')

ax2 = plt.subplot(gs[1])
data.plot(ax = ax2,
          kind = "scatter",
         x="y", y="x", title = "[1]")

ax3 = plt.subplot(gs[2])
data.plot(ax = ax3,
         x="x", y="y", title = "[2]")

ax4 = plt.subplot(gs[3])
data.plot(ax = ax4,
         x="y", y="x", title = "[3]")

ax5 = plt.subplot(gs[4])
data[['x']].boxplot(ax = ax5)
ax5.set_title('[4]')

ax6 = plt.subplot(gs[5])
myBoxplot(ax6)
ax6.set_title('[5]')

plt.show()

 

결과는 다음과 같다.

위에서 지정해 준 대로 row가 3개, col이 2개이며,

heigth ratio와 width ratio도 지정해 준 대로 나타난 것을 볼 수 있다.

 

 

myScatter와 myBoxplot은 직접 정의한 function으로, 다음과 같다.

ax를 parameter로 전달받는 형태로, 전달받은 ax에 그림을 그려주는 function이다.

 

def myBoxplot(ax) :
    colors = ['#F8766D',"gray"]

    bp_dict = data[['y','group']].boxplot(
        ax = ax,
        by="group",figsize=(3,5),
        return_type='both',
        patch_artist = True,
    )

    plt.suptitle("")

    for row_key, (ax_,row) in bp_dict.iteritems():
        ax_.set_xlabel('')
        for i,box in enumerate(row['boxes']):
            box.set_facecolor(colors[i])
            
def myScatter(ax) :
    colors = ['#F8766D',"gray"]
    for i, (name,group) in enumerate(data.groupby('group')):
        group.plot(ax=ax,## Scatter by Group
                   kind='scatter', 
                   x="x", y="y",
                   color=colors[i],
                   label = name)

0, 1, ... , 5 로 인덱싱하지 않고, 2차원 행렬을 나타낼 때 처럼 [0,0], [0,1] ... 로 나타낼 수도 있다.

 

fig = plt.figure(figsize=(18, 7)) # fig size
gs = gridspec.GridSpec(nrows=3, # row 몇 개 
                       ncols=2, # col 몇 개 
                       height_ratios=[1,2,3], # ratio of heithg
                       width_ratios=[3,1] # ratio of width
                      )

# fist graph
ax1 = plt.subplot(gs[0,0])
myScatter(ax1)
ax1.set_title('[0,0]')

# second graph
ax2 = plt.subplot(gs[0,1])
data.plot(ax = ax2,
          kind = "scatter",
         x="y", y="x", title = "[0,1]")

ax3 = plt.subplot(gs[1,0])
data.plot(ax = ax3,
         x="x", y="y", title = "[1,0]")

ax4 = plt.subplot(gs[1,1])
data.plot(ax = ax4,
         x="y", y="x", title = "[1,1]")

ax5 = plt.subplot(gs[2,0])
data[['x']].boxplot(ax = ax5)
ax5.set_title('[2,0]')

ax6 = plt.subplot(gs[2,1])
myBoxplot(ax6)
ax6.set_title('[2,1]')

plt.show()

 


마지막으로, 가장 처음 보여주었던 그래프처럼 모든 6개의 그래프가 다 채워지지 않은, 일정 그래프만 크게 그리는 방법은 다음과 같다.

 

fig = plt.figure(figsize=(18, 7)) # fig size
gs = gridspec.GridSpec(nrows=3, # row 몇 개 
                       ncols=2, # col 몇 개 
                       height_ratios=[1,2,3], # ratio of heithg
                       width_ratios=[3,1] # ratio of width
                      )

# fist graph
ax1 = plt.subplot(gs[0,0])
myScatter(ax1)
ax1.set_title('[0,0]')

# second graph
ax2 = plt.subplot(gs[0:2,1])
data.plot(ax = ax2,
          kind = "scatter",
         x="y", y="x", title = "[0:2,1]")

# ax3 = plt.subplot(gs[1,0])
# data.plot(ax = ax3,
#          x="x", y="y", title = "[1,0]")

# ax4 = plt.subplot(gs[1,1])
# data.plot(ax = ax4,
#          x="y", y="x", title = "[1,1]")

ax5 = plt.subplot(gs[1:,0])
data[['x']].boxplot(ax = ax5)
ax5.set_title('[1:,0]')

ax6 = plt.subplot(gs[2,1])
myBoxplot(ax6)
ax6.set_title('[2,1]')

plt.show()

 

[1,0] 그래프를 지우고, [2,0] 그래프를 [1:,0] 으로 두 칸을 채워 그렸고,

마찬가지로 [1,1] 그래프를 지우고, [0,1] 그래프를 [0:2,1] 로 두 칸을 채워 그렸다.

 

반응형