Skip to the content.

시각화 : matplotlib

Visualization : matplotlib


박 진 수 교수
Intelligent Data Semantics Lab
Seoul National University


[partial credit: 김도훈]

Table of Contents

matplotlib

matplotlib란?

matplotlib 설치 및 불러오기

!python -m pip install --upgrade matplotlib numpy
# 또는 
# !pip install --upgrade matplotlib numpy
# 버전 확인하기
import matplotlib, numpy
print('Matplotlib version...', matplotlib.__version__)
print('NumPy version........', numpy.__version__)
# 주로 아래 방식으로 matplot.pyplot을 plt이란 별칭으로 불러오지만 여기서는 별칭을 사용하지 않는디.
# from matplotlib import pyplot as plt 
from matplotlib import pyplot 

기본 도표 작성하기

선 그래프는 연속적인 직선이나 곡선으로 데이터 사이의 관계를 나타내는 도표다.

선 그래프를 그리기 위해서는 matplotlib.pyplot의 plot(x, y)를 사용한다.

matplotlib.pyplot.plot

pyplot.plot([1, 2, 3], [110, 130, 120])
pyplot.show()

png

x = numpy.arange(1, 10)
y = x * 3

pyplot.plot(x, y)
pyplot.show()

png

선 색상 변경

기본 색상은 파란색이지만 다른 색상으로 변경할 수 있다.

x = numpy.arange(1, 10)
y = x * 3

pyplot.plot(x, y, 'r')
pyplot.show()

png

선 모양 변경

기본 선은 직선이지만 마커를 변경해서 선 모양을 바꿀 수 있다. 이때 색상도 함께 바꿀 수 있다.

x = numpy.arange(1, 10)
y = x * 3

# 'o': circle marker, 'g': green color
pyplot.plot(x, y, 'og')
pyplot.show()

png

x = numpy.arange(1, 10)
y = x * 3

# 'P': filled plus marker
pyplot.plot(x, y, 'P')
pyplot.show()

png

x = numpy.arange(1, 10)
y = x * 3

# 'o': circle marker, ':': dotted line style, 'r': red color
pyplot.plot(x, y, 'o:r')
pyplot.show()

png

제목과 라벨

도표의 제목이나 X, Y 축 라벨을 붙이려면 title(‘제목’), xlabel(‘x축이름’), ylabel(‘y축이름’)을 사용한다.

x = ['Week 1', 'Week 2', 'Week 3', 'Week 4']
y = [70, 77, 83, 81]

pyplot.title('Report')
pyplot.ylabel('Customers')
pyplot.xlabel('Week')

pyplot.plot(x, y)
pyplot.show()

png

도표 구간의 확대 및 축소

도표는 입력한 x, y 값의 최소부터 최대의 구간으로 지정된다. 이 구간을 키우거나 줄이려면 x, y의 구간을 따로 지정하면 된다.

다음 예는 x 축을 1~5, y 축을 3~10으로 확대한 것이다.

# 기본 구간을 보여준다.
x = numpy.arange(1, 10)
y = x * 3

pyplot.plot(x, y)
pyplot.show()

png

# 확대한 구간으로 다시 정의하여 보여준다.
x = numpy.arange(1, 10)
y = x * 3

pyplot.title('Zoomed In')
pyplot.ylabel('y axis')
pyplot.xlabel('x axis')

pyplot.xlim(1, 5)
pyplot.ylim(3, 10)

pyplot.plot(x,y)
pyplot.show()

png

다음 예는 x 축을 1~20, y 축을 3~50으로 축소한 것이다.

# 축소한 구간으로 다시 정의하여 보여준다.
x = numpy.arange(1, 10)
y = x * 3

pyplot.title('Zoomed Out')
pyplot.ylabel('y axis')
pyplot.xlabel('x axis')

pyplot.xlim(1, 20)
pyplot.ylim(3, 50)

pyplot.plot(x,y)
pyplot.show()

png

범례(legend)

도표에서 여러 개의 선을 동시에 그릴 때, 각 선을 구분하기 위해 선마다 라벨을 달고 각 라벨의 이름을 보여줄 수 있는데 이를 범례(legend)라고 한다.

matplotlib.pyplot.legend

도표에 여러 개의 선을 추가하려면 plot 메소드를 show 메소드 전에 여러 번 호출한다. 다음 예는 두 개의 선을 그린 후, 좌측 상단에 범례를 표현한 것이다.

# 범례(legend)를 설정한다.
x = numpy.arange(1, 10, 0.1)
y1 = x * 0.3
y2 = numpy.sin(x)

pyplot.title('Legend Sample')
pyplot.ylabel('y axis')
pyplot.xlabel('x axis')

pyplot.plot(x, y1, 'g', label='linear')
pyplot.plot(x, y2, 'r', label='non-linear')

pyplot.legend(loc='upper left')
pyplot.show()

png

앞의 예에서는 plot 메소드의 매개변수 label 에 선의 이름을 지정했는데, legend() 메소드에서도 선의 이름을 지정할 수 있다. 각 선에 대한 범례를 추가하려면 다음과 같이 각 선에 대한 범례를 순서대로 지정하여 legend([‘선1범례’, 선2범례’, …]) 메소드를 호출하면 된다.

x = numpy.arange(1, 10, 0.1)
y1 = x * 0.3
y2 = numpy.sin(x)

pyplot.title('Legend Sample')
pyplot.ylabel('y axis')
pyplot.xlabel('x axis')

pyplot.plot(x, y1, 'g')
pyplot.plot(x, y2, 'r')

pyplot.legend(['linear','non-linear'], loc='upper left')
pyplot.show()

png

주석(annotation)

도표의 특정 좌표를 가리키는 화살표를 그린 후, 그 화살표에 문자열을 출력하는 기능이다.

matplotlib.pyplot.annotate

다음 예는 초록색 화살표와 문자열로 주석을 작성한 것이다.

# 초록색 화살표와 주석을 설정한다.
x = numpy.arange(1, 10)
y = x * 3

pyplot.title('Annotation Sample')
pyplot.ylabel('y axis')
pyplot.xlabel('x axis')

pyplot.annotate('start', 
                xy=(1.1, 3), xytext=(2, 5), 
                arrowprops={'color': 'green'})

pyplot.plot(x, y, 'r')
pyplot.show()

png

Lab: 상점 고객수 데이터로 선 그래프 그리기

다음 데이터는 2010년부터 2020년까지의 상점 고객수 데이터다. 이 데이터를 이용하여 선 그래프를 그리시오.

year = 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020
no_customers = 2031, 2623, 2750, 2908, 3103, 3288, 3453, 3667, 4021, 4300, 4732

문제



# YOUR CODE HERE

서브플롯

한 번에 여러 개의 도표를 그릴 경우 서브플롯을 사용한다.

matplotlib.pyplot.subplot

다음 예는 1, 2 즉, 1줄 2칸의 평면에 좌우에 두 개의 도표를 그린 것이다.

x = numpy.arange(1, 10)
y1 = x * 3
y2 = x * 4

pyplot.subplot(1, 2, 1, title='Subplot 1')
pyplot.plot(x, y1, 'or')

pyplot.subplot(122) # subplot(1, 2, 2)와 같다.
pyplot.title('Subplot 2')
pyplot.plot(x, y2, 'g')
pyplot.show()

png

subplot 안의 숫자를 변경하여 평면의 줄과 칸을 변경할 수 있다.

다음 예는 2, 1 즉, 2줄 1칸의 평면을 만들어 위와 아래에 두 개의 도표를 그린 것이다.

# 2줄 1칸의 서브플롯을 설정한다.
x = numpy.arange(1, 10)
y1 = x * 3
y2 = x * 4

pyplot.subplot(2, 1, 1)
pyplot.title('Subplot 1')
pyplot.plot(x, y1, 'or')

pyplot.subplot(2, 1, 2)
pyplot.title('Subplot 2')
pyplot.plot(x, y2, 'g')
pyplot.show()

png

그런데 2줄 1칸의 평면에서 도표를 그릴 때 첫 번째 도표의 x축과 두 번째 도표의 제목이 앞서 예처럼 겹칠 수가 있다. 겹치기를 방지하려면 subplots_adjust 메소드로 두 도표 사이의 간격을 설정하면 된다.

matplotlib.pyplot.subplots_adjust

The parameter meanings (and suggested defaults) are:

left = 0.125  # the left side of the subplots of the figure
right = 0.9   # the right side of the subplots of the figure
bottom = 0.1  # the bottom of the subplots of the figure
top = 0.9     # the top of the subplots of the figure
wspace = 0.2  # the amount of width reserved for space between subplots,
              # expressed as a fraction of the average axis width
hspace = 0.2  # the amount of height reserved for space between subplots,
              # expressed as a fraction of the average axis height
# 2줄 1칸의 서브플롯을 설정하면서 겹치기를 방지한다.
x = numpy.arange(1, 10)
y1 = x * 3
y2 = x * 4

pyplot.subplot(2, 1, 1)
pyplot.title('Subplot 1')
pyplot.plot(x, y1, 'or')

pyplot.subplot(2, 1, 2)
pyplot.title('Subplot 2')
pyplot.plot(x, y2, 'g')

pyplot.subplots_adjust(hspace=0.6)
pyplot.show()

png

간격을 자동으로 조정하려면 tight_layout 메소드를 사용하면 된다.

# 2줄 1칸의 서브플롯을 설정하면서 겹치기를 방지한다.
x = numpy.arange(1, 10)
y1 = x * 3
y2 = x * 4

pyplot.subplot(2, 1, 1)
pyplot.title('Subplot 1')
pyplot.plot(x, y1, 'or')

pyplot.subplot(2, 1, 2)
pyplot.title('Subplot 2')
pyplot.plot(x, y2, 'g')

pyplot.tight_layout()  # 서브플롯 사이의 높이 간격을 자동으로 맞춘다.
pyplot.show()

실행 결과

matplot16

다음 예는 3줄 3칸의 평면을 만들어 9개의 도표를 그리는 코드다.

# 3줄 3칸의 평면을 만들어 9개의 도표를 설정한다.
x = numpy.arange(1, 10)
y1 = x * 3
y2 = x * 4
y3 = x * 5
y4 = x * 6
y5 = x * 7
y6 = x * 8
y7 = x * 9
y8 = x * 10
y9 = x * 11

pyplot.subplot(331, title='Subplot 1')
pyplot.plot(x, y1)
pyplot.subplot(332, title='Subplot 2')
pyplot.plot(x, y2)
pyplot.subplot(333, title='Subplot 3')
pyplot.plot(x, y3)
pyplot.subplot(334, title='Subplot 4')
pyplot.plot(x, y4)
pyplot.subplot(335, title='Subplot 5')
pyplot.plot(x, y5)
pyplot.subplot(336, title='Subplot 6')
pyplot.plot(x, y6)
pyplot.subplot(337, title='Subplot 7')
pyplot.plot(x, y7)
pyplot.subplot(338, title='Subplot 8')
pyplot.plot(x, y8)
pyplot.subplot(339, title='Subplot 9')
pyplot.plot(x, y9)

pyplot.subplots_adjust(hspace=1, wspace=0.5)
pyplot.show()

png

도표 크기 조정

도표의 크기를 변경할 수 있다.

matplotlib.pyplot.figure

matplotlib.figure.Figure

앞서 그려본 9개의 도표는 전체 도표의 평면 크기가 작기 때문에 x축의 값들이 모두 보이지 않는 문제가 있었다.이 문제를 해결하기 위해 17 x 20 크기로 도표를 그리도록 크기를 설정해보자.

이렇게 하기 위해서는 figure(figsize=(17, 20)) 을 입력하면 된다.

x = numpy.arange(1, 10)
y1 = x * 3
y2 = x * 4
y3 = x * 5
y4 = x * 6
y5 = x * 7
y6 = x * 8
y7 = x * 9
y8 = x * 10
y9 = x * 11

pyplot.figure(figsize=(17, 20))  # 여기에 먼저 크기를 지정해야 한다.

pyplot.subplot(331, title='Subplot 1')
pyplot.plot(x, y1)
pyplot.subplot(332, title='Subplot 2')
pyplot.plot(x, y2)
pyplot.subplot(333, title='Subplot 3')
pyplot.plot(x, y3)
pyplot.subplot(334, title='Subplot 4')
pyplot.plot(x, y4)
pyplot.subplot(335, title='Subplot 5')
pyplot.plot(x, y5)
pyplot.subplot(336, title='Subplot 6')
pyplot.plot(x, y6)
pyplot.subplot(337, title='Subplot 7')
pyplot.plot(x, y7)
pyplot.subplot(338, title='Subplot 8')
pyplot.plot(x, y8)
pyplot.subplot(339, title='Subplot 9')
pyplot.plot(x, y9)

pyplot.subplots_adjust(wspace=0.2)
pyplot.show()

png

서브플롯과 전체 도표의 제목 설정

pyplot.suptitle 메소드를 사용하면 된다. pyplot.title 메소드는 axes의 제목을 설정할 때 사용하는 메소드다. 즉, 전체 도표 안에 있는 각각의 서브플롯에 제목을 설정한다고 생각하면 된다. 따라서 하나의 도표만 그린다면 pyplot.title 메소드를 사용하는게 일반적이다. 하지만 여러 개의 도표를 그리고 이 전체 도표를 대표하는 제목을 작성할 필요가 있을 때 pyplot.suptitle 메소드를 사용한다.

suptitle을 작성하려면 suptitle() 메소드를 suptitle(t, **kwargs) 형식으로 사용하면 된다.

matplotlib.pyplot.suptitle

# 1줄 2칸의 서브플롯을 설정한다.
x = numpy.arange(1, 10)
y1 = x * 3
y2 = x * 4

pyplot.subplot(1, 2, 1, title='Subplot 1')
pyplot.plot(x, y1, 'or')

pyplot.subplot(122) # subplot(1, 2, 2)와 같다.
pyplot.plot(x, y2, 'g')
pyplot.title('Subplot 2');

# 전체 도표에 대한 제목을 설정하고, 
# 각 서브플롯 제목과의 거리를 두기 위해 y=1.01로 설정한다.
pyplot.suptitle('Two Subplots', y=1.01)
pyplot.show()

png

다양한 도표 그리기

matplotlib는 앞서 그린 선 그래프 이외에 여러 다양한 도표를 그릴 수 있다. 이를 위해 각 도표마다 다른 메소드를 호출한다. 예를 들어, 막대 그래프를 그리기 위해서는 bar 메소드를, 원 그래프를 그리기 위해서는 pie 메소드를, 히스토그램을 그리기 위해선 hist 메소드를 호출한다.

막대 그래프

막대 그래프 데이터 값에 비례하여 높이와 길이를 지닌 직사각형 막대로 범주형 데이터를 표현하는 도표다.

막대 그래프를 작성하려면 bar 메소드를 주로 bar(x, height, width=0.8, bottom=None , align=’center’) 형식으로 사용하면 된다.

matplotlib.pyplot.bar

다음 예는 너비 0.5의 청록색 막대로 이루어진 막대 그래프를 작성한 코드다.

y = [1, 4, 7, 10, 3, 4, 9, 4.5]
x = list('abcdefgh')

# 너비 0.5의 청록색 막대로 이루어진 막대 그래프를 설정한다.
pyplot.bar(x, y, width=0.5, color='c')
pyplot.show()

png

만약 x축의 눈금 라벨이 너무 긴 경우 xticks 메소드의 매개변수 rotation 을 사용하여 글자를 회전시킬 수 있다.

matplotlib.pyplot.xticks

Call signatures:

locs, labels = xticks()            # Get locations and labels
xticks(ticks, [labels], **kwargs)  # Set locations and labels
y = [1, 4, 7, 10, 3, 4, 9, 4.5]
x = range(101, 109)

# 너비 0.5의 청록색('c') 막대로 이루어진 막대 그래프의 
# x축의 라벨을 90도 회전해서 보이도록 설정한다.
pyplot.bar(x, y, width=0.5, color='c')
pyplot.xticks(rotation=90)
pyplot.show()

png

모든 막대 당 하나의 눈금이 기본으로 붙는 게 아니기 때문에 많은 막대를 그릴 경우에는 자연스럽게 눈금이 생략될 수 있다. 이런 때는 xticks 메소드를 사용하여 눈금의 위치와 이름을 설정하면 된다.

다음 예는 국적별 전체 외국인 관광객 수를 막대 그래프로 작성한 코드다.

# y축의 값을 설정한다.
number_of_tourists_total = [
    258522, 102241, 58600, 49998, 
    49282, 43190, 41739, 23760
]

# 0부터 7번까지의 막대 밑에 눈금으로 이름을 설정한다.
# 즉, ticks를 0, 1, 2, 3, 4, 5, 6, 7로
# labels를 'Japan', 'Taiwan', 'Hong Kong', 'Thailand', 
# 'Malaysia ', 'Vietnam', 'Philippines ', 'Indonesia'로 설정한다.
pyplot.xticks(ticks=tuple(range(8)),
              labels=('Japan', 'Taiwan', 'Hong Kong', 'Thailand', 'Malaysia', 
                      'Vietnam', 'Philippines', 'Indonesia'),
              rotation=30)

pyplot.bar(range(len(number_of_tourists_total)), 
           number_of_tourists_total)
pyplot.show()

png

한 화면에 여러 개의 도표를 그릴 때 사용하는 서브플롯에서는 set_xticksset_xtickslabels 메소드를 사용한다.

만들고자 하는 서브플롯에 각각 set_xticks 메소드로 눈금의 위치를 지정하고 set_xtickslabels 메소드로 눈금의 이름을 설정하면 된다.

다음 예는 국적별 남자 외국인 관광객 수와 여자 외국인 관광객 수를 막대 그래프로 작성한 코드다. 두 개의 서브플롯을 만들어 각각 set_xticksset_xtickslabels()를 이용하여 눈금과 라벨을 설정하고 tight_layout 메소드로 그래프가 겹치지 않도록 설정한다.

matplotlib.pyplot.tight_layout

# 도표 크기를 설정한다.
pyplot.figure(figsize=(10, 6))

# x축의 눈금을 설정한다.
x_ticks = tuple(range(8))
# x축의 라벨을 설정한다.
x_labels = ('Japan', 'Taiwan', 'Hong Kong', 'Thailand', 
            'Malaysia', 'Vietnam', 'Philippines', 'Indonesia')

# --- 1줄 2칸의 서브플롯을 설정한다.
# 좌측 서브플롯을 설정한다.
sub1 = pyplot.subplot(1, 2, 1)
sub1.set_xticks(x_ticks)
sub1.set_xticklabels(x_labels, rotation=30)
number_of_tourists_male = (  # y축의 값을 설정한다.
    88718, 30560, 17997, 14185, 18196, 16549, 12686, 8548)
pyplot.bar(range(len(number_of_tourists_male)), 
           number_of_tourists_male)

# 우측 서브플롯을 설정한다.
sub2 = pyplot.subplot(1, 2, 2)
sub2.set_xticks(x_ticks)
sub2.set_xticklabels(x_labels, rotation=30)
number_of_tourists_female = [  # y축의 값을 설정한다.
    167326, 70670, 39860, 30178, 28885, 21552, 15764, 11035]
pyplot.bar(range(len(number_of_tourists_female)), 
           number_of_tourists_female,
           color='g')

pyplot.tight_layout()
pyplot.show()

png

barh를 사용하면 수평 막대 그래프를 그릴 수 있다.

그리고 barbarh의 매개변수인 xerryerr로 에러 바(error bar)를 추가할 수 있고, alpha로 투명도를 지정할 수 있다.(0이면 완전 투명, 1이면 완전 불투명)

products = ['A', 'B', 'C', 'D']

numpy.random.seed(5)
grades = 3 + 10 * numpy.random.rand(len(products))
error = numpy.random.rand(len(products))

pyplot.title('Horizon Bar')
pyplot.barh(products, grades, xerr=error, alpha=0.4)

pyplot.show()

png

Lab: 상점 고객수 데이터로 막대 그래프 그리기

다음 데이터는 2010년부터 2020년까지의 상점 고객수 데이터다. 이 데이터를 이용하여 막대 그래프를 그리시오.

year = 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020
no_customers = 2031, 2623, 2750, 2908, 3103, 3288, 3453, 3667, 4021, 4300, 4732

문제



# YOUR CODE HERE

막대 그래프 나란히 그리기

막대 두 개를 나란히 그릴 때는 x축 눈금(xticks) 설정에 유의해야 한다.

자세한 내용은 아래 링크에서 확인할 수 있다.

다음 예는 학생들의 퀴즈 점수 평균을 성별과 반으로 나누어 막대 그래프로 작성한 코드다. 여기서는 두 x 값들의 중간값으로 설정한다.

# --- 학생들의 퀴즈 점수 평균을 성별과 반으로 나누어 막대 그래프로 작성한다.

# 각 막대 위에 y 값을 입력하기 위한 함수
def autolabel(rects):
    for rect in rects:
        height = rect.get_height()
        pyplot.annotate(f'{height}',
                    xy=(rect.get_x() + rect.get_width() / 2, height),
                    xytext=(0, 3),  # 3 points vertical offset
                    textcoords='offset points',
                    ha='center', va='bottom')

men_means = 20, 35, 30, 35, 27      # 남학생 퀴즈 평균 점수
women_means = 28, 32, 34, 20, 25    # 여학생 퀴즈 평균 점수

x_labels = [                        # x축 라벨
    'Classroom 1', 'Classroom 2', 'Classroom 3', 
    'Classroom4', 'Classroom 5'
]
x = numpy.arange(len(x_labels))     # x축 눈금
width = 0.35                        # 막대의 너비

# 도표의 크기를 설정한다.
pyplot.figure(figsize=(8,8))

pyplot.title('Quiz Score by Student Groups and Gender')
pyplot.ylabel('Quiz Score')
pyplot.xticks(x, x_labels)

# 두 개의 막대를 나란히 보여주는 막대 그래프를 설정한다.
bar_men = pyplot.bar(x - width / 2, men_means, width, label='Men')
bar_women = pyplot.bar(x + width / 2, women_means, width, label='Women')

pyplot.legend()
autolabel(bar_men)                  # 남학생 퀴즈 평균 점수를 막대 위에 표시한다.
autolabel(bar_women)                # 여학생 퀴즈 평균 점수를 막대 위에 표시한다.
pyplot.show()

png

참고

두 개 이상의 데이터를 시각화 할 때 color를 지정하지 않으면 matplotlib에서는 파랑, 주황, 초록, 빨강, 보라 .. 순으로 색이 자동으로 설정된다.

누적 막대 그래프

누적(stacked) 막대 그래프는 막대를 사용하여 데이터 범주 간 비교를 표시하지만 전체를 부분으로 나눠 비교할 수 있는 도표다. 도표의 각 막대는 전체를 나타내고 막대의 세그먼트는 전체의 일부분이나 범주를 나타낸다.

누적 막대 그래프는 총계를 표시하고 각 범주 값이 어떻게 총계의 부분으로 나눠지는지 한 눈에 확인할 수 있어 편리하다.

bar 메소드로 여러 개의 바를 생성하여 누적 막대 그래프를 그릴 수 있다. 예를 들어, 두 개의 범주가 있을 때 bar 메소드로 두 개의 막대를 생성하면 되는데 아래에 오는 값으로 먼저 막대를 생성한 후, 그 위에 오는 값으로 막대를 생성할 때 매개변수 bottom 의 전달인자로 아래에 오는 막대의 값을 지정하면 된다.

막대 그래프 위에 오차 막대(error bar)를 표시해주고 싶으면 매개변수 yerr 에 값을 전달인자로 지정하면 된다. 오차 막대의 너비는 매개변수 capsize 로 설정하면 된다. 마지막으로 legend 메소드를 사용하여 각 값이 의미하는 바를 범례로 표시한다.

다음 예는 학생들의 퀴즈 점수 평균과 표준편차를 성별과 반으로 나누어 누적 막대 그래프로 작성한 코드다.

# x축의 다섯 개 막대는 학생들이 속한 반을 의미하며 여기서 색상이 다른 누적 막대로 성별을 표현한다. 
# 먼저 먼저 막대 lower_bar을 생성하여 남학생들의 반별 평균 퀴즈 점수를 할당한다. 
# 마찬가지로 upper_bar에는 여학생들의 반별 평균 퀴즈 점수를 할당하되, 
# 매개변수인 bottom에 lower_bar의 y 값인 men_means를 지정하여 
# lower_bar 위에 upper_bar가 그려지는 누적 바 차트를 작성한다.

men_means = 20, 35, 30, 35, 27          # 남학생 퀴즈 평균 점수
men_std = 5, 3, 5, 2, 4                 # 남학생 퀴즈 표준편차
    
women_means = 28, 32, 34, 20, 25        # 여학생 퀴즈 평균 점수
women_std = 3, 2, 6, 3, 4               # 여학생 퀴즈 표준편차

x_labels = [                            # x축 라벨
    'Classroom 1', 'Classroom 2', 'Classroom 3', 
    'Classroom4', 'Classroom 5'
]
x = numpy.arange(len(x_labels))         # x축 눈금
width = 0.35                            # 막대의 너비

# 도표의 크기를 설정한다.
pyplot.figure(figsize=(8,8))

pyplot.title('Quiz Score by Student Groups and Gender')
pyplot.ylabel('Quiz Score')
pyplot.yticks(numpy.arange(0, 71, 5))   # y축에 0부터 70까지 눈금을 5의 단위로 작성한다.
pyplot.xticks(x, x_labels)

# 두 개의 막대를 누적 막대 그래프로 설정한다.
lower_bar = pyplot.bar(x, men_means, width, yerr=men_std, capsize=3)
upper_bar = pyplot.bar(x, women_means, width, 
                       bottom=men_means, yerr=women_std, capsize=5)

pyplot.legend((lower_bar, upper_bar), ('Men', 'Women'))
pyplot.show()

png

100% 누적 막대 그래프 그리기

100% 누적 막대 그래프를 그릴 때는 누적해서 작성한 각 바들의 합이 모두 같아야 한다.

여러 개의 막대를 누적하여 그릴 때는 위에 쌓는 막대의 매개변수 bottom 에 아래에 놓인 모든 막대들의 누적한 값을 전달인자로 지정한다. 예를 들어, 두 번째 막대 B를 첫 번째 막대 A 위에 쌓으려면 B 막대의 bottom 에 A의 값을, 세 번째 막대 C를 두 번째 막대 B 위에 쌓으려면 C 막대의 bottom 에 A와 B를 합한 값을 전달인자로 입력한다. 네 번째 막대 D의 경우에는 첫 번째(A), 두 번째(B), 세 번째(C) 막대 값의 합을 D의 bottom 에 전달하면 된다. 즉, 네 개의 막대를 누적한 누적 막대 그래프를 작성할 때 네 번째 막대의 bottom 전달인자로 첫 번째, 두 번째, 세 번째 막대 값의 합이 들어간다.

다음 예는 연령대 별 선호하는 교통수단을 100% 누적 막대 그래프로 작성한 코드다. 참고로 100% 누적 막대 그래프를 그릴 때는 누적해서 작성한 각 막대(여기서는 각 연령대)들의 합이 모두 같아야 한다. 각 막대의 합이 다르면 그래프가 그려는 지지만 막대의 높이가 일정하지 않고 달라진다.

# --- 연령대 별 선호하는 교통수단을 100% 누적 막대 그래프로 설정한다.

# y축 값으로 각 범주의 합이 28이다.
car    =  2,  3, 15,  5
bus    =  6, 10,  4,  7
subway = 12, 10,  9, 14
taxi   =  8,  5,  0,  2

sum_of_car_bus = numpy.add(car, bus)
sum_of_car_bus_subway = numpy.add(sum_of_car_bus, subway)

# x축 라벨과 눈금 
x_labels = 'Age 10-20', 'Age 20-30', 'Age 30-40', 'Age 40-50'
x = range(len(x_labels))

# 도표의 크기를 설정한다.
pyplot.figure(figsize=(10, 10))

pyplot.title('Favorite Transportation by Age Groups')
pyplot.ylabel('Counts')
pyplot.xlabel('Groups')
pyplot.xticks(x, x_labels)

bar1 = pyplot.bar(x, car)
bar2 = pyplot.bar(x, bus, bottom=car)
bar3 = pyplot.bar(x, subway, bottom=sum_of_car_bus)
bar4 = pyplot.bar(x, taxi, bottom=sum_of_car_bus_subway)

pyplot.legend((bar1, bar2, bar3, bar4), 
              ('Car', 'Bus', 'Subway', 'Taxi'), 
              bbox_to_anchor=(1.01, 0.94), 
              loc='best')  # loc='center left'
pyplot.show()

png

원 그래프

원 그래프는 전체에 대한 각 부분의 비율을 부채꼴 모양으로 나타낸 그래프이며, 각 부분의 비율을 한 눈에 볼 수 있다는 장점이 있다.

원 그래프를 작성하려면 pie 메소드를 주로 pie(x, explode, labels=None, autopct=None, shadow=False, startangle=None) 형식으로 사용하면 된다.

참고로 부채꼴이 그려지는 순서는 시계 역방향이다. 그리고 axis(‘equal’) 로 설정하면 Equal aspect ratio를 사용하여 그려지는 도표의 x축과 y축의 길이 비율이 같도록 설정할 수 있다. 즉, 원 그래프의 데이터나 설정 등에 따라 그려지는 파이가 원이 아닌 타원의 형태로 그려질 수 있는데 x축과 y축의 길이 비율이 같게 하여 원형으로 그려지도록 한다.

matplotlib.pyplot.pie

다음 예는 학생들의 통학 수단을 원 그래프로 작성한 코드다.

# --- 학생들의 통학 수단을 원 그래프로 설정한다.

# 부채꼴의 값과 라벨을 설정한다.
labels = 'Car', 'Taxi', 'Bus', 'Train'
wedges = 20, 28, 45, 7

# 두 번째 부채꼴인 Taxi만 떼어내어 강조한다. explode의 전달인자는 각 부채꼴의 강조 정도를 뜻한다. 
# 0일 경우 원 그래프의 중심점에 붙어 있으며 값이 커질수록 중심에서 떨어져 강조가 된다.
# 여기서는 (0, 0.1, 0, 0)으로 설정했기 때문에 첫 번째, 세 번째, 네 번째 웨지는 0 이므로 중심에 붙어 있고
# 두번째 부채꼴만 0.1 만큼 중심에서 떨어진다.
explode = (0, 0.1, 0, 0)  

# autopct='%0.1f%%'에서 가장 왼쪽의 %는 데이터를 백분율의 형태로 표현하도록 변환해주며 
# 0.1f는 소수점 첫번째 자리까지 표현하도록 설정한다. 오른쪽의 %%는 각 부채꼴에서 표현하는 값 
# 뒤에 %를 붙여준다. '%'를 표현하기 위해서는 %%로 작성해야 한다.
pyplot.pie(wedges, explode=explode, labels=labels, 
           autopct='%0.1f%%', shadow=True, startangle=90)   

# 도표의 x축과 y축의 길이 비율이 같도록 설정하여 원 그래프가 원형으로 그려지도록 한다.
pyplot.axis('equal')  
pyplot.show()

png

히스토그램

히스토그램은 도수분포표를 시각적으로 표현한 막대 그래프다. 즉, 특정 구간에 속하는 자료의 개수를 나타내는 빈도표(frequency table)인 도수분포표를 시각화한 도형으로 비교할 양이나 수치에 대한 구간별 빈도수를 막대 모양의 도형으로 나타낸 그래프다.

히스토그램을 작성하려면 hist 메소드를 주로 hist(x, bins=None, density=None, weights=None, cumulative=False, histtype=’bar’, orientation=’vertical’, rwidth=None, color=None, **kwargs) 형식으로 사용하면 된다.

matplotlib.pyplot.hist

다음 예는 학생들의 키 데이터를 막대 히스토그램으로 작성한 코드다.

# 학생들의 키 데이터를 막대 히스토그램으로 작성한다.
height = [
    140, 146, 154, 156, 156, 158, 160, 161, 162, 163, 164, 165, 
    170, 171, 172, 172, 173, 174, 177, 179, 180, 181, 185, 188, 190
]

# 구간을 5로 설정하여 위의 데이터들을 5개의 막대로 표현한다. 
# color='r'로 설정하야 막대의 색깔을 red로 표현한다.
pyplot.hist(height, bins=5, color='r')
pyplot.show()

png

앞과 같은 데이터로 다른 형태의 막대 히스토그램을 작성해보자.

# 학생들의 키 데이터를 다른 형태의 막대 히스토그램을 작성한다.
height = [
    140, 146, 154, 156, 156, 158, 160, 161, 162, 163, 164, 165, 
    170, 171, 172, 172, 173, 174, 177, 179, 180, 181, 185, 188, 190
]

# 앞의 코드는 기본값을 사용했기 때문에 density=True, cumulative=True로 설정하였다. 
# y축이 빈도에서 확률 밀도로 변경하고 그래프 막대가 x축의 방향으로 진행함에 따라 구간 값을 축적해서 그리도록 한다.
# 그리고 생성하는 5개의 막대간 간격이 있도록 rwidth = 0.9로 설정한다.
pyplot.hist(height, bins=5, density=True, cumulative=True, rwidth=0.95)
pyplot.show()

png

다음 예는 중학교 1, 2, 3학년 학생 몸무게 데이터를 히스토그램으로 그리되 histtype, orientation, alpha을 다르게 설정하여 다양한 모양의 히스토그램으로 작성한 코드다.

# 2차원 리스트 내의 값들을 히스토그램으로 그리되 histtype, orientation, alpha를 다르게 설정하여 
# 서로 다른 모양을 가지는 5개의 히스토그램을 작성한다.

weights = [
    [41, 43, 46, 50, 48, 40, 46, 46, 50, 52, 54, 58, 46, 48, 51, 52, 56, 60, 42, 61, 52, 45, 44, 45],
    [46, 47, 49, 50, 53, 55, 59, 60, 62, 60, 58, 57, 59, 70, 68, 72, 73, 70, 66, 63, 61, 62, 53, 74],
    [58, 59, 56, 60, 64, 66, 63, 68, 69, 70, 74, 77, 74, 79, 75, 76, 77, 71, 75, 75, 80, 82, 76, 85],
]
    
# 구간을 10으로 설정하여 주어진 데이터 범위에서 같은 너비의 막대를 10개 그리도록 한다. 
# 예를 들어 학년별 몸무게 데이터에서 2차원 리스트 내에 세 개의 1차원 리스트가 있으므로 
# 각 리스트에 있는 데이터의 범위에서 막대를 10개 그리도록 한다.
# --- [부연 설명]
# bins가 정수 n을 전달받으면 주어진 데이터 범위에서 같은 너비의 막대를 n개 만큼 그린다. 
# 여기서는 x축이 전체 2차원 리스트의 데이터 범위인 41~85가 된다.
# 그리고 bins=10 이므로 41~85 사이에 각 1차원 리스트 별(학년별)로 막대를 10개씩 만들어야 하지만 
# 2차원 리스트의 범위에 비해 1차원 리스트의 데이터 범위가 작기 때문에 막대 10개가 모두 그려지지 않는다.
# 1학년 학생의 데이터는  41~60, 2학년 학생의 데이터는 46~74, 3학년 학생의 데이터는 58~85 구간에 그려진다.
bins = 10  

# 전체 도표의 크기를 figsize=(8, 12)로 5개의 subplot을 생성하여, 5개의 히스토그램을 한번에 출력한다.
fig, (ax1, ax2, ax3, ax4, ax5) = pyplot.subplots(nrows=5, figsize=(8, 15))

# 첫번째 히스토그램은 histtype='bar'로 막대 히스토그램을 작성한다. 
# 전체 데이터가 40~85 사이의 값을 가지므로 set_xlim([40,85])으로 설정하여 x축의 구간을 40~85로 한다.
# 3개의 1차원 데이터로 생성하는 막대 별 색상을 green, red, blue로 설정한다.
# --- [그림에 대한 부연 설명] 
# 막대가 그려지는 눈금의 위치가 조금씩 다른데 이는 전체 2차원 리스트 데이터의 구간이 40~85이고 
# 각 1차원 리스트 데이터의 구간은 상이하기 때문이다. 첫 번째 리스트의 데이터부터 막대가 그려진다.
# 2학년 데이터인 두 번째 리스트에서 45와 50 사이의 숫자는 46, 47, 49다. 하지만 46, 47 두 개만 
# 카운트 되어 빨간색 막대(빨간색 막대 중 첫 번째)가 그려졌다. 실질적으로는 49 또한 같이 카운트 되어 
# 세 개가 카운트 된 막대를 생성해야 한다. 하지만 이미 세 번째 초록색 막대가 50 눈금 앞에 그려졌기 때문에 
# 두 번째 리스트의 49는 x축의 50 눈금 뒤로 카운트 되어 그려진다.
ax1.set_title('bar')
ax1.set_xlim([40, 85])
ax1.hist(weights, bins, histtype='bar', color=['g', 'r', 'b'])


# 두 번째 히스토그램은 첫 번째 히스토그램과 달리 histtype='barstacked'으로 설정하여 
# 누적 막대 히스토그램을 그리도록 하고 누적이 되기에 첫 번째 1차원 리스트로 그려지는 초록색 막대가 가장 아래로 간다.
ax2.set_title('stacked bar')
ax2.set_xlim([40, 85])
ax2.hist(weights, bins, histtype='barstacked', color=['g', 'r', 'b'])

# 세 번째 히스토그램은 첫 번째 막대 히스토그램과 달리 orientation='horizontal'로 설정하여
# 막대가 가로로 그려지도록 설정한다. 가로로 그려지는 이 히스토그램은 x축의 구간을 따로 설정하지 않았다.
# 물론 전체 데이터가 40~85 사이의 값을 가지므로 set_ylim([40,85])으로 설정하여 y축의 구간을 40~85로
# 할 수 있지만 여기서는 불필요해서 하지 않는다.
ax3.set_title('horizontal bar')
# ax3.set_ylim([40, 85])
ax3.hist(weights, bins, histtype='bar', orientation='horizontal', color=['g', 'r', 'b'])

# 네 번째 히스토그램은 histtype='step'으로 설정하여 안이 비어있는 선 그래프 형태의 히스토그램으로 작성한다.
# 안이 비어있는 선이기 때문에 겹치는 부분이 막대처럼 나란히 그려지지 않는다. 
# 선이 겹치는 부분은 먼저 그려진 선만 보이게 된다. 
ax4.set_title('step')
ax4.set_xlim([40, 85])
ax4.hist(weights, bins, histtype='step', color=['g', 'r', 'b'])

# 다섯 번째 히스토그램은 histtype='stepfilled'으로 설정하여 안이 차있는 선 그래프 형태의 히스토그램으로 작성한다.
# 전체 선의 색상을 red로 통일하기 위해 facecolor='r'로 설정하였고 투명도는 alpha=0.3으로 설정하였다.
# 투명도가 0.3인 빨강색으로 그리기 때문에 겹치는 부분은 진하게 표현이 되는 것을 확인할 수 있다.
ax5.set_title('stepfilled')
ax5.set_xlim([40, 85])
ax5.hist(weights, bins, histtype='stepfilled', facecolor='r', alpha=0.3)

fig.tight_layout()
pyplot.show()

png

박스 그래프

박스 그래프는 데이터의 분포를 시각적으로 표현한 박스 모양의 그래프다. 데이터의 범위, 중앙값과 이상치를 빠르게 확인할 수 있는 장점이 있다.

박스 그래프를 작성하려면 boxplot 메소드를 주로 boxplot(x, notch=None, sym=None, vert=None, labels=None) 형식으로 사용하면 된다.

matplotlib.pyplot.boxplot

matplotlib.pyplot.grid

다음 예는 남자들의 몸무게를 박스 그래프로 작성한 코드다.

# 남자들의 몸무게를 박스 그래프로 작성한다.
male_weights = [
    53, 59, 66, 67, 68, 70, 73, 74, 75, 78, 
    81, 82, 85, 90, 90, 91, 120, 130
]

# 격자를 생성한다.
pyplot.grid()

# 위 데이터 값으로 박스 그래프를 작성한다. 
pyplot.boxplot(male_weights)
pyplot.show()

png

이번에는 이상치의 기본값을 다른 문자로 바꿔 표시하고 잘록한 박스 그래프를 만들어 본다.

# 이상치의 기본값을 .로 표시하는 잘록한 박스 그래프를 설정한다.
male_weights = [
    53, 59, 66, 67, 68, 70, 73, 74, 75, 78, 
    81, 82, 85, 90, 90, 91, 120, 130
]

pyplot.title('Outliers = "."')

# 격자를 생성한다.
pyplot.grid()

# 위의 코드에서 notch=True로 설정하여 잘록한 박스 그래프(notched box plot)를 작성하고
# sym='.'로 설정하여 이상치를 +로 표시한다.
pyplot.boxplot(male_weights, notch=True, sym='.')
pyplot.show()

png

도표에서 이상치를 생략하고 박스 그래프를 그려본다.

# 이상치의 생략한 잘록한 박스 그래프를 설정한다.
male_weights = [
    53, 59, 66, 67, 68, 70, 73, 74, 75, 78, 
    81, 82, 85, 90, 90, 91, 120, 130
]

pyplot.title('Outliers Not Shown')

# 격자를 생성한다.
pyplot.grid()

# 위의 코드에서 sym=''로 설정하여 이상치를 표시하지 않도록 한다. 
# 이상치를 표시하지 않기 때문에 y축이 90까지 표현되도록 자동으로 변경되었다.
pyplot.boxplot(male_weights, notch=True, sym='')
pyplot.show()

png

다음 예는 두 남자 그룹의 몸무게를 박스 그래프로 작성한 코드다.

# 두 남자 그룹의 몸무게를 박스 그래프로 설정한다.
male1_weights = [
    53, 59, 66, 67, 68, 70, 73, 74, 75, 78, 
    81, 82, 85, 90, 90, 91, 120, 130
]

male2_weights = [
    58, 61, 64, 67, 68, 71, 75, 77, 79,
    83, 84, 85, 89, 91, 93, 94, 121, 127
]

pyplot.title('Weight comparison of Two Groups')

# 격자를 생성한다.
pyplot.grid()

# 두 개의 데이터를 사용하여 박스 그래프를 작성한다.
# sym='o' 설정으로 이상치는 o로 표시하고, 
# labels=...로 각 박스 아래에 라벨을 설정한다.
pyplot.boxplot((male1_weights, male2_weights), 
               sym='o', 
               labels=('Male Group 1 Weight', 'Male Group 2 Weight'))
pyplot.show()

png

산점도

산점도는 두 변수 간의 관계를 좌표평면 상에 점으로 나타내는 그래프이다.

산점도를 작성하려면 scatter 메소드를 주로 scatter(x, y, s=None, c=None, marker=None, alpha=None) 형식으로 사용하면 된다.

matplotlib.pyplot.scatter

다음 예는 성인 남성들의 나이와 몸무게 데이터를 산점도로 작성한 코드다. 입력값인 나이와 몸무게의 데이터 개수는 25이며, 마커의 색상은 초록, 투명도는 0.5, 모양은 다이아몬드로 설정한다.

# 성인 남성들의 나이와 몸무게 데이터를 산점도로 설정한다.
age = [
    20, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
    30, 33, 37, 38, 39, 40, 40, 40, 40, 40, 40, 41, 41, 41
]
weight = [
    78, 65, 54, 59, 67, 80, 90, 83, 100, 64, 75,
    89, 89, 66, 68, 75, 79, 93, 88, 78, 83, 89, 78, 71, 82
]

pyplot.title('Scatter Plot of Age & Weight')

# age를 x축으로 weight을 y축으로 입력받아 산점도를 작성한다.
# 마커의 크기는 s=40으로, 투명도는 alpha=0.5로 설정한다.
# 마커를 빨간색 다이아몬드로 설정하기 위해 c='red', marker='D'로 설정한다. 
pyplot.scatter(age, weight, s=40, c='red', marker='D', alpha=0.5)
pyplot.show()

png

등고선 그래프

등고선은 지표의 높낮이를 나타내는 곡선을 뜻한다. 등고선 그래프를 작성하려면 contourcontourf 메소드를 사용한다.

다음 예는 contourcontourf를 사용하여 등고선 그래프를 작성한 코드다. contourf의 투명도를 0.75로 매개변수 cmap의 전달인자를 ‘jet’로 한다. contour의 컬러는 ‘black’으로 설정한다.

def f(x, y):
    return (1 - x / 2 + x ** 5 + y ** 3) * numpy.exp(-x ** 2 - y ** 2)

N = 256
x = numpy.linspace(-3, 3, N)
y = numpy.linspace(-3, 3, N)
X, Y = numpy.meshgrid(x, y)
Z = f(X, Y)

pyplot.title('Contour')
pyplot.contourf(X, Y, Z, alpha=.75, cmap='jet')
pyplot.contour(X, Y, Z, colors='black')

pyplot.show()

matplot35

3D 표면도

3D 표면도(surface plot)는 등고선 그래프와 달리 Axes3D라는 3차원 전공 axes를 생성하여 입체적으로 표시한다.

다음 예는 plot_surface를 사용하여 3D 표면도를 작성한 코드다. 매개변수 rstridecstride의 전달인자를 각각 1로, cmap의 전달인자를 ‘jet’로 설정한다.

from mpl_toolkits.mplot3d import Axes3D

x = numpy.arange(-4, 4, 0.25)
y = numpy.arange(-4, 4, 0.25)
X, Y = numpy.meshgrid(x, y)
R = numpy.sqrt(X ** 2 + Y ** 2)
Z = numpy.sin(R)

fig = pyplot.figure()
ax = Axes3D(fig, auto_add_to_figure=False)
fig.add_axes(ax)
ax.set_title('3D Surface Plot')

ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='jet')  # cmap='hot'
pyplot.show()

matplot35

Lab: 아파트 내 외국인 국적 및 연령 데이터 시각화

다음 데이터는 OO 아파트에 살고 있는 외국인들의 연령과 국적을 기록한 데이터다. 이 데이터를 이용하여 각 문제에서 제시하는 그래프를 그리시오.

age_groups = 'Age 10-20', 'Age 20-30', 'Age 30-40', 'Age 40-50'

chinese = 7, 8, 15, 11
japanese = 6, 7, 14, 10
vietnamese = 3, 5, 10, 9

문제 1 : 막대 그래프를 나란히 그리시오.



# YOUR CODE HERE

문제 2 : 누적 막대 그래프를 그리시오



# YOUR CODE HERE

문제 3 : 원 그래프를 그리시오.



# YOUR CODE HERE

Lab: 학급의 영어와 수학 점수 데이터 시각화

다음 데이터는 한 학급의 영어와 수학 시험 점수가 기록된 데이터다. 이 데이터를 이용하여 각 문제에서 제시하는 그래프를 그리시오.

english_score = [
    7, 17, 20, 28, 40, 59, 60, 62, 63, 64, 
    67, 69, 70, 70, 71, 72, 72, 72, 74, 77,
    78, 80, 97, 97,99
]
math_score = [
    5, 7, 14, 19, 28, 39, 40, 52, 60, 61, 
    63, 64, 65, 66, 66, 68, 69, 70, 71, 73,
    74, 76, 87, 90, 100
]

문제 1 : 히스토그램을 그리시오.



# YOUR CODE HERE

문제 2 : 박스 그래프를 그리시오.



# YOUR CODE HERE

문제 3 : 산점도를 그리시오.



# YOUR CODE HERE

THE END