코딩하는 해맑은 거북이

[데이터시각화] Color 본문

Data Analysis & Viz

[데이터시각화] Color

#CJE 2023. 3. 22.
본 게시물의 내용은 '부스트캠프 AI Tech - Data Visualization(안수빈)' 강의를 듣고 작성하였다.
해당 글은 아래의 4가지를 다룬다.
🍀 Color
🍀 Color Palette
   🚩 Student Score Dataset
   🟨 범주형 (Categorical)
   🟨 연속형 (Sequential)
   🟨 발산형 (Diverge)
🍀 강조, 색상 대비
🍀 색각 이상

 

🍀 Color

- 위치와 색은 가장 효과적인 채널 구분
- 위치는 시각화 방법에 따라 결정되고, 색은 우리가 직접적으로 골라야 한다.
- 사람이 공통적으로 색이 가지는 느낌은 다르다.

- 심미적으로 화려한 것은 분명 매력적이다. 하지만, 화려함은 시각화의 일부 요소!
- 가장 중요한 것은 독자에게 원하는 인사이트를 전달!
  → 전하고 싶은 내용을 모두 전달했는가 + 그 과정에서 오해는 없었는가

- 우리는 살면서 이미 많은 색을 사용했다. 즉, 기존 정보와 느낌을 잘 활용하는 것이 중요
  ex) 높은 온도에는 파랑, 낮은 온도에는 빨강이라면?
  ex) 카X오가 초록색, 네X버가 노란색이라면?
- 무슨 색을 사용할지 모르겠다면, 다른 사례 스터디를 통해 색상 선택하거나 이미 사용하는 색을 사용할 것.

- HSI 색상

  • Hue(색조) : 빨강, 파랑, 초록 등 색상으로 생각하는 부분
    • 빨강에서 보라색까지 있는 스펙트럼에서 0-360으로 표현
  • Saturate(채도) : 무채색과의 차이
    • 선명도라고 볼 수 있음 (선명하다와 탁하다.)
  • Lightness(광도) : 색상의 밝기

 

🍀 Color Palette

🚩 앞서 데이터셋 준비! Student Score Dataset 

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

 

 

🟨 범주형 (Categorical)

- Discrete, Qualitative 등 다양한 이름으로 불림
- 독립된 색상으로 구성되어 범주형 변수에 사용
- 최대 10개의 색상까지 사용하고, 그 외에는 기타로 묶는다
- 색의 차이로 구분하는 것이 특징이다. 채도, 명도를 개별적 조정은 지양한다

- 일반적으로 tab10과 Set2가 가장 많이 사용된다

* Built-in Colormap 사용하기 : plt.cm.get_cmap(범주형컬러맵종류).colors

# Group to Number
groups = sorted(student['race/ethnicity'].unique())
gton = dict(zip(groups , range(5)))

# Group에 따라 색 1, 2, 3, 4, 5
student['color'] = student['race/ethnicity'].map(gton)
from matplotlib.colors import ListedColormap

qualitative_cm_list = ['Pastel1', 'Pastel2', 'Accent', 'Dark2', 'Set1', 'Set2', 'Set3', 'tab10']

fig, axes = plt.subplots(2, 4, figsize=(20, 8))
axes = axes.flatten()

student_sub = student.sample(100)

for idx, cm in enumerate(qualitative_cm_list):    
    pcm = axes[idx].scatter(student_sub['math score'], student_sub['reading score'],
                     c=student_sub['color'], cmap=ListedColormap(plt.cm.get_cmap(cm).colors[:5])
                     )
    cbar = fig.colorbar(pcm, ax=axes[idx], ticks=range(5))
    cbar.ax.set_yticklabels(groups)
    axes[idx].set_title(cm)
    
plt.show()

 

 

🟨 연속형 (Sequential)

- 정렬된 값을 가지는 순서형, 연속형 변수에 적합
- 연속적인 색상을 사용하여 값을 표현
  → 어두운 배경에서는 밝은 색이, 밝은 배경에서는 어두운 색이 큰 값을 표현
- 색상은 단일 색조로 표현하는 것이 좋고, 색의 밝기를 조정한다
- 균일한 색상 변화가 중요

- Heatmap, Contour Plot, 지리지도 데이터, 계층형 데이터에도 적합

sequential_cm_list = ['Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds',
            'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu',
            'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn']

fig, axes = plt.subplots(3, 6, figsize=(25, 10))
axes = axes.flatten()

student_sub = student.sample(100)

for idx, cm in enumerate(sequential_cm_list):    
    pcm = axes[idx].scatter(student['math score'], student['reading score'],
                            c=student['reading score'], 
                            cmap=cm,
                            vmin=0, vmax=100
                    
                     )
    fig.colorbar(pcm, ax=axes[idx])
    axes[idx].set_title(cm)
    
plt.show()

 

* imshow

- colormap의 디폴트 값이 viridis로 설정

- viridis colormap은 최솟값이 보라, 최댓값이 노랑

- 우리가 입력한 숫자를 0~1 사이로 노멀라이즈하여 색으로 나타낸다

im = np.arange(100).reshape(10, 10)
fig, ax = plt.subplots(figsize=(10, 10))
ax.imshow(im)
plt.show()

이를 활용해서 github 잔디밭을 만들 수 있다.

im =  np.random.randint(10, size=(7, 52))
fig, ax = plt.subplots(figsize=(20, 5))
ax.imshow(im, cmap='Greens')
ax.set_yticks(np.arange(7)+0.5, minor=True)
ax.set_xticks(np.arange(52)+0.5, minor=True)
ax.grid(which='minor', color="w", linestyle='-', linewidth=3)
plt.show()

 

 

🟨 발산형 (Diverge)

- 연속형과 유사하지만 중앙을 기준으로 발산
- 상반된 값(ex. 기온)이나, 서로 다른 2개(ex. 지지율)을 표현하는 데 적합
- 양 끝으로 갈수록 색이 진해지며, 중앙의 색은 양쪽의 점에서 편향되지 않아야 함
- 중앙의 색은 꼭 무채색일 필요는 없음.

from matplotlib.colors import TwoSlopeNorm

diverging_cm_list = ['PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu',
            'RdYlBu', 'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic']

fig, axes = plt.subplots(3, 4, figsize=(20, 15))
axes = axes.flatten()

offset = TwoSlopeNorm(vmin=0, vcenter=student['reading score'].mean(), vmax=100)
# 평균값을 0.5로, 작아질수록 0, 클수록 1에 가깝게 바꾸는 것

student_sub = student.sample(100)

for idx, cm in enumerate(diverging_cm_list):    
    pcm = axes[idx].scatter(student['math score'], student['reading score'],
                            c=offset(student['math score']), 
                            cmap=cm,
                     )
    cbar = fig.colorbar(pcm, ax=axes[idx], 
                        ticks=[0, 0.5, 1], 
                        orientation='horizontal'
                       )
    cbar.ax.set_xticklabels([0, student['math score'].mean(), 100])
    axes[idx].set_title(cm)
    
plt.show()

 

 

 

🍀 강조, 색상 대비

- 데이터에서 다름을 보이기 위해 Highlighting 가능
- 강조를 위한 방법 중 하나. 색상 대비(Color Contrast) 사용

fig = plt.figure(figsize=(18, 15))
groups = student['race/ethnicity'].value_counts().sort_index()

ax_bar = fig.add_subplot(2, 1, 1)
ax_bar.bar(groups.index, groups, width=0.5)

ax_s1 = fig.add_subplot(2, 3, 4)
ax_s2 = fig.add_subplot(2, 3, 5)
ax_s3 = fig.add_subplot(2, 3, 6)

ax_s1.scatter(student['math score'], student['reading score'])
ax_s2.scatter(student['math score'], student['writing score'])
ax_s3.scatter(student['writing score'], student['reading score'])

for ax in [ax_s1, ax_s2, ax_s3]:
    ax.set_xlim(-2, 105)
    ax.set_ylim(-2, 105)

plt.show()

a_color, nota_color = 'black', 'lightgray'

# 그룹A는 black, 아니면 lightgray
colors = student['race/ethnicity'].apply(lambda x : a_color if x =='group A' else nota_color)
color_bars = [a_color] + [nota_color]*4

fig = plt.figure(figsize=(18, 15))
groups = student['race/ethnicity'].value_counts().sort_index()

ax_bar = fig.add_subplot(2, 1, 1)
ax_bar.bar(groups.index, groups, color=color_bars, width=0.5)

ax_s1 = fig.add_subplot(2, 3, 4)
ax_s2 = fig.add_subplot(2, 3, 5)
ax_s3 = fig.add_subplot(2, 3, 6)

ax_s1.scatter(student['math score'], student['reading score'], color=colors, alpha=0.5)
ax_s2.scatter(student['math score'], student['writing score'], color=colors, alpha=0.5)
ax_s3.scatter(student['writing score'], student['reading score'], color=colors, alpha=0.5)

for ax in [ax_s1, ax_s2, ax_s3]:
    ax.set_xlim(-2, 105)
    ax.set_ylim(-2, 105)

plt.show()
  • 명도 대비 : 밝은 색과 어두운 색을 배치하면 밝은 색은 더 밝게, 어두운 색은 더 어둡게 보임 (회색검정)
    • 위 코드에서 색상만 변경 : a_color, nota_color = 'black', 'lightgray'

 

 

  • 색상 대비 : 가까운 색은 차이가 더 크게 보임 (파랑보라, 빨강보라)
    • 위 코드에서 색상만 변경 : a_color, nota_color = 'purple', 'blue'

 

  • 채도 대비 : 채도의 차이. 채도가 더 높아보임 (회색주황)
    • 위 코드에서 색상만 변경 : a_color, nota_color = 'orange', 'lightgray'

  • 보색 대비 : 정반대 색상을 사용하면 더 선명해 보인다. (빨강초록)
    • 위 코드에서 색상만 변경 : a_color, nota_color = 'tomato', 'lightgreen'

🍀 색각 이상

- 삼원색 중에 특정 색을 감지 못하면 색맹
- 부분적 인지 이상이 있다면 색약
- 색 인지가 중요한 분야(과학/연구 등)에 있어서는 이에 대한 고려가 필수

 

 

Comments