看完這篇文章,我徹底愛上了Python動態圖表!

2021-02-24 裸睡的豬

關於動態條形圖,小F以前推薦過「Bar Chart Race」這個庫。三行代碼就能實現動態條形圖的繪製。

有些同學在使用的時候,會出現一些錯誤。一個是加載文件報錯,另一個是生成GIF的時候報錯。

這是因為作者的示例是網絡加載數據,會讀取不到。通過讀取本地文件,就不會出錯。

GIF生成失敗一般是需要安裝imagemagick(圖片處理工具)。

最近小F又發現一個可視化圖庫「Pandas_Alive」,不僅包含動態條形圖,還可以繪製動態曲線圖、氣泡圖、餅狀圖、地圖等。

同樣也是幾行代碼就能完成動態圖表的繪製。

GitHub地址:

https://github.com/JackMcKew/pandas_alive

使用文檔:https://jackmckew.github.io/pandas_alive/

安裝版本建議是0.2.3matplotlib版本是3.2.1

同時需自行安裝tqdm(顯示進度條)和descartes(繪製地圖相關庫)。

要不然會出現報錯,估計是作者的requestment.txt沒包含這兩個庫。

好了,成功安裝後就可以引入這個第三方庫,直接選擇加載本地文件。

import pandas_alive
import pandas as pd

covid_df = pd.read_csv('data/covid19.csv', index_col=0, parse_dates=[0])
covid_df.plot_animated(filename='examples/example-barh-chart.gif', n_visible=15)

生成了一個GIF圖,具體如下。

剛開始學習這個庫的時候,大家可以減少數據,這樣生成GIF的時間就會快一些

比如小F在接下來的實踐中,基本都只選取了20天左右的數據。

對於其他圖表,我們可以查看官方文檔的API說明,得以了解。

下面我們就來看看其他動態圖表的繪製方法吧!

01 動態條形圖


elec_df = pd.read_csv("data/Aus_Elec_Gen_1980_2018.csv", index_col=0, parse_dates=[0], thousands=',')
elec_df = elec_df.iloc[:20, :]
elec_df.fillna(0).plot_animated('examples/example-electricity-generated-australia.gif', period_fmt="%Y",
                                title='Australian Electricity Generation Sources 1980-2018')


02 動態柱狀圖


covid_df = pd.read_csv('data/covid19.csv', index_col=0, parse_dates=[0])
covid_df.plot_animated(filename='examples/example-barv-chart.gif', orientation='v', n_visible=15)

03 動態曲線圖


covid_df = pd.read_csv('data/covid19.csv', index_col=0, parse_dates=[0])
covid_df.diff().fillna(0).plot_animated(filename='examples/example-line-chart.gif', kind='line', period_label={'x': 0.25, 'y': 0.9})


04 動態面積圖


covid_df = pd.read_csv('data/covid19.csv', index_col=0, parse_dates=[0])
covid_df.sum(axis=1).fillna(0).plot_animated(filename='examples/example-bar-chart.gif', kind='bar',
        period_label={'x': 0.1, 'y': 0.9},
        enable_progress_bar=True, steps_per_period=2, interpolate_period=True, period_length=200
)

05 動態散點圖


max_temp_df = pd.read_csv(
    "data/Newcastle_Australia_Max_Temps.csv",
    parse_dates={"Timestamp": ["Year", "Month", "Day"]},
)
min_temp_df = pd.read_csv(
    "data/Newcastle_Australia_Min_Temps.csv",
    parse_dates={"Timestamp": ["Year", "Month", "Day"]},
)

max_temp_df = max_temp_df.iloc[:5000, :]
min_temp_df = min_temp_df.iloc[:5000, :]

merged_temp_df = pd.merge_asof(max_temp_df, min_temp_df, on="Timestamp")
merged_temp_df.index = pd.to_datetime(merged_temp_df["Timestamp"].dt.strftime('%Y/%m/%d'))

keep_columns = ["Minimum temperature (Degree C)", "Maximum temperature (Degree C)"]
merged_temp_df[keep_columns].resample("Y").mean().plot_animated(filename='examples/example-scatter-chart.gif', kind="scatter",
                                                                title='Max & Min Temperature Newcastle, Australia')

06 動態餅狀圖


covid_df = pd.read_csv('data/covid19.csv', index_col=0, parse_dates=[0])
covid_df.plot_animated(filename='examples/example-pie-chart.gif', kind="pie",
                       rotatelabels=True, period_label={'x': 0, 'y': 0})

07 動態氣泡圖

multi_index_df = pd.read_csv("data/multi.csv", header=[0, 1], index_col=0)
multi_index_df.index = pd.to_datetime(multi_index_df.index, dayfirst=True)

map_chart = multi_index_df.plot_animated(
    kind="bubble",
    filename="examples/example-bubble-chart.gif",
    x_data_label="Longitude",
    y_data_label="Latitude",
    size_data_label="Cases",
    color_data_label="Cases",
    vmax=5, steps_per_period=3, interpolate_period=True, period_length=500,
    dpi=100
)

08 地理空間點圖表


import geopandas
import pandas_alive
import contextily

gdf = geopandas.read_file('data/nsw-covid19-cases-by-postcode.gpkg')
gdf.index = gdf.postcode
gdf = gdf.drop('postcode',axis=1)

result = gdf.iloc[:, :20]
result['geometry'] = gdf.iloc[:, -1:]['geometry']

map_chart = result.plot_animated(filename='examples/example-geo-point-chart.gif',
                                 basemap_format={'source':contextily.providers.Stamen.Terrain})

09 多邊形地理圖表


import geopandas
import pandas_alive
import contextily

gdf = geopandas.read_file('data/italy-covid-region.gpkg')
gdf.index = gdf.region
gdf = gdf.drop('region',axis=1)

result = gdf.iloc[:, :20]
result['geometry'] = gdf.iloc[:, -1:]['geometry']

map_chart = result.plot_animated(filename='examples/example-geo-polygon-chart.gif',
                                 basemap_format={'source': contextily.providers.Stamen.Terrain})

10 多個動態圖表


covid_df = pd.read_csv('data/covid19.csv', index_col=0, parse_dates=[0])

animated_line_chart = covid_df.diff().fillna(0).plot_animated(kind='line', period_label=False,add_legend=False)
animated_bar_chart = covid_df.plot_animated(n_visible=10)

pandas_alive.animate_multiple_plots('examples/example-bar-and-line-chart.gif',
                                    [animated_bar_chart, animated_line_chart], enable_progress_bar=True)

11 城市人口


def population():
    urban_df = pd.read_csv("data/urban_pop.csv", index_col=0, parse_dates=[0])

    animated_line_chart = (
        urban_df.sum(axis=1)
            .pct_change()
            .fillna(method='bfill')
            .mul(100)
            .plot_animated(kind="line", title="Total % Change in Population", period_label=False, add_legend=False)
    )

    animated_bar_chart = urban_df.plot_animated(n_visible=10, title='Top 10 Populous Countries', period_fmt="%Y")

    pandas_alive.animate_multiple_plots('examples/example-bar-and-line-urban-chart.gif',
                                        [animated_bar_chart, animated_line_chart],
                                        title='Urban Population 1977 - 2018', adjust_subplot_top=0.85,
                                        enable_progress_bar=True)

12 G7國家平均壽命


def life():
    data_raw = pd.read_csv("data/long.csv")

    list_G7 = [
        "Canada",
        "France",
        "Germany",
        "Italy",
        "Japan",
        "United Kingdom",
        "United States",
    ]

    data_raw = data_raw.pivot(
        index="Year", columns="Entity", values="Life expectancy (Gapminder, UN)"
    )

    data = pd.DataFrame()
    data["Year"] = data_raw.reset_index()["Year"]
    for country in list_G7:
        data[country] = data_raw[country].values

    data = data.fillna(method="pad")
    data = data.fillna(0)
    data = data.set_index("Year").loc[1900:].reset_index()

    data["Year"] = pd.to_datetime(data.reset_index()["Year"].astype(str))

    data = data.set_index("Year")
    data = data.iloc[:25, :]

    animated_bar_chart = data.plot_animated(
        period_fmt="%Y", perpendicular_bar_func="mean", period_length=200, fixed_max=True
    )

    animated_line_chart = data.plot_animated(
        kind="line", period_fmt="%Y", period_length=200, fixed_max=True
    )

    pandas_alive.animate_multiple_plots(
        "examples/life-expectancy.gif",
        plots=[animated_bar_chart, animated_line_chart],
        title="Life expectancy in G7 countries up to 2015",
        adjust_subplot_left=0.2, adjust_subplot_top=0.9, enable_progress_bar=True
    )

13 新南威爾斯州COVID可視化


def nsw():
    import geopandas
    import pandas as pd
    import pandas_alive
    import contextily
    import matplotlib.pyplot as plt
    import json

    with open('data/package_show.json', 'r', encoding='utf8')as fp:
        data = json.load(fp)

    # Extract url to csv component
    covid_nsw_data_url = data["result"]["resources"][0]["url"]
    print(covid_nsw_data_url)

    # Read csv from data API url
    nsw_covid = pd.read_csv('data/confirmed_cases_table1_location.csv')
    postcode_dataset = pd.read_csv("data/postcode-data.csv")

    # Prepare data from NSW health dataset

    nsw_covid = nsw_covid.fillna(9999)
    nsw_covid["postcode"] = nsw_covid["postcode"].astype(int)

    grouped_df = nsw_covid.groupby(["notification_date", "postcode"]).size()
    grouped_df = pd.DataFrame(grouped_df).unstack()
    grouped_df.columns = grouped_df.columns.droplevel().astype(str)

    grouped_df = grouped_df.fillna(0)
    grouped_df.index = pd.to_datetime(grouped_df.index)

    cases_df = grouped_df

    # Clean data in postcode dataset prior to matching

    grouped_df = grouped_df.T
    postcode_dataset = postcode_dataset[postcode_dataset['Longitude'].notna()]
    postcode_dataset = postcode_dataset[postcode_dataset['Longitude'] != 0]
    postcode_dataset = postcode_dataset[postcode_dataset['Latitude'].notna()]
    postcode_dataset = postcode_dataset[postcode_dataset['Latitude'] != 0]
    postcode_dataset['Postcode'] = postcode_dataset['Postcode'].astype(str)

    # Build GeoDataFrame from Lat Long dataset and make map chart
    grouped_df['Longitude'] = grouped_df.index.map(postcode_dataset.set_index('Postcode')['Longitude'].to_dict())
    grouped_df['Latitude'] = grouped_df.index.map(postcode_dataset.set_index('Postcode')['Latitude'].to_dict())
    gdf = geopandas.GeoDataFrame(
        grouped_df, geometry=geopandas.points_from_xy(grouped_df.Longitude, grouped_df.Latitude), crs="EPSG:4326")
    gdf = gdf.dropna()

    # Prepare GeoDataFrame for writing to geopackage
    gdf = gdf.drop(['Longitude', 'Latitude'], axis=1)
    gdf.columns = gdf.columns.astype(str)
    gdf['postcode'] = gdf.index
    # gdf.to_file("data/nsw-covid19-cases-by-postcode.gpkg", layer='nsw-postcode-covid', driver="GPKG")

    # Prepare GeoDataFrame for plotting
    gdf.index = gdf.postcode
    gdf = gdf.drop('postcode', axis=1)
    gdf = gdf.to_crs("EPSG:3857")  # Web Mercator

    result = gdf.iloc[:, :22]
    result['geometry'] = gdf.iloc[:, -1:]['geometry']
    gdf = result

    map_chart = gdf.plot_animated(basemap_format={'source': contextily.providers.Stamen.Terrain}, cmap='cool')

    # cases_df.to_csv('data/nsw-covid-cases-by-postcode.csv')
    cases_df = cases_df.iloc[:22, :]

    from datetime import datetime

    bar_chart = cases_df.sum(axis=1).plot_animated(
        kind='line',
        label_events={
            'Ruby Princess Disembark': datetime.strptime("19/03/2020", "%d/%m/%Y"),
            # 'Lockdown': datetime.strptime("31/03/2020", "%d/%m/%Y")
        },
        fill_under_line_color="blue",
        add_legend=False
    )

    map_chart.ax.set_title('Cases by Location')

    grouped_df = pd.read_csv('data/nsw-covid-cases-by-postcode.csv', index_col=0, parse_dates=[0])
    grouped_df = grouped_df.iloc[:22, :]

    line_chart = (
        grouped_df.sum(axis=1)
            .cumsum()
            .fillna(0)
            .plot_animated(kind="line", period_label=False, title="Cumulative Total Cases", add_legend=False)
    )

    def current_total(values):
        total = values.sum()
        s = f'Total : {int(total)}'
        return {'x': .85, 'y': .2, 's': s, 'ha': 'right', 'size': 11}

    race_chart = grouped_df.cumsum().plot_animated(
        n_visible=5, title="Cases by Postcode", period_label=False, period_summary_func=current_total
    )

    import time

    timestr = time.strftime("%d/%m/%Y")

    plots = [bar_chart, line_chart, map_chart, race_chart]

    from matplotlib import rcParams

    rcParams.update({"figure.autolayout": False})
    # make sure figures are `Figure()` instances
    figs = plt.Figure()
    gs = figs.add_gridspec(2, 3, hspace=0.5)
    f3_ax1 = figs.add_subplot(gs[0, :])
    f3_ax1.set_title(bar_chart.title)
    bar_chart.ax = f3_ax1

    f3_ax2 = figs.add_subplot(gs[1, 0])
    f3_ax2.set_title(line_chart.title)
    line_chart.ax = f3_ax2

    f3_ax3 = figs.add_subplot(gs[1, 1])
    f3_ax3.set_title(map_chart.title)
    map_chart.ax = f3_ax3

    f3_ax4 = figs.add_subplot(gs[1, 2])
    f3_ax4.set_title(race_chart.title)
    race_chart.ax = f3_ax4

    timestr = cases_df.index.max().strftime("%d/%m/%Y")
    figs.suptitle(f"NSW COVID-19 Confirmed Cases up to {timestr}")

    pandas_alive.animate_multiple_plots(
        'examples/nsw-covid.gif',
        plots,
        figs,
        enable_progress_bar=True
    )

14 義大利COVID可視化


def italy():
    import geopandas
    import pandas as pd
    import pandas_alive
    import contextily
    import matplotlib.pyplot as plt

    region_gdf = geopandas.read_file('data/geo-data/italy-with-regions')
    region_gdf.NOME_REG = region_gdf.NOME_REG.str.lower().str.title()
    region_gdf = region_gdf.replace('Trentino-Alto Adige/Sudtirol', 'Trentino-Alto Adige')
    region_gdf = region_gdf.replace("Valle D'Aosta/Vallée D'Aoste\r\nValle D'Aosta/Vallée D'Aoste", "Valle d'Aosta")

    italy_df = pd.read_csv('data/Regional Data - Sheet1.csv', index_col=0, header=1, parse_dates=[0])

    italy_df = italy_df[italy_df['Region'] != 'NA']

    cases_df = italy_df.iloc[:, :3]
    cases_df['Date'] = cases_df.index
    pivoted = cases_df.pivot(values='New positives', index='Date', columns='Region')
    pivoted.columns = pivoted.columns.astype(str)
    pivoted = pivoted.rename(columns={'nan': 'Unknown Region'})

    cases_gdf = pivoted.T
    cases_gdf['geometry'] = cases_gdf.index.map(region_gdf.set_index('NOME_REG')['geometry'].to_dict())

    cases_gdf = cases_gdf[cases_gdf['geometry'].notna()]

    cases_gdf = geopandas.GeoDataFrame(cases_gdf, crs=region_gdf.crs, geometry=cases_gdf.geometry)

    gdf = cases_gdf

    result = gdf.iloc[:, :22]
    result['geometry'] = gdf.iloc[:, -1:]['geometry']
    gdf = result

    map_chart = gdf.plot_animated(basemap_format={'source': contextily.providers.Stamen.Terrain}, cmap='viridis')

    cases_df = pivoted
    cases_df = cases_df.iloc[:22, :]

    from datetime import datetime

    bar_chart = cases_df.sum(axis=1).plot_animated(
        kind='line',
        label_events={
            'Schools Close': datetime.strptime("4/03/2020", "%d/%m/%Y"),
            'Phase I Lockdown': datetime.strptime("11/03/2020", "%d/%m/%Y"),
            # '1M Global Cases': datetime.strptime("02/04/2020", "%d/%m/%Y"),
            # '100k Global Deaths': datetime.strptime("10/04/2020", "%d/%m/%Y"),
            # 'Manufacturing Reopens': datetime.strptime("26/04/2020", "%d/%m/%Y"),
            # 'Phase II Lockdown': datetime.strptime("4/05/2020", "%d/%m/%Y"),
        },
        fill_under_line_color="blue",
        add_legend=False
    )

    map_chart.ax.set_title('Cases by Location')

    line_chart = (
        cases_df.sum(axis=1)
            .cumsum()
            .fillna(0)
            .plot_animated(kind="line", period_label=False, title="Cumulative Total Cases", add_legend=False)
    )

    def current_total(values):
        total = values.sum()
        s = f'Total : {int(total)}'
        return {'x': .85, 'y': .1, 's': s, 'ha': 'right', 'size': 11}

    race_chart = cases_df.cumsum().plot_animated(
        n_visible=5, title="Cases by Region", period_label=False, period_summary_func=current_total
    )

    import time

    timestr = time.strftime("%d/%m/%Y")

    plots = [bar_chart, race_chart, map_chart, line_chart]

    # Otherwise titles overlap and adjust_subplot does nothing
    from matplotlib import rcParams
    from matplotlib.animation import FuncAnimation

    rcParams.update({"figure.autolayout": False})
    # make sure figures are `Figure()` instances
    figs = plt.Figure()
    gs = figs.add_gridspec(2, 3, hspace=0.5)
    f3_ax1 = figs.add_subplot(gs[0, :])
    f3_ax1.set_title(bar_chart.title)
    bar_chart.ax = f3_ax1

    f3_ax2 = figs.add_subplot(gs[1, 0])
    f3_ax2.set_title(race_chart.title)
    race_chart.ax = f3_ax2

    f3_ax3 = figs.add_subplot(gs[1, 1])
    f3_ax3.set_title(map_chart.title)
    map_chart.ax = f3_ax3

    f3_ax4 = figs.add_subplot(gs[1, 2])
    f3_ax4.set_title(line_chart.title)
    line_chart.ax = f3_ax4

    axes = [f3_ax1, f3_ax2, f3_ax3, f3_ax4]
    timestr = cases_df.index.max().strftime("%d/%m/%Y")
    figs.suptitle(f"Italy COVID-19 Confirmed Cases up to {timestr}")

    pandas_alive.animate_multiple_plots(
        'examples/italy-covid.gif',
        plots,
        figs,
        enable_progress_bar=True
    )

15 單擺運動


def simple():
    import pandas as pd
    import matplotlib.pyplot as plt
    import pandas_alive
    import numpy as np

    # Physical constants
    g = 9.81
    L = .4
    mu = 0.2

    THETA_0 = np.pi * 70 / 180  # init angle = 70degs
    THETA_DOT_0 = 0  # no init angVel
    DELTA_T = 0.01  # time stepping
    T = 1.5  # time period

    # Definition of ODE (ordinary differential equation)
    def get_theta_double_dot(theta, theta_dot):
        return -mu * theta_dot - (g / L) * np.sin(theta)

    # Solution to the differential equation
    def pendulum(t):
        # initialise changing values
        theta = THETA_0
        theta_dot = THETA_DOT_0
        delta_t = DELTA_T
        ang = []
        ang_vel = []
        ang_acc = []
        times = []
        for time in np.arange(0, t, delta_t):
            theta_double_dot = get_theta_double_dot(
                theta, theta_dot
            )
            theta += theta_dot * delta_t
            theta_dot += theta_double_dot * delta_t
            times.append(time)
            ang.append(theta)
            ang_vel.append(theta_dot)
            ang_acc.append(theta_double_dot)
        data = np.array([ang, ang_vel, ang_acc])
        return pd.DataFrame(data=data.T, index=np.array(times), columns=["angle", "ang_vel", "ang_acc"])

    # units used for ref: ["angle [rad]", "ang_vel [rad/s]", "ang_acc [rad/s^2]"]
    df = pendulum(T)
    df.index.names = ["Time (s)"]
    print(df)

    # generate dataFrame for animated bubble plot
    df2 = pd.DataFrame(index=df.index)
    df2["dx (m)"] = L * np.sin(df["angle"])
    df2["dy (m)"] = -L * np.cos(df["angle"])
    df2["ang_vel"] = abs(df["ang_vel"])
    df2["size"] = df2["ang_vel"] * 100  # scale angular vels to get nice size on bubble plot
    print(df2)

    # static pandas plots
    #
    # print(plt.style.available)
    # NOTE: 2 lines below required in Jupyter to switch styles correctly
    plt.rcParams.update(plt.rcParamsDefault)
    plt.style.use("ggplot")  # set plot style

    fig, (ax1a, ax2b) = plt.subplots(1, 2, figsize=(8, 4), dpi=100)  # 1 row, 2 subplots
    # fig.subplots_adjust(wspace=0.1)      # space subplots in row
    fig.set_tight_layout(True)
    fontsize = "small"

    df.plot(ax=ax1a).legend(fontsize=fontsize)
    ax1a.set_title("Outputs vs Time", fontsize="medium")
    ax1a.set_xlabel('Time [s]', fontsize=fontsize)
    ax1a.set_ylabel('Amplitudes', fontsize=fontsize);

    df.plot(ax=ax2b, x="angle", y=["ang_vel", "ang_acc"]).legend(fontsize=fontsize)
    ax2b.set_title("Outputs vs Angle | Phase-Space", fontsize="medium")
    ax2b.set_xlabel('Angle [rad]', fontsize=fontsize)
    ax2b.set_ylabel('Angular Velocity / Acc', fontsize=fontsize)

    # sample scatter plot with colorbar
    fig, ax = plt.subplots()
    sc = ax.scatter(df2["dx (m)"], df2["dy (m)"], s=df2["size"] * .1, c=df2["ang_vel"], cmap="jet")
    cbar = fig.colorbar(sc)
    cbar.set_label(label="ang_vel [rad/s]", fontsize="small")
    # sc.set_clim(350, 400)
    ax.tick_params(labelrotation=0, labelsize="medium")
    ax_scale = 1.
    ax.set_xlim(-L * ax_scale, L * ax_scale)
    ax.set_ylim(-L * ax_scale - 0.1, L * ax_scale - 0.1)
    # make axes square: a circle shows as a circle
    ax.set_aspect(1 / ax.get_data_ratio())
    ax.arrow(0, 0, df2["dx (m)"].iloc[-1], df2["dy (m)"].iloc[-1],
             color="dimgray", ls=":", lw=2.5, width=.0, head_width=0, zorder=-1
             )
    ax.text(0, 0.15, s="size and colour of pendulum bob\nbased on pd column\nfor angular velocity",
            ha='center', va='center')

    # plt.show()

    dpi = 100
    ax_scale = 1.1
    figsize = (3, 3)
    fontsize = "small"

    # set up figure to pass onto `pandas_alive`
    # NOTE: by using Figure (capital F) instead of figure() `FuncAnimation` seems to run twice as fast!
    # fig1, ax1 = plt.subplots()
    fig1 = plt.Figure()
    ax1 = fig1.add_subplot()
    fig1.set_size_inches(figsize)
    ax1.set_title("Simple pendulum animation, L=" + str(L) + "m", fontsize="medium")
    ax1.set_xlabel("Time (s)", color='dimgray', fontsize=fontsize)
    ax1.set_ylabel("Amplitudes", color='dimgray', fontsize=fontsize)
    ax1.tick_params(labelsize=fontsize)

    # pandas_alive
    line_chart = df.plot_animated(filename="pend-line.gif", kind='line', period_label={'x': 0.05, 'y': 0.9},
                                  steps_per_period=1, interpolate_period=False, period_length=50,
                                  period_fmt='Time:{x:10.2f}',
                                  enable_progress_bar=True, fixed_max=True, dpi=100, fig=fig1
                                  )
    plt.close()

    # Video('examples/pend-line.mp4', html_attributes="controls muted autoplay")

    # set up and generate animated scatter plot
    #

    # set up figure to pass onto `pandas_alive`
    # NOTE: by using Figure (capital F) instead of figure() `FuncAnimation` seems to run twice as fast!
    fig1sc = plt.Figure()
    ax1sc = fig1sc.add_subplot()
    fig1sc.set_size_inches(figsize)
    ax1sc.set_title("Simple pendulum animation, L=" + str(L) + "m", fontsize="medium")
    ax1sc.set_xlabel("Time (s)", color='dimgray', fontsize=fontsize)
    ax1sc.set_ylabel("Amplitudes", color='dimgray', fontsize=fontsize)
    ax1sc.tick_params(labelsize=fontsize)

    # pandas_alive
    scatter_chart = df.plot_animated(filename="pend-scatter.gif", kind='scatter', period_label={'x': 0.05, 'y': 0.9},
                                     steps_per_period=1, interpolate_period=False, period_length=50,
                                     period_fmt='Time:{x:10.2f}',
                                     enable_progress_bar=True, fixed_max=True, dpi=100, fig=fig1sc, size="ang_vel"
                                     )
    plt.close()

    print("Points size follows one of the pd columns: ang_vel")
    # Video('./pend-scatter.gif', html_attributes="controls muted autoplay")

    # set up and generate animated bar race chart
    #
    # set up figure to pass onto `pandas_alive`
    # NOTE: by using Figure (capital F) instead of figure() `FuncAnimation` seems to run twice as fast!
    fig2 = plt.Figure()
    ax2 = fig2.add_subplot()
    fig2.set_size_inches(figsize)
    ax2.set_title("Simple pendulum animation, L=" + str(L) + "m", fontsize="medium")
    ax2.set_xlabel("Amplitudes", color='dimgray', fontsize=fontsize)
    ax2.set_ylabel("", color='dimgray', fontsize="x-small")
    ax2.tick_params(labelsize=fontsize)

    # pandas_alive
    race_chart = df.plot_animated(filename="pend-race.gif", kind='race', period_label={'x': 0.05, 'y': 0.9},
                                  steps_per_period=1, interpolate_period=False, period_length=50,
                                  period_fmt='Time:{x:10.2f}',
                                  enable_progress_bar=True, fixed_max=False, dpi=100, fig=fig2
                                  )
    plt.close()

    # set up and generate bubble animated plot
    #

    # set up figure to pass onto `pandas_alive`
    # NOTE: by using Figure (capital F) instead of figure() `FuncAnimation` seems to run twice as fast!
    fig3 = plt.Figure()
    ax3 = fig3.add_subplot()
    fig3.set_size_inches(figsize)
    ax3.set_title("Simple pendulum animation, L=" + str(L) + "m", fontsize="medium")
    ax3.set_xlabel("Hor Displacement (m)", color='dimgray', fontsize=fontsize)
    ax3.set_ylabel("Ver Displacement (m)", color='dimgray', fontsize=fontsize)
    # limits & ratio below get the graph square
    ax3.set_xlim(-L * ax_scale, L * ax_scale)
    ax3.set_ylim(-L * ax_scale - 0.1, L * ax_scale - 0.1)
    ratio = 1.  # this is visual ratio of axes
    ax3.set_aspect(ratio / ax3.get_data_ratio())

    ax3.arrow(0, 0, df2["dx (m)"].iloc[-1], df2["dy (m)"].iloc[-1],
              color="dimgray", ls=":", lw=1, width=.0, head_width=0, zorder=-1)

    # pandas_alive
    bubble_chart = df2.plot_animated(
        kind="bubble", filename="pend-bubble.gif",
        x_data_label="dx (m)", y_data_label="dy (m)",
        size_data_label="size", color_data_label="ang_vel", cmap="jet",
        period_label={'x': 0.05, 'y': 0.9}, vmin=None, vmax=None,
        steps_per_period=1, interpolate_period=False, period_length=50, period_fmt='Time:{x:10.2f}s',
        enable_progress_bar=True, fixed_max=False, dpi=dpi, fig=fig3
    )
    plt.close()

    print("Bubble size & colour animates with pd data column for ang_vel.")

    # Combined plots
    #
    fontsize = "x-small"
    # Otherwise titles overlap and subplots_adjust does nothing
    from matplotlib import rcParams
    rcParams.update({"figure.autolayout": False})

    figs = plt.Figure(figsize=(9, 4), dpi=100)
    figs.subplots_adjust(wspace=0.1)
    gs = figs.add_gridspec(2, 2)

    ax1 = figs.add_subplot(gs[0, 0])
    ax1.set_xlabel("Time(s)", color='dimgray', fontsize=fontsize)
    ax1.set_ylabel("Amplitudes", color='dimgray', fontsize=fontsize)
    ax1.tick_params(labelsize=fontsize)

    ax2 = figs.add_subplot(gs[1, 0])
    ax2.set_xlabel("Amplitudes", color='dimgray', fontsize=fontsize)
    ax2.set_ylabel("", color='dimgray', fontsize=fontsize)
    ax2.tick_params(labelsize=fontsize)

    ax3 = figs.add_subplot(gs[:, 1])
    ax3.set_xlabel("Hor Displacement (m)", color='dimgray', fontsize=fontsize)
    ax3.set_ylabel("Ver Displacement (m)", color='dimgray', fontsize=fontsize)
    ax3.tick_params(labelsize=fontsize)
    # limits & ratio below get the graph square
    ax3.set_xlim(-L * ax_scale, L * ax_scale)
    ax3.set_ylim(-L * ax_scale - 0.1, L * ax_scale - 0.1)
    ratio = 1.  # this is visual ratio of axes
    ax3.set_aspect(ratio / ax3.get_data_ratio())

    line_chart.ax = ax1
    race_chart.ax = ax2
    bubble_chart.ax = ax3

    plots = [line_chart, race_chart, bubble_chart]
    # pandas_alive combined using custom figure
    pandas_alive.animate_multiple_plots(
        filename='pend-combined.gif', plots=plots, custom_fig=figs, dpi=100, enable_progress_bar=True,
        adjust_subplot_left=0.2, adjust_subplot_right=None,
        title="Simple pendulum animations, L=" + str(L) + "m", title_fontsize="medium"
    )
    plt.close()

最後如果你想完成中文動態圖表的製作,加入中文顯示代碼即可。

# 中文顯示
plt.rcParams['font.sans-serif'] = ['SimHei']  # Windows
plt.rcParams['font.sans-serif'] = ['Hiragino Sans GB'] # Mac
plt.rcParams['axes.unicode_minus'] = False

# 讀取數據
df_result = pd.read_csv('data/yuhuanshui.csv', index_col=0, parse_dates=[0])
# 生成圖表
animated_line_chart = df_result.diff().fillna(0).plot_animated(kind='line', period_label=False, add_legend=False)
animated_bar_chart = df_result.plot_animated(n_visible=10)
pandas_alive.animate_multiple_plots('examples/yuhuanshui.gif',
                                    [animated_bar_chart, animated_line_chart], enable_progress_bar=True,
                                    title='我是餘歡水演職人員熱度排行')

還是使用演員的百度指數數據。

CSV文件及相關代碼連結:https://pan.baidu.com/s/1ugxtHNF7wpvZB2meKXhQpQ  密碼:r8qx

相關焦點

  • 看完這篇文章,我才知道 Python 製作動態圖表的正確方式
    關於動態圖表,相信大家都或多或少的接觸過一些,如果是代碼水平比較不錯的,可以選擇 Matplotlib,當然也可以使用 pyecharts 的相關功能,不過這些工具都專注於圖表的製作,也就是對於圖表的數據,你是需要自行轉換的。而今天介紹的這個可視化圖庫,完美的結合了 Pandas 數據格式,又輔以 Matplotlib 的強大功能,使得我們製作動圖變得容易的多了。
  • Python製作動態圖表看全球疫情趨勢
    昨天剛分享了一篇文章,關於製作動態圖的,那是用現成的網站工具,可以直接生成動態圖,大家還沒看過的可以點擊去看看:火爆全網的動態曲線圖是怎麼做的
  • Python 製作動態圖表,看全球疫情變化趨勢
    前言最近國內疫情已經有所好轉,但是國外的情況不容樂觀,那麼怎樣用Python去製作動態圖表來看全球疫情變化趨勢呢?比如下面的國內外疫情發展趨勢:可以看到一共採集到了7584條數據,由於髒數據比較多,所以這一部分的工作量是比較大的,因此我們不在這裡使用太多篇幅去講如何一步一步提取出我們想要的數據,會單獨寫一篇數據處理過程的文章,不過還是來看看經歷了哪些過程與代碼吧!
  • 用Python自動化操作PPT,看完這篇文章就夠了!
    ,這裡提示已經安裝2.2 win32com複製ppt模板有時候我們需要對ppt的模板進行複製,然後再添加相應內容,由於python-pptx對複製模板也沒有很好的支持(我沒找到~憂傷),所以我們用win32com對模板頁進行複製,然後再用python-pptx增加ppt內容。
  • 看完這篇文章,你不可能不懂「動態代理」
    這件事情確實很難,我們需要一點點地來完成這件事情,跟上我的思路,保證能讓你徹底理解動態代理!」陀螺自信地對招財說。動態代理的誕生「首先回憶一下靜態代理中你編寫的日誌代理。」說著,陀螺給出了代碼。「這個代碼你應該已經非常熟悉了吧。」陀螺問招財。
  • 讓數據「動」起來:python動態圖表製作
    選自TowardsDataScience作者:Costas Andreou機器之心編譯參與:Jamin、張倩在讀技術博客的過程中,我們會發現那些能夠把知識、成果講透的博主很多都會做動態圖表這篇文章就介紹了 Python 中一種簡單的動態圖表製作方法。數據暴增的年代,數據科學家、分析師在被要求對數據有更深的理解與分析的同時,還需要將結果有效地傳遞給他人。
  • python正則表達式,看完這篇文章就夠了...
    作者:王翔丨公眾號:清風Python正則表達式這東西,你說它簡單它也簡單,你說它難吧,確實不容易。為什麼?這東西就是死記硬背的。網上關於python正則的帖子很多,我再去寫壓力比較大,儘可能的總結詳細一些吧!正則表達式,是一個特殊的字符序列,又稱規則表達式(英語:Regular Expression,在代碼中常簡寫為regex、regexp 或RE),本質而言是一種小型的,高度專業化的程式語言。Python 自1.5版本起增加了re 模塊,re 模塊使Python語言擁有全部的正則表達式功能。
  • python實現酷炫實用的動態可視化圖表,還原漢斯·羅斯林的經典演示數據視圖
    後面了解到他老人家,還成立了基金會Gapminder開發了Trendalyzer軟體,他演講中的數據可視化圖表就是用這個軟體製作,同時該軟體還向公眾免費開放。任何人都可以使用該軟體將統計數據轉換成動態、交互的和有趣的圖表。實現通過增進對可以自由訪問的公共統計數據的使用和理解,以促進以事實為基礎的世界觀察。
  • 看完這篇文章,你就知道了
    看完這篇文章,你就都知道了。https://arxiv.org/pdf/1904.13310.pdfSurvey of Dropout Methods for Deep Neural Networks深度神經網絡是當代人工智慧和信號處理領域的一個重要課題。它們的大量參數使得它們特別容易過度擬合,在實踐中需要正則化方法。
  • Python-Matplotlib:動態條形圖
    抱著學習的目的,本期推文使用python可視化包matplotlib進行Bar Chart Race的繪製,這也是繼上兩篇動態圖表教程後最後一篇matplotlib動態圖表教程(畢竟原理都差不多,最多就是數據處理方法的不同,後面遇到好的動態作品,還是會推出matplotlib教程的)
  • Python正則表達式,看完這篇文章就夠了!
    https://www.runoob.com/regexp/regexp-tutorial.htmlhttps://tool.oschina.net/regex/https://goregex.cn/https://docs.python.org
  • 用Python讓圖表動起來,居然這麼簡單?!
    編譯:佑銘參考:https://towardsdatascience.com/how-to-create-animated-graphs-in-python-bb619cc2dec1用Matplotlib和Seaborn這類Python庫可以畫出很好看的圖,但是這些圖只是靜態的,難以動態且美觀地呈現數值變化。
  • 徹底搞懂python字符編碼,看這篇就夠了!
    不論你是有著多年經驗的 Python 老司機還是剛入門 Python 不久,你一定遇到過UnicodeEncodeError、UnicodeDecodeError 錯誤,每當遇到錯誤我們就拿著 encode、decode 函數翻來覆去的轉換,有時試著試著問題就解決了,有時候怎麼試都沒轍,只有借用 Google,百度各種 大神幫忙,但似乎很少去關心問題的本質是什麼,下次遇到類似的問題重蹈覆轍,那麼你有沒有想過一次性徹底把
  • 看完這20個細節,你會愛上小米的MIUI系統(續)
    大約一周前,MIUI內部的小夥伴,出於方便大家輕鬆、愉快地了解MIUI的目的,寫了一篇《看完這20個細節,你會愛上小米的MIUI系統》的文章,沒想到這個文章出來
  • Excel實現動態圖表,附教程
    GDP動態圖表,2分鐘看完中國崛起!動態條形圖展現了中國GDP排名不斷攀升、不斷超越,最終穩居世界第二的位置,加上StarSky的配樂,很燃,振奮人心!查了一下,是通過D3.js實現的,並且在GitHub上公開了原始碼,有興趣的朋友可以去看一下:https://github.com/Jannchie/Historical-ranking-data-visualization-based-on-d3.js  D3.js能實現,我就想Excel作為數據分析師鼻祖級的軟體,肯定也有辦法實現,實際上就是一個條形圖,根據數據變化,圖表隨之而動。
  • 看完這篇文章,你打開了瀏覽器……
    網際網路是人類最偉大發明之一,徹底地改變了我們的生活,但我們似乎已經忘記了自己的「本心」,很少再去瀏覽什麼特定的網站。只是偶爾夜深人靜時,「鐵汁給個網站,好人一生平安」的評論和彈幕仍然昭示著你我心中最純真的渴望。
  • 用Python開發爬蟲,看這篇文章就夠了
    __dict__)print(response.text)關於requests我就不多做介紹了,因為它有中文文檔,雖然比官方落後幾個小版本號,不過無傷大雅,大家可以放心參閱。首先先來安裝它:pip install beautifulsoup4這次就用我簡書主頁作為例子,爬取一下我簡書的文章列表。首先先用requests獲取到網頁內容。
  • Excel動態圖表教程
    在Excel中製作動態圖表的方法有很多,今天我們要介紹的是控制項+函數法
  • 聽說你不會用mac電腦裝Python?看了這篇文章,秒懂!
    有很多學員,來諮詢老師mac下的環境安裝,於是小簡老師就出了這篇文章。
  • 免費分享一波Excel數據圖表模板,包含統計圖表、複合圖表、組合圖表、動態圖表等
    大家好,我是老幫,今天分享一大波Excel圖表,有需要的自行下載,先來幾張圖,看看效果