#!/usr/bin/env python
# coding: utf-8
# # Matplotlib을 활용한 시각화 1
# - Matplotlib은 NumPy 배열을 기반으로 만들어진 다중 플랫폼 데이터 시각화 라이브러리로서 광범위한 SciPy 스택과 함께 작업하기 위해 설계됨
# - 다양한 운영체제와 그래픽 백엔드에서 잘 동작한다는 장점이 있음
# - D3js와 HTML5 캔버스를 기반으로 한 웹 시각화 툴킷과 함께 R언어의 ggplot과 ggvis 같은 새로운 도구와 비교해 보면 종종 Matplotlib이 구식으로 느껴질수도 있지만 테스트가 잘 된 교차 플랫폼 그래픽 엔진으로서의 Matplotlib의 강점을 무시할 수 없음
# ## 일반적인 Matplotlib 사용법
# ### 1. matplotlib 임포트하기
# In[1]:
import matplotlib.pyplot as plt
import numpy as np
import warnings
warnings.filterwarnings('ignore')
# ### 2. 스타일 설정하기
# In[2]:
# 전형적인 classic 스타일을 선택했다.
# 더 많은 스타일은 https://matplotlib.org/gallery/style_sheets/style_sheets_reference.html 여기를 참고.
plt.style.use('classic')
# ### 3. show()
# - 현재 활성화된 모든 그림 객체를 찾아서 그림을 표시하는 하나 이상의 대화창을 연다.
# In[3]:
x = np.linspace(0, 10, 100)
display(x)
# cos 함수, sin 함수를 그려본다.
plt.plot(x, np.sin(x))
plt.plot(x, np.cos(x))
# show 명령어는 시스템의 대화형 그래픽 벡엔드와 상호작용을해야 하기 때문에 내부에서 많은 작업을 수행한다.
plt.show()
# - `plt.show()` 파이썬 세션당 한 번만 사용할 수 있어서 대체로 스크립트의 맨 마지막에 사용된다.
# ### 4. %matplotlib
# - IPython shell에서 대화식으로 Matplotlib을 사용하기 위해서는 `%matplotlib` 명령어를 사용하면 된다.
# - 이 모드에서는 `show()` 함수를 사용하지 않아도 된다.
# In[4]:
get_ipython().run_line_magic('matplotlib', '')
# In[5]:
# 노트북에 플롯의 정적 이미지를 삽입할 수 있다. 커널/세션당 한 번만 실행하면 된다.
get_ipython().run_line_magic('matplotlib', 'inline')
# In[6]:
x = np.linspace(0, 10, 100)
# 해당 plot을 사진 파일로 저장할 때 사용할 것이다.
fig = plt.figure()
plt.plot(x, np.sin(x), '-')
plt.plot(x, np.cos(x), '--')
# ### 5. 그림을 파일로 저장하기
# In[7]:
fig.savefig('my_figure.png')
# In[8]:
# 이 명령어를 실행하면, 그림 파일이 저장된 것을 확인할 수 있다. !는 리눅스 명령어 모드로 진입할 수 있도록 해주는 것.
get_ipython().system('ls -lh my_figure.png')
# In[9]:
# 외부에 있던 파일을 호출해서 표시해보자.
from IPython.display import Image
Image('my_figure.png')
# In[10]:
# 저장 가능한 파일의 종류는 무엇이 있을까?
fig.canvas.get_supported_filetypes()
# ## 두 개의 인터페이스
# - Matlab 스타일의 상태 기반 인터페이스
# - 객체지향 인터페이스
# ### 1. 매트랩 스타일의 인터페이스
# - `Matplotlib`은 원래 매트랩(MATLAB) 사용자를 위한 파이썬 대안으로 제작됐으며, `Matplotlib`이 제공하는 구문의 대부분이 그 사실을 반영한다.
# In[11]:
"""매트랩 사용자들에게 친숙해보이는 코드"""
# 플롯 그림을 생성
plt.figure()
# 두 개의 패널 중 첫 번째 패널을 생성하고 현재 축(axis)을 설정
plt.subplot(2, 1, 1)
plt.plot(x, np.sin(x))
# 두 번째 패널을 생성하고 현재 축(axis)을 설정
plt.subplot(2, 1, 2)
plt.plot(x, np.cos(x))
# - 이 인터페이스는 **상태를 저장**한다. 따라서 plt 명령어가 적용되는 곳에 있는 현재 그림과 축을 기억한다.
# - 만약 두 번째 패널에 대해서 작업하다가, 첫 번째 패널로 돌아가서 다시 작업하려면?
# ### 2. 객체지향 인터페이스
# - 객체지향 인터페이스에서 플로팅 함수는 "활성화된" 그림이나 축의 개념에 의존하지 않는 명시적은 `Figure`와 `Axes` 객체의 **메서드**이다.
# In[12]:
# 먼저 플롯 그리드를 생성
# ax는 두 개의 축 객체의 배열이 된다.
fig, ax = plt.subplots(2)
# 적절한 객체에서 plot() 메서드를 호출
ax[0].plot(x, np.sin(x))
ax[1].plot(x, np.cos(x))
# - 사실 어떤 스타일을 선택할지는 대체적으로 취향 문제이지만, 플롯이 복잡해질수록 객체지향 방식을 채택할 수밖에 없다.
# ## 간단한 라인 플롯
# In[13]:
# 스타일을 변경하자.
plt.style.use('seaborn-whitegrid')
# - `plt.Figure` 클래스의 인스턴스 : 축, 그래픽, 텍스트, 레이블을 표시하는 모든 객체를 포함하는 하나의 컨테이너로 생각하면 된다.
# - `plt.Axes` 클래스의 인스턴스 : 눈금과 레이블이 있는 테두리 상자로 나중에 시각화를 형성하는 플롯 요소를 포함하게 된다.
# In[14]:
# 그림(figure)과 축(axes)을 만드는 명령어
fig = plt.figure()
ax = plt.axes()
# In[15]:
# 간단한 Sin 곡선으로 플로팅을 시작해보자.
x = np.linspace(0, 10, 1000)
plt.plot(x, np.sin(x))
# In[16]:
plt.plot(x, np.sin(x))
plt.plot(x, np.cos(x))
# ### 1. 플롯 수정하기: 선 색생과 스타일
# In[17]:
"""색상을 변경하는 다양한 방법 1"""
plt.plot(x, np.sin(x - 0), color='blue')
plt.plot(x, np.sin(x - 1), color='g')
plt.plot(x, np.sin(x - 2), color='0.75')
# In[18]:
"""색상을 변경하는 다양한 방법 2"""
plt.plot(x, np.sin(x - 0), color='#FFDD44')
plt.plot(x, np.sin(x - 1), color=(1.0, 0.2, 0.3))
plt.plot(x, np.sin(x - 2), color='chartreuse')
# In[19]:
"""선 스타일을 조정하는 다양한 방법 1"""
plt.plot(x, x + 0, linestyle='solid')
plt.plot(x, x + 1, linestyle='dashed')
plt.plot(x, x + 2, linestyle='dashdot')
plt.plot(x, x + 3, linestyle='dotted')
# In[20]:
"""선 스타일을 조정하는 다양한 방법 2"""
plt.plot(x, x + 0, linestyle='-') # solid
plt.plot(x, x + 1, linestyle='--') # dashed
plt.plot(x, x + 2, linestyle='-.') # dashdot
plt.plot(x, x + 3, linestyle=':') # dotted
# In[21]:
"""색상과 선 스타일을 동시에 조정하는 다양한 방법 2"""
plt.plot(x, x + 0, '-g') # solid green
plt.plot(x, x + 1, '--c') # dashed cyan
plt.plot(x, x + 2, '-.k') # dashdot black
plt.plot(x, x + 3, ':r') # dotted red
# ### 2. 플롯 조정하기: 축 경계
# - 축 경계를 조정하는 가장 기본적인 방식은 `plt.xlim()`과 `plt.ylim()` 메서드를 사용하는 것.
# In[22]:
plt.plot(x, np.sin(x))
display(plt.xlim(-1, 11))
display(plt.ylim(-1.5, 1.5))
# - 두 축 중 하나를 역으로 표시해야 한다면 단순히 인수의 순서를 바꾸면 된다.
# In[23]:
plt.plot(x, np.sin(x))
display(plt.xlim(10, 0))
display(plt.ylim(1.2, -1.2))
# - `plt.axis()`는 현재 플롯 주변의 경계를 자동으로 더 밀착시켜준다.
# In[24]:
plt.plot(x, np.sin(x))
plt.axis('tight')
# - 가로세로 비율을 균등하게 설정해 화면상에 `x`축의 한 단위와 `y`축의 한 단위가 똑같게 설정
# In[25]:
plt.plot(x, np.sin(x))
plt.axis('equal')
# ### 3. 플롯에 레이블 붙이기
# - 라벨과 제목을 간단하게 설정하기
# In[26]:
plt.plot(x, np.sin(x))
plt.title("A Sine Curve")
plt.xlabel("x")
plt.ylabel("sin(x)")
# - 여러 선을 표시하는 경우 각 선의 유형에 레이블을 붙이는 플롯 범례를 생성
# In[27]:
# 곡선별로 라벨링을 한다.
plt.plot(x, np.sin(x), '-g', label='sin(x)')
plt.plot(x, np.cos(x), ':b', label='cos(x)')
# x, y의 간격을 동일하게한다.
plt.axis('equal')
# 라인 스타일과 색상을 기록하고 이를 정확한 레이블과 매칭하도록 하는 메서드.
plt.legend()
# ## 간단한 산점도
# - 산점도는 데이터의 퍼짐 정도를 보기에 좋은 도구 중 하나이다.
# ### 1. plt.plot()을 이용한 산점도
# In[28]:
x = np.linspace(0, 10, 30)
y = np.sin(x)
# 산점도 표현을 위해 plot의 입력인수를 'o'로 한다.
plt.plot(x, y, 'o', color='black')
# In[29]:
rng = np.random.RandomState(0)
for maker in ['o', '.', ',', 'x', '+', 'v', '^', '<', '>', 's', 'd']:
plt.plot(rng.rand(5), rng.rand(5), maker, label="maker='{0}'".format(maker))
plt.legend(numpoints=1)
plt.xlim(0, 1.8)
# In[30]:
# 더 간단하게 나타내는 방법
# 선(-), 원 표시 기호(o), 검정색(k)
plt.plot(x, y, '-ok')
# In[31]:
# 다양한 선과 표시 속성을 지정
# p : 오각형
plt.plot(x, y, '-p', color='gray', markersize=15, linewidth=4,
markerfacecolor='white', markeredgecolor='gray', markeredgewidth=2)
plt.ylim(-1.2, 1.2)
# ### 3. plt.scatter를 활용한 산점도
# In[32]:
plt.scatter(x, y, marker='o')
# - `plt.scatter()`의 경우 각 점의 속성(크기, 표면 색상, 테두리 색상 등)을 개별적으로 제어하거나 데이터에 매핑할 수 있는 산점도를 만드는데 사용할 수 있다.
# In[33]:
rng = np.random.RandomState(0)
x = rng.randn(100)
y = rng.randn(100)
colors = rng.rand(100)
sizes = 1000 * rng.rand(100)
plt.scatter(x, y, c=colors, s=sizes, alpha=0.3, cmap='viridis')
# 색상 척도 표시 - 다차원 데이터를 표시하기 위해 점의 색상과 크기를 사용해 정보를 전달 할 수 있다.
plt.colorbar()
# In[34]:
"""Scikit-Learn에서 제공하는 붓꽃 데이터를 사용해보자.
이 데이터에서 각 표본은 세 가지 유형의 꽃 중 하나로 그 꽃잎과
꽃받침의 크기를 세밀하게 측정한 값을 가지고 있다."""
from sklearn.datasets import load_iris
iris = load_iris()
features = iris.data.T
plt.scatter(features[0], features[1], alpha=0.2,
s=100*features[3], c=iris.target, cmap='viridis')
plt.xlabel(iris.feature_names[0])
plt.xlabel(iris.feature_names[1])
# ### 4. plot과 scatter의 차이: 효율성 측면에서 유의할 점
# - 데이터세트가 수천 개가 넘어가는 경우에는 `plt.plot`이 `plt.scatter`보다 확실히 더 효율적이다.
# - `plt.scatter`는 각 점에 대한 다양한 크기와 색상을 나타내는 능력이 있어서 렌더러가 각 점을 개별적으로 구성하는 추가 작업을 해야 하기 때문이다.
# - `plt.plot`에서는 점이 기본적으로 항상 서로 복제되므로 점의 모양을 결정하는 작업이 전체 데이터에 대해 한 번만 수행된다.
# ## 오차 시각화하기
# ### 1. 기본 오차 막대 (`errorbar`)
# In[35]:
plt.style.use('seaborn-whitegrid')
x = np.linspace(0, 10, 50)
dy = 0.8
# 오차를 일부러 준 상황
y = np.sin(x) + dy *np.random.randn(50)
# 오차구간을 0.8을 준다.
# 선과 점의 모양을 제어하는 포맷 코드
plt.errorbar(x, y, yerr=dy, fmt='.k')
# In[36]:
# errorbar의 색깔 및 면적을 조절한다.
plt.errorbar(x, y, yerr=dy, fmt='o', color='black', ecolor='lightgray', elinewidth=3, capsize=0)
# ## 밀도 플롯과 등고선 플롯
# In[37]:
plt.style.use('seaborn-white')
# ### 1. 3차원 함수 시각화하기
# In[38]:
# 3차원 공간에 정의되는 함수를 정의한다.
def f(x, y):
return np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)
# In[39]:
"""plt.contour는 x값의 격자, y값의 격자, z값의 격자라는 세 개의 인수를 취한다."""
x = np.linspace(0, 5, 50)
y = np.linspace(0, 5, 40)
# 1차 배열로부터 2차원 그리드를 만든다.
X, Y = np.meshgrid(x, y)
Z = f(X, Y)
display(X)
display(Y)
# In[40]:
# 선으로만 구성된 표준 등고선 플롯을 그린다.
# 단색이 사용되면 음수 값은 점선으로 양수 값은 실선으로 표시된다.
plt.contour(X, Y, Z, colors='black')
# In[41]:
# 색상표를 지정해 선에 색을 입힌다.
# RdGy : RedGray의 약어
plt.contour(X, Y, Z, 20, cmap='RdGy')
# In[42]:
"""색으로 채워진 등고선 플롯으로 바꾸기"""
plt.contourf(X, Y, Z, 20, cmap='RdGy')
# In[43]:
# 색상 단계가 연속적이 아니라 불연속적으로 보이는 것을 해결하기.
# imshow 메서드는 x와 y그리드를 받지 않으므로 플롯에 이미지의 extent[xmin, xmax, ymin, ymax]
# imshow 메서드는 입력 데이터를 매칭하기 위해 자동으로 축의 가로세로 비율을 조정한다.
# axis(aspect=)를 이용해 x와 y의 단위를 일치시킬 수 있다.
plt.imshow(Z, extent=[0, 5, 0, 5], origin='lower', cmap='RdGy')
plt.colorbar()
plt.axis(aspect='image')
# In[44]:
"""등고선 플롯과 이미지 플롯을 결합하는 경우"""
contours = plt.contour(X, Y, Z, 3, colors='black')
plt.clabel(contours, inline=True, fontsize=8)
plt.imshow(Z, extent=[0, 5, 0, 5], origin='lower', cmap='RdGy', alpha=0.5)
plt.colorbar()
# ## Plot config 변경하기
# In[45]:
import matplotlib as mpl
# In[46]:
# Default settings
mpl.rcParams.update(mpl.rcParamsDefault)
# In[47]:
# 간단하게 지수분포를 그려보자.
x = np.arange(0, 1, 0.01)
y = np.exp(x)
# In[48]:
plt.plot(x, y)
plt.xlabel('X')
plt.ylabel('Y')
# > Size 조절 : `plt.rcParams`사용
# In[49]:
# plt의 rcParams를 사용한다.
plt.rcParams["figure.figsize"] = (20,3)
# In[50]:
plt.plot(x, y)
plt.xlabel('X')
plt.ylabel('Y')
# > Font 조절 (https://matplotlib.org/users/text_props.html?highlight=configuring%20font%20family)
# - `matplotlib.rc` 사용
# In[51]:
mpl.rcParams.update(mpl.rcParamsDefault)
# matplotlib.rc를 이용하여, dictinary를 주입
font = {'family' : 'fantasy',
'weight' : 'bold',
'size' : 22}
mpl.rc('font', **font)
plt.plot(x, y)
plt.xlabel('X')
plt.ylabel('Y')
# In[53]:
mpl.rcParams.update(mpl.rcParamsDefault)
MEDIUM_SIZE = 20
BIGGER_SIZE = 30
mpl.rc('xtick', labelsize=MEDIUM_SIZE)
mpl.rc('ytick', labelsize=BIGGER_SIZE)
plt.plot(x, y)
plt.xlabel('X')
plt.ylabel('Y')