7000 字 23 张图,Pandas 一键生成炫酷的动态交互式图表

这是「进击的Coder」的第 518 篇技术分享

作者:俊欣

来源:关于数据分析与可视化

阅读本文大概需要 13 分钟。

今天小编来演示一下如何用pandas一行代码来绘制可以动态交互的图表,并且将绘制的图表组合到一起,组成可视化大屏,本次小编将要绘制的图表有

  • 折线图

  • 散点图

  • 直方图

  • 柱状图

  • 饼图

  • 面积图

  • 地图

  • 组合图

准备工作

我们先导入需要用到的库,并做相应的设置

import pandas as pd
import pandas_bokeh
pandas_bokeh.output_notebook()

因为小编是在jupyter nobteook上面操作的,这边就用到了output_notebook()的设置

折线图

我们先来画一张简单的折线图,当中随机生成一批数据

import numpy as np

np.random.seed(55)
df = pd.DataFrame({"宁德时代": np.random.randn(100)+0.2, 
                   "贵州茅台": np.random.randn(100)+0.17}, 
                   index=pd.date_range('1/1/2021', periods=100))
df = df.cumsum()
df = df + 50
df.plot_bokeh(kind="line")

output

3b3dd6f5ca7529fd3716237c419da141.gif

绘制出来的图表可以任意的缩放以及拖拽,我们也可以点击右边的“保存”按钮来实现对图表的下载保存,以至于图表的类型只需要对参数kind加以设定,我们将上面的代码优化一下

df.plot_bokeh.line(
    figsize=(800, 450),
    title="宁德时代 vs 贵州茅台",
    xlabel="日期",
    ylabel="股票价格 [$]",
    yticks=[0, 100, 200, 300, 400],
    ylim=(0, 100),
    xlim=("2021-01-01", "2021-04-01"),
    colormap=["red", "blue"],
    plot_data_points=True,
    plot_data_points_size=10,
    marker="asterisk")

output

0037827426c25089ce23184ddfa6895e.gif

我们对 X 轴以及 Y 轴坐标做了范围的限定,并且加上了标注,效果看起来也更加的美观一些。和pyecharts类似,我们也可以在图标的底部添加一个时间轴,拖动时间轴来展示数据

ts = pd.Series(np.random.randn(100), index=pd.date_range('1/1/2021', periods=100))
df = pd.DataFrame(np.random.randn(100, 4), index=ts.index, columns=list('ABCD'))
df = df.cumsum()

df.plot_bokeh(rangetool=True)

output

c79f21bce376c0026f21e47287e1a587.gif

当然我们也可以对折线加以修改,就可以变成另外一种样子,主要修改的就是参数marker

x = np.arange(-5, 5, 0.1)
y2 = x**2
y3 = x**3
df = pd.DataFrame({"x": x, "Type 1": y2, "Type 2": y3})
df.plot_bokeh.point(
    x="x",
    xticks=range(-5, 5),
    size=5,
    colormap=["#009933", "#ff3399"],
    title="折线图 (Type 1 vs. Type 2)",
    marker="x")

output

661a157cb10ffefa21b89d01445c893d.png

散点图

接下来我们来看散点图,步骤与上述的折线图相类似

df = pd.read_csv("iris.csv")
p_scatter = df.plot_bokeh.scatter(
    x="petal length(cm)",
    y="sepal width(cm)",
    category="species",
    title="Iris数据集可视化",
    show_figure=True,
)

output

f24015fe6c898ccde7f9b0705997d54a.gif

我们在读取了iris数据集之后,将x参数和y参数上填上我们所要绘制的两列,而title参数则是设置图表的标题

我们也可以通过当中size这个参数来控制散点的大小,例如

df.loc[13, "sepal length(cm)"] = 15
df.loc[15, "sepal length(cm)"] = 17
df.loc[20, "sepal length(cm)"] = 30
df.loc[40, "sepal length(cm)"] = 20

p_scatter = df.plot_bokeh.scatter(
    x="petal length(cm)",
    y="sepal width(cm)",
    category="species",
    title="Iris数据集可视化",
    show_figure=True,
    size="sepal length(cm)"
)

output

53892e9f5161b1066663aba4f8e1acca.gif

柱状图

下面我们来看一下直方图的绘制

data = {
    'fruits':
    ['苹果', '梨', '草莓', '西瓜', '葡萄', '香蕉'],
    '2015': [2, 1, 4, 3, 2, 4],
    '2016': [5, 3, 3, 2, 4, 6],
    '2017': [3, 2, 4, 4, 5, 3]
}
df = pd.DataFrame(data).set_index("fruits")

p_bar = df.plot_bokeh.bar(
    ylabel="每斤的的价格 [¥]", 
    title="水果每年的价格", 
    alpha=0.6)

output

f0568d6f2043410c65685d4a264b55cc.gif

我们看到上面的直方图是按照不同的年份分开来的,我们也可以堆叠起来,通过stacked这个参数来实现

p_stacked_bar = df.plot_bokeh.bar(
    ylabel="每斤的的价格 [¥]",
    title="水果每年的价格",
    stacked=True,
    alpha=0.6)

output

fa85b0372f0ed2a6e7628fab2f8b068f.gif

直方图

绘制直方图的方式也是类似的

p_hist = df_hist.plot_bokeh.hist(
    y=["a", "b"],
    bins=np.arange(-5, 5, 0.5),
    normed=100,
    vertical_xlabel=True,
    ylabel="Share[%]",
    title="正则分布直方图",
    show_average=True,
    xlim=(-4, 6),
    ylim=(0, 30),
    show_figure=True)

output

de135d6fa49250b9e388673f3e1a67f0.png

小编个人觉得直方图有点丑,不知道大家是不是有类似的体验

面积图
df.plot_bokeh.area(
    x="Year",
    stacked=True,
    legend="top_left",
    colormap=["yellow", "orange", "black", "grey", "blue", "green"],
    title="全球不同能源的消耗量",
    ylabel="不同能源的消耗(吨)",
    ylim=(0, 16000))

output

b28c9b8382ffcb6c90da60609f2decc0.gif

我们看到石油的消耗量一直都在不断的提升,另外有一个normed参数来帮助我们更好的观察数据的走势

df.plot_bokeh.area(
    x="Year",
    stacked=True,
    normed = 100,
    legend="bottom_left",
    colormap=["yellow", "orange", "black", "grey", "blue", "green"],
    title="全球不同能源的消耗量",
    ylabel="不同能源的消耗(吨)")

output

2061ac935f340b729b6ab29795b938e2.gif

饼图
df_pie.plot_bokeh.pie(
    x="Type",
    y="2017",
    colormap=["blue", "red", "yellow", "green", "purple", "orange", "grey"],
    title="饼图",
    )

output

88c98cebbd006f5c39ef9889338bb873.gif

上面的代码只是引用了表格当中的一列,当然我们也可以不做指定,引用表格当中的每一列数据

df_pie.plot_bokeh.pie(
    x="Type",
    colormap=["blue", "red", "yellow", "green", "purple", "orange", "grey"],
    title="多重饼图",
    line_color="black")

output

fe3738b79865284ce218c735a52a08bc.gif

地图

同时我们来看一下地图的绘制,下面的图表是基于全球各大城市的人口密度分布来绘制的

df_mapped.plot_bokeh.map(
    x="longitude",
    y="latitude",
    hovertool_string="""<h2> @{name} </h2> 
    
                        <h3> Population: @{pop_max} </h3>""",
    tile_provider="STAMEN_TERRAIN_RETINA",
    size="population", 
    figsize=(900, 600),
    title="全球特大城市分布")

output

1b51ddcd53c20d56ad8d7eb4e06c764b.gif

从图中可以看出,亚洲的日本主要是集中在东京这块,而像在国内的话,有大家熟知的北上广深。上面的代码有两个参数xy分别对应的是经纬度,

import geopandas as gpd
import pandas_bokeh
pandas_bokeh.output_file("Interactive Plot.html")

df_states = gpd.read_file("states.geojson")
print(df_states.head())

下面这张图是美国各个州 2017 年的的人口总量,我们给上面的每一个州配上不同的颜色

df_states.plot_bokeh(
    figsize=(900, 600),
    category="POPESTIMATE2017",
    simplify_shapes=5000,
    colormap="Inferno",
    colormap_uselog=True,
    colorbar_tick_format="0.0a")

output

7886101fa4ef174c3d9eed51b845667d.gif

当然我们也可以在地图上面添加一个时间轴,让图表随着时间的流逝而变化

for i in range(8):
    df_states["Delta_Population_201%d"%i] = ((df_states["POPESTIMATE201%d"%i] / df_states["POPESTIMATE2010"]) -1 ) * 100
    
slider_columns = ["Delta_Population_201%d"%i for i in range(8)]
slider_range = range(2010, 2018)
df_states.plot_bokeh(
    figsize=(900, 600),
    simplify_shapes=5000,
    slider=slider_columns,
    slider_range=slider_range,
    slider_name="Year",
    colormap="Inferno",
    hovertool_columns=["STATE_NAME"] + slider_columns,
    title="Change of Population [%]")

output

3fd1606489203474813f09a8c59cb822.gif

同时我们也可以在地图上面添加一个下拉框,通过点选来筛选数据的展示

df_states["STATE_NAME_SMALL"] = df_states["STATE_NAME"].str.lower()

df_states.plot_bokeh(
    figsize=(900, 600),
    simplify_shapes=5000,
    dropdown=["POPESTIMATE2010", "POPESTIMATE2017"],
    colormap="Viridis",
    hovertool_string="""
                        <img
                        src="https://www.states101.com/img/flags/gif/small/@STATE_NAME_SMALL.gif" 
                        height="42" alt="@imgs" width="42"
                        style="float: left; margin: 0px 15px 15px 0px;"
                        border="2"></img>
                
                        <h2>  @STATE_NAME </h2>
                        <h3> 2010: @POPESTIMATE2010 </h3>
                        <h3> 2017: @POPESTIMATE2017 </h3>""",
    tile_provider_url=r"http://c.tile.stamen.com/watercolor/{Z}/{X}/{Y}.jpg",
    tile_attribution='Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.'
    )

output

6b5bda4795e277d88ed2ac35f70d8ff3.gif

最后我们可以通过区域的筛选来进行数据的呈现,通过`category`这个参数来实现

df_states.plot_bokeh(
    figsize=(900, 600),
    simplify_shapes=5000,
    category="REGION",
    show_colorbar=False,
    colormap=["blue", "yellow", "green", "red"],
    hovertool_columns=["STATE_NAME", "REGION"],
    tile_provider="STAMEN_TERRAIN_RETINA")

97a882ea6cffc809a8f0a74feb386f7e.gif

多图组合

pandas_bokeh模块也能够实现多张图表的组合,例如上面 人口密度的图表就可以和美国各大洲的人口总量的图表进行组合

#绘制出大致的轮廓图
figure = df_states.plot_bokeh(
    figsize=(800, 450),
    simplify_shapes=10000,
    show_figure=False,
    xlim=[-170, -80],
    ylim=[10, 70],
    category="REGION",
    colormap="Dark2",
    legend="States",
    show_colorbar=False,
)

#绘制人口的密度图
df_cities.plot_bokeh(
    figure=figure,         # <== pass figure here!
    category="pop_max",
    colormap="Viridis",
    colormap_uselog=True,
    size="size",
    hovertool_string="""<h1>@name</h1>
                        <h3>Population: @pop_max </h3>""",
    marker="inverted_triangle",
    legend="Cities",
)

57635c30afc2068b30b7ca579b72c4da.gif

上面的代码我们主要是用到了pandas_bokeh.plot_grid这个方法来将多个图结合起来,再来看几个简单的案例

df = pd.read_csv("iris.csv")

from bokeh.models.widgets import DataTable, TableColumn
from bokeh.models import ColumnDataSource

data_table = DataTable(
    columns=[TableColumn(field=Ci, title=Ci) for Ci in df.columns],
    source=ColumnDataSource(df),
    height=300,
)

# 创建散点图:
p_scatter = df.plot_bokeh.scatter(
    x="petal length(cm)",
    y="sepal width(cm)",
    category="species",
    title="Iris数据可视化",
    show_figure=False,
)

# Combine Table and Scatterplot via grid layout:
pandas_bokeh.plot_grid([[data_table, p_scatter]], plot_width=400, plot_height=350)

output

0026e02272609e3586ca42674186d8b3.png

我们也可以借此多绘制几个直方图,然后组合起来

#重置表格的行索引:
df.reset_index(inplace=True)

#创建水平方向的直方图:
p_hbar = df.plot_bokeh(
    kind="barh",
    x="fruits",
    xlabel="Price per Unit [€]",
    title="Fruit prices per Year",
    alpha=0.6,
    legend = "bottom_right",
    show_figure=False)

#创建堆叠式的柱状图:
p_stacked_hbar = df.plot_bokeh.barh(
    x="fruits",
    stacked=True,
    xlabel="Price per Unit [€]",
    title="Fruit prices per Year",
    alpha=0.6,
    legend = "bottom_right",
    show_figure=False)

#Plot all barplot examples in a grid:
pandas_bokeh.plot_grid([[p_bar, p_stacked_bar],
                        [p_hbar, p_stacked_hbar]], 
                       plot_width=450)

output

334d71da671bda6f971458925d5dc9ae.png

f521b93a7130c414332ec156dd461634.png

End

「进击的Coder」专属学习群已正式成立,搜索「CQCcqc4」添加崔庆才的个人微信或者扫描下方二维码拉您入群交流学习。

6f0960ccfd723b0521e891e7f022162e.png

看完记得关注@进击的Coder

及时收看更多好文

↓↓↓

崔庆才的「进击的Coder」知识星球已正式成立,感兴趣的可以查看《我创办了一个知识星球》了解更多内容,欢迎您的加入:

35dd9660ce6520f3c736e14d453ea31c.png

好文和朋友一起看~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值