Matplotlib 을 이용한 해치 (Hatch) 채움 히스토그램 생성

Beginner

This tutorial is from open-source community. Access the source code

소개

이 랩에서는 Matplotlib 을 사용하여 해치 (hatch) 로 채워진 히스토그램을 만드는 방법을 배웁니다. 히스토그램은 수치 데이터의 빈도를 막대 그래프로 나타낸 것입니다. 해치로 채워진 히스토그램은 막대가 선, 점 또는 기타 기호 패턴으로 채워진 히스토그램입니다.

VM 팁

VM 시작이 완료되면 왼쪽 상단을 클릭하여 Notebook 탭으로 전환하여 실습을 위해 Jupyter Notebook에 액세스하십시오.

때로는 Jupyter Notebook 이 로딩을 완료하는 데 몇 초 정도 기다려야 할 수 있습니다. Jupyter Notebook 의 제한으로 인해 작업의 유효성 검사는 자동화될 수 없습니다.

학습 중에 문제가 발생하면 언제든지 Labby 에게 문의하십시오. 세션 후 피드백을 제공해주시면 문제를 신속하게 해결해 드리겠습니다.

필요한 라이브러리 가져오기

이 랩에 필요한 라이브러리를 가져오겠습니다. 다음 라이브러리가 필요합니다.

  • 랜덤 데이터를 생성하기 위한 numpy
  • 플롯을 생성하기 위한 matplotlib.pyplot
  • 축 눈금 위치를 설정하기 위한 matplotlib.ticker
  • 스타일 사이클을 생성하기 위한 cycler
  • 부분 함수를 생성하기 위한 functools.partial
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
from cycler import cycler
from functools import partial

히스토그램 함수 정의

계단형 패치 (stepped patch) 로 히스토그램을 그리는 함수를 정의합니다. 이 함수는 다음과 같은 매개변수를 사용합니다.

  • ax: 플롯을 그릴 Axes
  • edges: 각 빈 (bin) 의 왼쪽 가장자리와 마지막 빈의 오른쪽 가장자리를 제공하는 길이 n+1 배열
  • values: 빈 카운트 또는 값을 나타내는 길이 n 배열
  • bottoms: float 또는 배열, 선택 사항, 막대의 하단을 나타내는 길이 n 배열. None 인 경우 0 이 사용됩니다.
  • orientation: 문자열, 선택 사항, 히스토그램의 방향. 'v'(기본값) 는 막대가 양의 y 방향으로 증가합니다.
def filled_hist(ax, edges, values, bottoms=None, orientation='v', **kwargs):
    """
    계단형 패치로 히스토그램을 그립니다.

    매개변수
    ----------
    ax : Axes
        플롯을 그릴 축 (Axes)

    edges : array
        각 빈 (bin) 의 왼쪽 가장자리와
        마지막 빈의 오른쪽 가장자리를 제공하는 길이 n+1 배열.

    values : array
        빈 카운트 또는 값을 나타내는 길이 n 배열

    bottoms : float 또는 array, 선택 사항
        막대의 하단을 나타내는 길이 n 배열.  None 인 경우 0 이 사용됩니다.

    orientation : {'v', 'h'}
       히스토그램의 방향.  'v'(기본값) 는
       막대가 양의 y 방향으로 증가합니다.

    **kwargs
        추가 키워드 인수는 `.fill_between` 으로 전달됩니다.

    반환값
    -------
    ret : PolyCollection
        Axes 에 추가된 아티스트 (Artist)
    """
    if orientation not in 'hv':
        raise ValueError(f"orientation must be in {{'h', 'v'}} not {orientation}")

    kwargs.setdefault('step', 'post')
    kwargs.setdefault('alpha', 0.7)
    edges = np.asarray(edges)
    values = np.asarray(values)
    if len(edges) - 1 != len(values):
        raise ValueError(f'Must provide one more bin edge than value not: {len(edges)=} {len(values)=}')

    if bottoms is None:
        bottoms = 0
    bottoms = np.broadcast_to(bottoms, values.shape)

    values = np.append(values, values[-1])
    bottoms = np.append(bottoms, bottoms[-1])
    if orientation == 'h':
        return ax.fill_betweenx(edges, values, bottoms, **kwargs)
    elif orientation == 'v':
        return ax.fill_between(edges, values, bottoms, **kwargs)
    else:
        raise AssertionError("you should never be here")

스택 히스토그램 함수 정의

스택 히스토그램을 생성하는 함수를 정의합니다. 이 함수는 다음과 같은 매개변수를 사용합니다.

  • ax: 아티스트 (artist) 를 추가할 축 (axes)
  • stacked_data: (M, N) 모양의 배열. 첫 번째 차원은 행별로 히스토그램을 계산하기 위해 반복됩니다.
  • sty_cycle: 각 세트에 적용할 스타일인 Cycler 또는 dict 의 연산 가능 객체
  • bottoms: 배열, 기본값: 0, 하단의 초기 위치.
  • hist_func: 호출 가능 객체, 선택 사항. 시그니처 bin_vals, bin_edges = f(data)가 있어야 합니다. bin_edgesbin_vals보다 하나 더 길어야 합니다.
  • labels: 문자열 목록, 선택 사항, 각 세트의 레이블. 제공되지 않고 stacked_data 가 배열인 경우 'default set {n}'으로 기본 설정됩니다. stacked_data 가 매핑이고 labels 가 None 인 경우 키로 기본 설정됩니다. stacked_data 가 매핑이고 labels 가 제공된 경우 나열된 열만 플롯됩니다.
  • plot_func: 호출 가능 객체, 선택 사항, 히스토그램을 그리기 위해 호출할 함수. 시그니처 ret = plot_func(ax, edges, top, bottoms=bottoms, label=label, **kwargs)가 있어야 합니다.
  • plot_kwargs: 딕셔너리, 선택 사항, 플로팅 함수에 전달할 추가 키워드 인수. 이는 플로팅 함수에 대한 모든 호출에 대해 동일하며 sty_cycle의 값을 재정의합니다.
def stack_hist(ax, stacked_data, sty_cycle, bottoms=None, hist_func=None, labels=None, plot_func=None, plot_kwargs=None):
    """
    매개변수
    ----------
    ax : axes.Axes
        아티스트를 추가할 축

    stacked_data : array 또는 Mapping
        (M, N) 모양의 배열. 첫 번째 차원은 행별로
        히스토그램을 계산하기 위해 반복됩니다.

    sty_cycle : Cycler 또는 dict 의 연산 가능 객체
        각 세트에 적용할 스타일

    bottoms : array, 기본값: 0
        하단의 초기 위치.

    hist_func : callable, 선택 사항
        시그니처 `bin_vals, bin_edges = f(data)`가 있어야 합니다.
        `bin_edges` 는 `bin_vals` 보다 하나 더 길어야 합니다.

    labels : list of str, 선택 사항
        각 세트의 레이블.

        제공되지 않고 stacked data 가 배열인 경우 'default set {n}'으로 기본 설정됩니다.

        *stacked_data*가 매핑이고 *labels*가 None 인 경우 키로 기본 설정됩니다.

        *stacked_data*가 매핑이고 *labels*가 제공된 경우 나열된
        열만 플롯됩니다.

    plot_func : callable, 선택 사항
        히스토그램을 그리기 위해 호출할 함수는 다음 시그니처를 가져야 합니다.

          ret = plot_func(ax, edges, top, bottoms=bottoms,
                          label=label, **kwargs)

    plot_kwargs : dict, 선택 사항
        플로팅 함수에 전달할 추가 키워드 인수.
        이는 플로팅 함수에 대한 모든 호출에 대해 동일하며
        *sty_cycle*의 값을 재정의합니다.

    반환값
    -------
    arts : dict
        레이블을 기준으로 키가 지정된 아티스트의 딕셔너리
    """
    ## 기본 binning 함수 처리
    if hist_func is None:
        hist_func = np.histogram

    ## 기본 플로팅 함수 처리
    if plot_func is None:
        plot_func = filled_hist

    ## 기본값 처리
    if plot_kwargs is None:
        plot_kwargs = {}

    try:
        l_keys = stacked_data.keys()
        label_data = True
        if labels is None:
            labels = l_keys

    except AttributeError:
        label_data = False
        if labels is None:
            labels = itertools.repeat(None)

    if label_data:
        loop_iter = enumerate((stacked_data[lab], lab, s) for lab, s in zip(labels, sty_cycle))
    else:
        loop_iter = enumerate(zip(stacked_data, labels, sty_cycle))

    arts = {}
    for j, (data, label, sty) in loop_iter:
        if label is None:
            label = f'dflt set {j}'
        label = sty.pop('label', label)
        vals, edges = hist_func(data)
        if bottoms is None:
            bottoms = np.zeros_like(vals)
        top = bottoms + vals
        sty.update(plot_kwargs)
        ret = plot_func(ax, edges, top, bottoms=bottoms, label=label, **sty)
        bottoms = top
        arts[label] = ret
    ax.legend(fontsize=10)
    return arts

고정 빈 (bin) 을 위한 히스토그램 함수 설정

numpy.histogram을 사용하여 고정 빈 (bin) 을 가진 히스토그램 함수를 설정합니다. -3 에서 3 까지의 범위를 갖는 20 개의 빈 (bin) 을 생성합니다.

edges = np.linspace(-3, 3, 20, endpoint=True)
hist_func = partial(np.histogram, bins=edges)

스타일 사이클 설정

cycler를 사용하여 히스토그램에 대한 스타일 사이클을 설정합니다. facecolor, label, 그리고 hatch 패턴에 대한 세 개의 스타일 사이클을 생성합니다.

color_cycle = cycler(facecolor=plt.rcParams['axes.prop_cycle'][:4])
label_cycle = cycler(label=[f'set {n}' for n in range(4)])
hatch_cycle = cycler(hatch=['/', '*', '+', '|'])

랜덤 데이터 생성

numpy.random.randn을 사용하여 랜덤 데이터를 생성합니다. 각 12250 개의 포인트를 가진 4 개의 데이터 세트를 생성합니다.

np.random.seed(19680801)
stack_data = np.random.randn(4, 12250)

해치 (hatch) 로 채워진 히스토그램 생성

앞서 정의한 stack_hist 함수를 사용하여 해치로 채워진 히스토그램을 생성합니다. 앞서 정의한 stack_data, color_cycle, 그리고 hist_func를 사용합니다. 또한 plot_kwargs를 설정하여 edgecolor 와 orientation 을 포함시킵니다.

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(9, 4.5), tight_layout=True)
arts = stack_hist(ax1, stack_data, color_cycle + label_cycle + hatch_cycle, hist_func=hist_func)

arts = stack_hist(ax2, stack_data, color_cycle, hist_func=hist_func, plot_kwargs=dict(edgecolor='w', orientation='h'))
ax1.set_ylabel('counts')
ax1.set_xlabel('x')
ax2.set_xlabel('counts')
ax2.set_ylabel('x')

레이블이 지정된 해치 (hatch) 로 채워진 히스토그램 생성

앞서 정의한 stack_hist 함수를 사용하여 레이블이 지정된 해치로 채워진 히스토그램을 생성합니다. 앞서 정의한 dict_data, color_cycle, 그리고 hist_func를 사용합니다. 또한 처음과 마지막 세트만 플롯하기 위해 labels['set 0', 'set 3']으로 설정합니다.

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(9, 4.5), tight_layout=True, sharey=True)
dict_data = dict(zip((c['label'] for c in label_cycle), stack_data))
arts = stack_hist(ax1, dict_data, color_cycle + hatch_cycle, hist_func=hist_func)

arts = stack_hist(ax2, dict_data, color_cycle + hatch_cycle, hist_func=hist_func, labels=['set 0', 'set 3'])
ax1.xaxis.set_major_locator(mticker.MaxNLocator(5))
ax1.set_xlabel('counts')
ax1.set_ylabel('x')
ax2.set_ylabel('x')

요약

이 랩에서는 Matplotlib 을 사용하여 해치로 채워진 히스토그램을 생성하는 방법을 배웠습니다. 우리는 두 개의 함수를 정의했습니다: 스텝 패치 (stepped patch) 로 히스토그램을 그리는 filled_hist와 스택 히스토그램을 생성하는 stack_hist. 또한 numpy.histogram을 사용하여 고정된 빈 (bin) 을 가진 히스토그램 함수를 설정하고, cycler를 사용하여 히스토그램에 대한 세 가지 스타일 사이클을 정의했습니다. 마지막으로, 우리는 임의의 데이터를 생성하고 stack_hist 함수를 사용하여 두 개의 해치로 채워진 히스토그램을 생성했습니다.