코딩하는 해맑은 거북이

[데이터시각화] Grid, 선/면 추가, 테두리 설정, Setting 변경 본문

Data Analysis & Viz

[데이터시각화] Grid, 선/면 추가, 테두리 설정, Setting 변경

#CJE 2023. 3. 22.
본 게시물의 내용은 '부스트캠프 AI Tech - Data Visualization(안수빈)' 강의를 듣고 작성하였다.
해당 글은 아래의 5가지를 다룬다.
🍀 Grid
  🚩 Student Score Dataset
🍀 선 추가하기 : Line
🍀 면 추가하기 : Span
🍀 테두리 설정하기 : Spines
🍀 Setting 변경

 

🍀 Grid

- 기본적인 Grid는 축과 평행한 선을 사용하여 거리 및 값 정보를 보조적으로 제공

  • 색은 다른 표현들을 방해하지 않도록 무채색 (color)
  • 항상 Layer 순서 상 맨 밑에 오도록 조정 (zorder)
  • 큰 격자/세부 격자 (which=‘major’ | ‘minor’ | ‘both’)
  • X축, Y축 따로 하거나, 동시에 설정할 수 있음 (axis=‘x’ | ‘y’ | ‘both’)
  • 선의 스타일과 두께 설정 (linestyle, linewidth)
fig, ax = plt.subplots()
ax.grid()
plt.show()

np.random.seed(970725)

x = np.random.rand(20)
y = np.random.rand(20)


fig = plt.figure(figsize=(16, 7))
ax = fig.add_subplot(1, 1, 1, aspect=1)


ax.scatter(x, y, s=150, 
           c='#1ABDE9',
           linewidth=1.5,
           edgecolor='black', zorder=10)


ax.set_xticks(np.linspace(0, 1.1, 12, endpoint=True), minor=True)

ax.set_xlim(0, 1.1)
ax.set_ylim(0, 1.1)

    
ax.grid(zorder=0, linestyle='--')    
# ax.grid(zorder=0, linestyle='--', which='minor')    # minor에만 grid
# ax.grid(zorder=0, linestyle='--', which='both')     # 둘다 grid
ax.set_title(f"Default Grid", fontsize=15, va='center', fontweight='semibold')

plt.tight_layout()
plt.show()

np.random.seed(970725)

x = np.random.rand(20)
y = np.random.rand(20)


fig = plt.figure(figsize=(16, 7))
ax = fig.add_subplot(1, 1, 1, aspect=1)


ax.scatter(x, y, s=150, 
           c='#1ABDE9',
           linewidth=1.5,
           edgecolor='black', zorder=10)


ax.set_xticks(np.linspace(0, 1.1, 12, endpoint=True), minor=True)

ax.set_xlim(0, 1.1)
ax.set_ylim(0, 1.1)

    
ax.grid(zorder=0, linestyle='--', axis='x', linewidth=2)    
# ax.grid(zorder=0, linestyle='--', which='minor')    # minor에만 grid
# ax.grid(zorder=0, linestyle='--', which='both')     # 둘다 grid
ax.set_title(f"Default Grid", fontsize=15, va='center', fontweight='semibold')

plt.tight_layout()
plt.show()

 

 

- 전형적인 Grid는 아니지만 여러 형태의 Grid가 존재

🟨 두 변수의 합이 중요하다면 (x+y = c)

  • X+Y = C를 사용한 Grid
  • 회색 선에 걸치는 값은 X+Y 값이 동일
  • Feature의 절대적 합이 중요한 경우 사용 (ex. 공격 + 수비 합으로 평가 / 국어+수학 비중 평가)
fig = plt.figure(figsize=(16, 7))
ax = fig.add_subplot(1, 1, 1, aspect=1)


ax.scatter(x, y, s=150, 
           c=['#1ABDE9' if xx+yy < 1.0 else 'darkgray' for xx, yy in zip(x, y)],
           linewidth=1.5,
           edgecolor='black', zorder=10)

## Grid Part
x_start = np.linspace(0, 2.2, 12, endpoint=True)

for xs in x_start:
    ax.plot([xs, 0], [0, xs], linestyle='--', color='gray', alpha=0.5, linewidth=1)


ax.set_xlim(0, 1.1)
ax.set_ylim(0, 1.1)

ax.set_title(r"Grid ($x+y=c$)", fontsize=15,va= 'center', fontweight='semibold')

plt.tight_layout()
plt.show()

 

 

🟨 비율이 중요하다면 (y = cx)

  • Y = CX를 사용한 Grid
  • 가파를 수록 Y/X가 커짐
  • Feature의 비율이 중요한 경우
fig = plt.figure(figsize=(16, 7))
ax = fig.add_subplot(1, 1, 1, aspect=1)


ax.scatter(x, y, s=150, 
           c=['#1ABDE9' if yy/xx >= 1.0 else 'darkgray' for xx, yy in zip(x, y)],
           linewidth=1.5,
           edgecolor='black', zorder=10)

## Grid Part
radian = np.linspace(0, np.pi/2, 11, endpoint=True)

for rad in radian:
    ax.plot([0,2], [0, 2*np.tan(rad)], linestyle='--', color='gray', alpha=0.5, linewidth=1)


ax.set_xlim(0, 1.1)
ax.set_ylim(0, 1.1)

ax.set_title(r"Grid ($y=cx$)", fontsize=15,va= 'center', fontweight='semibold')

plt.tight_layout()
plt.show()

 

 

🟨 두 변수의 곱이 중요하다면 (xy = c)

 

🟨 특정 데이터를 중심으로 보고 싶다면 ( (x-x')^2 + (y-y')^2 = c )

  • 동심원을 사용
  • 특정 지점에서 거리를 살펴볼 수 있음
  • 가장 가까운 포인트를 찾거나, 한 데이터에서 특정 범위의 데이터
fig = plt.figure(figsize=(16, 7))
ax = fig.add_subplot(1, 1, 1, aspect=1)


ax.scatter(x, y, s=150, 
           c=['darkgray' if i!=2 else '#1ABDE9'  for i in range(20)] ,
           linewidth=1.5,
           edgecolor='black', zorder=10)

## Grid Part
rs = np.linspace(0.1, 0.8, 8, endpoint=True)

for r in rs:
    xx = r*np.cos(np.linspace(0, 2*np.pi, 100))
    yy = r*np.sin(np.linspace(0, 2*np.pi, 100))
    ax.plot(xx+x[2], yy+y[2], linestyle='--', color='gray', alpha=0.5, linewidth=1)

    ax.text(x[2]+r*np.cos(np.pi/4), y[2]-r*np.sin(np.pi/4), f'{r:.1}', color='gray')

ax.set_xlim(0, 1.1)
ax.set_ylim(0, 1.1)

ax.set_title(r"Grid ($(x-x')^2+(y-y')^2=c$)", fontsize=15,va= 'center', fontweight='semibold')

plt.tight_layout()
plt.show()

 

- 전형적이지 않고, 구현도 까다롭지만 numpy + matplotlib으로 쉽게 구현 가능

  (다양한 예시: https://medium.com/nightingale/gotta-gridem-all-2f768048f934)

 

🚩 Student Score Dataset

import pandas as pd 

student = pd.read_csv('./StudentsPerformance.csv')
student.head()

 

 

🍀 선 추가하기 : Line

  • axvline() : 수직으로 선 그리기
  • axhline() : 수평으로 선 그리기
fig, ax = plt.subplots()

ax.set_aspect(1)
ax.axvline(0, color='red')
ax.axhline(0, color='green')

ax.set_xlim(-1, 1)
ax.set_ylim(-1, 1)

plt.show()

- ax의 전체 구간을 [0, 1]로 생각하여 특정 부분에만 선을 그릴 수 있다.

fig, ax = plt.subplots()

ax.set_aspect(1)
ax.axvline(0, ymin=0.3, ymax=0.7, color='red')

ax.set_xlim(-1, 1)
ax.set_ylim(-1, 1)

plt.show()

fig, ax = plt.subplots(figsize=(10, 10))
ax.set_aspect(1)

math_mean = student['math score'].mean()
reading_mean = student['reading score'].mean()

ax.axvline(math_mean, color='gray', linestyle='--')
ax.axhline(reading_mean, color='gray', linestyle='--')

ax.scatter(x=student['math score'], y=student['reading score'],
           alpha=0.5,
           color=['royalblue' if m>math_mean and r>reading_mean else 'gray'  for m, r in zip(student['math score'], student['reading score'])],
           zorder=10,
          )

ax.set_xlabel('Math')
ax.set_ylabel('Reading')

ax.set_xlim(-3, 103)
ax.set_ylim(-3, 103)
plt.show()

 

 

🍀 면 추가하기 : Span

  • axvspan : 수직으로 면 그리기
  • axhspan : 수평으로 면 그리기
fig, ax = plt.subplots()

ax.set_aspect(1)
ax.axvspan(0,0.5, color='red')
ax.axhspan(0,0.5, color='green')

ax.set_xlim(-1, 1)
ax.set_ylim(-1, 1)

plt.show()

- 선 그리는 것과 같이 특정 부분에만 면을 그릴 수 있다.

fig, ax = plt.subplots()

ax.set_aspect(1)
ax.axvspan(0,0.5, ymin=0.3, ymax=0.7, color='red')

ax.set_xlim(-1, 1)
ax.set_ylim(-1, 1)

plt.show()

 

- 특정 부분을 강조할 수 있지만, 오히려 특정 부분의 주의를 없앨 수도 있다.

fig, ax = plt.subplots(figsize=(8, 8))
ax.set_aspect(1)

math_mean = student['math score'].mean()
reading_mean = student['reading score'].mean()

ax.axvspan(-3, math_mean, color='gray', linestyle='--', zorder=0, alpha=0.3)
ax.axhspan(-3, reading_mean, color='gray', linestyle='--', zorder=0, alpha=0.3)

ax.scatter(x=student['math score'], y=student['reading score'],
           alpha=0.4, s=20,
           color=['royalblue' if m>math_mean and r>reading_mean else 'gray'  for m, r in zip(student['math score'], student['reading score'])],
           zorder=10,
          )

ax.set_xlabel('Math')
ax.set_ylabel('Reading')

ax.set_xlim(-3, 103)
ax.set_ylim(-3, 103)
plt.show()

 

🍀 테두리 설정하기 : Spines

- 대표적인 3가지

  • set_visible : 보일지 말지를 설정
  • set_linewidth : 테두리 두께 설정
  • set_position : 테두리의 위치 설정
    • 'center' -> ('axes', 0.5)
    • 'zero' -> ('data', 0.0)
fig = plt.figure(figsize=(12, 6))

_ = fig.add_subplot(1,2,1)
ax = fig.add_subplot(1,2,2)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_linewidth(1.5)
ax.spines['bottom'].set_linewidth(1.5)
plt.show()

fig = plt.figure(figsize=(12, 6))

_ = fig.add_subplot(1,2,1)
ax = fig.add_subplot(1,2,2)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)

ax.spines['left'].set_position('center')
ax.spines['bottom'].set_position('center')
plt.show()

fig = plt.figure(figsize=(12, 6))

ax1 = fig.add_subplot(1,2,1)
ax2 = fig.add_subplot(1,2,2)

for ax in [ax1, ax2]:
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)

ax1.spines['left'].set_position('center')
ax1.spines['bottom'].set_position('center')

ax2.spines['left'].set_position(('data', 0.3))  # 비율
ax2.spines['bottom'].set_position(('axes', 0.2))  # 비율

ax2.set_ylim(-1, 1)
plt.show()

fig = plt.figure(figsize=(12, 9))

ax = fig.add_subplot(aspect=1)

x = np.linspace(-np.pi, np.pi, 1000)
y = np.sin(x)

ax.plot(x, y)

ax.set_xlim(-np.pi, np.pi)
ax.set_ylim(-1.2, 1.2)

ax.set_xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi])
ax.set_xticklabels([r'$\pi$', r'-$-\frac{\pi}{2}$', r'$0$', r'$\frac{\pi}{2}$', r'$\pi$'],)

ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)

ax.spines['left'].set_position('center')
ax.spines['bottom'].set_position('center')
plt.show()

 

 

🍀 Setting 변경

- mpl을 rcParams로 커스터마이징하기

# 방법 1
plt.rcParams['lines.linewidth'] = 2
plt.rcParams['lines.linestyle'] = ':'

# plt.rcParams['figure.dpi'] = 150
# 방법 2
plt.rc('lines', linewidth=2, linestyle=':')
plt.plot([1, 2, 3])

plt.rcParams.update(plt.rcParamsDefault)	# Default 값으로 되돌리기

 

- mpl의 스타일 Theme를 변경하기

- 대표적으로 많이 사용하는 테마는 fivethirtyeight, ggplot 이 있다. 없으면 default

print(mpl.style.available)

mpl.style.use('seaborn')
# mpl.style.use('./CUSTOM.mplstyle') # 커스텀을 사용하고 싶다면

plt.plot([1, 2, 3])

with plt.style.context('fivethirtyeight'):
    plt.plot(np.sin(np.linspace(0, 2 * np.pi)))
plt.show()

plt.plot(np.sin(np.linspace(0, 2 * np.pi)))

 

 

 

 

 

'Data Analysis & Viz' 카테고리의 다른 글

[데이터시각화] Polar Coordinate - Polar, Radar Plot  (0) 2023.03.27
[데이터시각화] Seaborn  (0) 2023.03.27
[데이터시각화] Facet  (0) 2023.03.22
[데이터시각화] Color  (0) 2023.03.22
[데이터시각화] Text  (0) 2023.03.22
Comments