/r/dataisbeautiful에 맞는 애니메이션 GIF를 만드는 방법

좋은 비주얼리제이션은 청중의 관심을 끌고 깊은 인상을 주어야 합니다. 밝은 색상과 움직임보다 관심을 끄는 것은 거의 없습니다.

이 게시물에서 나는 당신이 /r/dataisbeautiful에서 일부 인터넷 포인트를 파밍할 수 있도록 애니메이션 GIF를 만드는 방법을 정확히 보여줄 것입니다.

우리가 만들 것은 다음과 같습니다.



0단계 - 데이터



그래프를 만들기 전에 몇 가지 데이터를 손에 넣어야 합니다. StatsCanada에서 일부 비즈니스 데이터를 가져왔습니다here. 데이터가 최상의 상태가 아니므로 데이터를 덜 빨아들이도록 약간의 팬더가 있습니다.

import pandas as pd

df = pd.read_csv("3310027001-noSymbol.csv", skiprows=7).iloc[1:5]
df = df.rename(columns={"Business dynamics measure": "status"})
df['status'] = df['status'].apply(lambda x: x[:-13])
df = pd.melt(df, id_vars="status", var_name="date", value_name="count")
df["date"] = pd.to_datetime(df["date"], format="%B %Y")
df['count'] = df['count'].apply(lambda x: int(x.replace(",", "")))

print(df.head())
#        status       date   count
# 0      Active 2015-01-01  775497
# 1     Opening 2015-01-01   40213
# 2  Continuing 2015-01-01  731116
# 3     Closing 2015-01-01   30979
# 4      Active 2015-02-01  778554

1단계 - 그래프



GIF를 만들려면 먼저 단일 프레임을 만들어야 합니다. 우연히도 그래프일 뿐입니다.

from matplotlib import pyplot as plt

da = df[df["status"] == "Active"]
plt.plot(da["date"], da["count"])



2단계 - 크기



그래프가 더 커질 수 있고 y축 제한이 조정될 수 있습니다. 문제 없습니다. 두 줄의 코드가 추가되었습니다. 일부 코드는 크기를 조정하고 제한할 수 있습니다.

plt.figure(figsize=(8, 5), dpi=300)
plt.plot(da["date"], da["count"])
plt.ylim([0, da['count'].max() * 1.1])



3단계 - 틱



내 그래프에서 눈금을 수동으로 설정하고 싶지만 그럴 필요는 없지만 원하는 경우:

ymax = int(da['count'].max() * 1.1 // 1)

plt.figure(figsize=(8, 5), dpi=300)
plt.plot(da["date"], da["count"])
plt.ylim([0, ymax])
plt.yticks(range(0, ymax, 200_000))



4단계 - 라벨



누군가 지금 우리의 그래프를 본다면 아무런 맥락도 없이 무슨 일이 일어나고 있는지 알 것입니다. 몇 가지 레이블을 추가하여 문제를 해결해 보겠습니다.

plt.figure(figsize=(8, 5), dpi=300)
plt.plot(da["date"], da["count"])
plt.ylim([0, ymax])
plt.yticks(range(0, ymax, 200_000))
plt.title("Active Businesses in Canada (Seasonally Adjusted)")
plt.xlabel("Year")
plt.ylabel("Count")



4.5단계 - 우회



우리의 그래프는 캐나다의 "활성"비즈니스에 대한 것입니다. "시작"및 "마감"숫자는 다음과 같습니다.

dc = df[df["status"] == "Closing"]
do = df[df["status"] == "Opening"]

plt.plot(dc["date"], dc["count"], color='red', label="closing")
plt.plot(do["date"], do["count"], color='green', label="opening")
plt.legend()



5단계 - 결합



"열림 및 닫힘"그래프는 "활성"데이터에 흥미로운 색상을 추가합니다. 멋진 바지 matplotlib와 두 가지를 결합해 봅시다.

rows = 7
figure = plt.figure(figsize=(8, 4), constrained_layout=False, dpi=300)
grid = plt.GridSpec(
    nrows=rows,
    ncols=1,
    wspace=0,
    hspace=0.5,
    figure=figure
)

main = plt.subplot(grid[:5, 0])
sub = plt.subplot(grid[5:, 0])

main.plot(da["date"], da["count"])
sub.plot(do["date"], do["count"])
sub.plot(dc["date"], dc["count"])



6단계 - 색상



나는 지금 가지고 있는 것의 색상이나 간격에 관심이 없습니다. 몇 가지 축 조정과 함께 수정하려면 다음이 필요합니다.

figure = plt.figure(figsize=(8, 4), constrained_layout=False, dpi=300)
grid = plt.GridSpec(
    nrows=rows,
    ncols=1,
    wspace=0,
    hspace=0.75,
    figure=figure
)

main = plt.subplot(grid[:5, 0])
sub = plt.subplot(grid[5:, 0])

main.plot(da["date"], da["count"], color="purple")
sub.plot(do["date"], do["count"], color="blue")
sub.plot(dc["date"], dc["count"], color="red")

main.set_xticks([])
main.set_ylim([0, ymax])
main.set_yticks(range(0, ymax, 200_000))
main.set_yticklabels([0, "200K", "400K", "600K", "800K\nbusinesses"])

sub.set_ylim([0, 110_000])
sub.set_yticks([0, 100_000])
sub.set_yticklabels([0, "100K"])



7단계 - 리팩토링



그래프 코드가 거의 준비되었습니다. 개별 날짜를 취하고 해당 날짜에 대한 개별 프레임을 만들 수 있도록 리팩터링하기만 하면 됩니다. 또한 일부 vlines를 추가하고 xlim를 수정하여 가독성을 높이고 플로팅 공간이 플롯 간에 일관되도록 했습니다.

date = pd.Timestamp("2019-08-01")

xmin = df['date'].min()
xmax = df['date'].max()

dd = df[df["date"] <= date]
dc = dd[dd["status"] == "Closing"]
do = dd[dd["status"] == "Opening"]
da = dd[dd["status"] == "Active"]

figure = plt.figure(figsize=(8, 4), constrained_layout=False, dpi=300)
grid = plt.GridSpec(
    nrows=rows,
    ncols=1,
    wspace=0,
    hspace=1.25,
    figure=figure
)

main = plt.subplot(grid[:5, 0])
sub = plt.subplot(grid[5:, 0])

main.plot(da["date"], da["count"], color="#457b9d")
main.vlines(date, ymin=0, ymax=1e20, color="#000000")
sub.plot(do["date"], do["count"], color="#a8dadc")
sub.plot(dc["date"], dc["count"], color="#e63946")
sub.vlines(date, ymin=0, ymax=1e20, color="#000000")

main.set_xlim([xmin, xmax])
main.set_xticks([])
main.set_ylim([0, ymax])
main.set_yticks(range(0, ymax, 200_000))
main.set_yticklabels([0, "200K", "400K", "600K", "800K"])
main.set_title("Active Businesses in Canada")

sub.set_xlim([xmin, xmax])
sub.set_xticks([date])
sub.set_xticklabels([date.strftime("%B '%y")])
sub.set_ylim([0, 110_000])
sub.set_yticks([0, 100_000])
sub.set_yticklabels([0, "100K"])
sub.set_title("Businesses Opening and Closing")



7.5단계 - 기능화



여러 날짜에 여러 프레임을 빌드하려면 코드를 함수로 래핑해야 합니다.

def plot(date):
    dd = df[df["date"] <= date]
    dc = dd[dd["status"] == "Closing"]
    do = dd[dd["status"] == "Opening"]
    da = dd[dd["status"] == "Active"]

    figure = plt.figure(figsize=(8, 4), constrained_layout=False, dpi=300)
    grid = plt.GridSpec(
        nrows=rows,
        ncols=1,
        wspace=0,
        hspace=1.25,
        figure=figure
    )

    main = plt.subplot(grid[:5, 0])
    sub = plt.subplot(grid[5:, 0])

    main.plot(da["date"], da["count"], color="#457b9d")
    main.vlines(date, ymin=0, ymax=1e20, color="#000000")
    sub.plot(do["date"], do["count"], color="#a8dadc")
    sub.plot(dc["date"], dc["count"], color="#e63946")
    sub.vlines(date, ymin=0, ymax=1e20, color="#000000")

    main.set_xlim([xmin, xmax])
    main.set_xticks([])
    main.set_ylim([0, ymax])
    main.set_yticks(range(0, ymax, 200_000))
    main.set_yticklabels([0, "200K", "400K", "600K", "800K"])
    main.set_title("Active Businesses in Canada")

    sub.set_xlim([xmin, xmax])
    sub.set_xticks([date])
    sub.set_xticklabels([date.strftime("%b '%y")])
    sub.set_ylim([0, 110_000])
    sub.set_yticks([0, 100_000])
    sub.set_yticklabels([0, "100K"])
    sub.set_title("Businesses Opening and Closing");

단 한 번의 호출로 프레임을 만들 수 있습니다.

plot(pd.Timestamp("2017-06-01"))

8단계 - GIF 가져오기



정적 프레임을 애니메이션 gif로 바꾸려면 이제 gif package을 설치하고 가져오기만 하면 됩니다.

import gif
plot 함수를 gif.frame로 장식합니다.

@gif.frame
def plot(date):
    dd = df[df["date"] <= date]
    dc = dd[dd["status"] == "Closing"]
    do = dd[dd["status"] == "Opening"]
    da = dd[dd["status"] == "Active"]

    figure = plt.figure(figsize=(8, 4), constrained_layout=False, dpi=300)
    grid = plt.GridSpec(
        nrows=7,
        ncols=1,
        wspace=0,
        hspace=1.25,
        figure=figure
    )

    main = plt.subplot(grid[:5, 0])
    sub = plt.subplot(grid[5:, 0])

    main.plot(da["date"], da["count"], color="#457b9d")
    main.vlines(date, ymin=0, ymax=1e20, color="#000000")
    sub.plot(do["date"], do["count"], color="#a8dadc")
    sub.plot(dc["date"], dc["count"], color="#e63946")
    sub.vlines(date, ymin=0, ymax=1e20, color="#000000")

    main.set_xlim([xmin, xmax])
    main.set_xticks([])
    main.set_ylim([0, ymax])
    main.set_yticks(range(0, ymax, 200_000))
    main.set_yticklabels([0, "200K", "400K", "600K", "800K"])
    main.set_title("Active Businesses in Canada")

    sub.set_xlim([xmin, xmax])
    sub.set_xticks([date])
    sub.set_xticklabels([date.strftime("%b '%y")])
    sub.set_ylim([0, 110_000])
    sub.set_yticks([0, 100_000])
    sub.set_yticklabels([0, "100K"])
    sub.set_title("Businesses Opening and Closing");

모든 프레임 구축:

dates = pd.date_range(df['date'].min(), df['date'].max(), freq="1MS")

frames = [plot(date) for date in dates]

그리고 애니메이션을 디스크에 저장합니다.

gif.save(frames, "businesses.gif", duration=5, unit="s", between="startend")



이제 흥미로운 데이터를 찾아 GIF로 변환할 차례입니다.

더 알고 싶으시면 ODSC/AI+ on October 22 과 함께 gif에 대한 워크샵을 진행하고 있습니다. 수업에서 뵙기를 바랍니다!

좋은 웹페이지 즐겨찾기