可视化神器Plotly玩转多子图绘制

Posted 尤尔小屋的猫

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可视化神器Plotly玩转多子图绘制相关的知识,希望对你有一定的参考价值。

公众号:尤而小屋
作者:Peter
编辑:Peter

可视化神器Plotly玩转多子图绘制

大家好,我是Peter~

很长时间没有Plotly绘图的文章,之前已经介绍如何绘制柱状图、饼图、小提琴图、桑基图等,今天给大家带来的是一篇关于Plotly如何绘制多子图的文章,在一个画布中如何实现多种类型图形的绘制。

Plotly连载文章

多子图绘制

首先看看实际的效果:

Plotly中有两种方式来绘制子图,基于plotly_express和 graph_objects。

但是plotly_express只支持 facet_plots(切面图) 和 marginal distribution subplots(边际分布子图),只有graph_objects是基于make_subplots模块才能够绘制真正意义上的多子图。下面通过实际例子来讲解。

import pandas as pd
import numpy as np

import plotly_express as px
import plotly.graph_objects as go

# 绘制子图
from plotly.subplots import make_subplots

最重要的是要导入make_subplots模块。

基于plotly_express

plotly_express绘制“子图”是通过参数marginal_xmarginal_y 来实现的,表示在边际上图形的类型,可以是"histogram", “rug”, “box”, or “violin”。

基于facet_plots

切面图是由具有相同轴集的多个子图组成的图形,其中每个子图显示数据的子集,也称之为:trellis(网格) plots or small multiples。直接上官方英文,感觉更合适,暂时找不到比较恰当的中文来翻译。

不同图形切面展示

先导入内置的消费数据集:

1、基于散点图的切面图形

fig = px.scatter(tips,  #  数据
                 x="total_bill", # xy轴 
                 y="tip", 
                 color="smoker", # 颜色
                 facet_col="day"  # 列方向切面字段
                )
fig.show()

2、基于柱状图的切面展示

# 2、柱状图切面

fig = px.bar(tips, 
             x="size", 
             y="total_bill", 
             color="day", 
             facet_row="smoker"  # 行方向切面字段:是否抽烟
            )
fig.show()

控制子图个数

3、wrapping column Facets:控制显示元素个数的切面图

当我们指定的某个切面的字段的取值有很多种不同的情况,我们可以通过facet_col_wrap参数来控制每行最多显示的图形个数,wrap可以理解成:被限制的意思,就是每行限制显示多少。

使用内置的GDP数据集:

# 3、被限制每行图形个数的切面图

fig = px.scatter(gdp,   # 数据集
                 x='gdpPercap',  # x、y、颜色、点的大小size
                 y='lifeExp', 
                 color='continent', 
                 size='pop',
                 facet_col='continent', # 列切面字段
                 facet_col_wrap=3 # 每行最多3个图形
                )
fig.show()

上面的切面图形的col字段是洲,最多只有5个洲。下面的图形选用时间year:

fig = px.scatter(gdp,   # 数据集
                 x='gdpPercap',  # x、y、颜色、点的大小size
                 y='lifeExp', 
                 color='continent', 
                 size='pop',
                 facet_col='year', # 列切面字段
                 facet_col_wrap=3  # 每行最多3个图形
                )
fig.show()

每行最多显示4个图形:

fig = px.scatter(gdp, 
                 x='gdpPercap', 
                 y='lifeExp', 
                 color='continent', 
                 size='pop',
                 facet_col='year', 
                 facet_col_wrap=4  # 每行最多4个图形
                )
fig.show()

子图坐标轴设置

默认情况下子图的y轴是相同的:

# 独立轴的切面:默认情况是相同的y轴
# 默认下y轴的取值范围相同
fig = px.scatter(tips, 
                 x="total_bill", 
                 y="tip", 
                 color='day', 
                 facet_row="time"
                )
fig.show()

通过参数设置不共享y轴:

fig = px.scatter(tips, 
                 x="total_bill", 
                 y="tip", 
                 color='day', 
                 facet_row="time"  # 列方向上切面图
                )

# 设置不共享y轴,对应的是facet_row
fig.update_yaxes(matches=None)

fig.show()

如果是facet_col在列方向上的切面,则可以设置不共享x轴

fig = px.scatter(tips, 
                 x="total_bill", 
                 y="tip", 
                 color='day', 
                 facet_col="time"  # 列方向上切面图
                )

# 设置不共享x轴,对应的是facet_col
fig.update_xaxes(matches=None)

fig.show()

子图标题设置

fig = px.scatter(tips,
                 x="total_bill", 
                 y="tip", 
                 color="time",
                 facet_col="smoker"
                )
fig.show()

通过设置改变子图的标题:

fig = px.scatter(tips, 
                 x="total_bill", 
                 y="tip", 
                 color="time",
                 facet_col="smoker"
                )

# 增加代码:对每行标题通过=切割,取出最后的元素
fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))  

fig.show()

基于边际图Marginal

该方法主要是通过marginal_x和marginal_y来实现的。首先导入数据集:

基于不同图形边际图

1、基于散点图:

fig = px.scatter(iris,  # 数据集 
                 x="sepal_length",  # 指定xy轴
                 y="sepal_width",
                 marginal_x="rug",  # 边际图形类型:直方图
                 marginal_y="histogram"  # 轴须图
                )

fig.show()

2、基于密度热图的边际图形设置:

fig = px.density_heatmap(
    iris,  # 数据
    x="sepal_width",  # 两个轴
    y="sepal_length",  
    marginal_x="violin",  # 边际图:小提琴和箱型图
    marginal_y="box")

fig.show()

3、边际图颜色设置

fig = px.scatter(iris,
                 x="sepal_length", 
                 y="sepal_width", 
                 color="species",   # 颜色的设置同样适用于边际图
                 marginal_x="violin", 
                 marginal_y="box",
                 title="边际图颜色设置")
fig.show()

边际图和切面图连用

fig = px.scatter(
    tips, 
    x="total_bill",
    y="tip", 
    color="sex", 
    facet_col="day",  # 日期字段切面
    marginal_x="violin"  # 边际图用小提琴图
)

fig.show()

基于graph_objects

graph_objects方式其实是通过make_subplots函数来实现的。一定要先导入:

# 这种方式一定要导入的模块

from plotly.subplots import make_subplots
import plotly.graph_objects as go

基础子图

# 两个基本参数:设置行、列
fig = make_subplots(rows=1, cols=2)  # 1行2列

# 添加两个数据轨迹,构成两个图形
fig.add_trace(
    go.Scatter(x=[1, 2, 3], y=[5, 10, 15]),
    row=1, col=1  # 第一行第一列
)

fig.add_trace(
    go.Scatter(x=[20, 30, 40], y=[60, 70, 80]),
    row=1, col=2  # 第一行第二列
)

# 设置图形的宽高和标题
fig.update_layout(height=600, 
                  width=800, 
                  title_text="子图制作")
fig.show()

fig = make_subplots(rows=3, cols=1)  # 3行1列

# 添加3个数据轨迹
fig.add_trace(
    go.Scatter(x=[1, 2, 3], y=[5, 10, 15]),
    row=1, col=1  # 1*1
)

fig.add_trace(
    go.Scatter(x=[20, 30, 40], y=[60, 70, 80]),
    row=2, col=1  # 2*1
)

fig.add_trace(
    go.Scatter(x=[50, 60, 70], y=[110, 120, 130]),
    row=3, col=1  # 3*1
)

fig.update_layout(height=600, 
                  width=800, 
                  title_text="子图制作")
fig.show()

多行多列子图

多行多列的时候,我们可以指定第一个图形的位置,表示图形从哪里开始。默认左上角是第一个图形的位置。

\\fig = make_subplots(rows=2, cols=2,# 2行2列
                    start_cell="bottom-left"# 第一个图形的位置,两个选择:bottom-left', 'top-left
                   )  

# 添加4个数据轨迹
fig.add_trace(
    go.Bar(x=[1, 2, 3], y=[5, 10, 15]),
    row=1, col=1  # 1*1
)

fig.add_trace(
    go.Scatter(x=[20, 30, 40], y=[60, 70, 80]),
    row=1, col=2  # 1*2
)

fig.add_trace(
    go.Scatter(x=[50, 60, 70], y=[110, 120, 130]),
    row=2, col=1  # 2*1
)
fig.add_trace(
    go.Bar(x=[50, 60, 70], y=[110, 120, 130]),
    row=2, col=2  # 2*2
)

fig.update_layout(height=600, 
                  width=800, 
                  title_text="子图制作")
fig.show()

多子图标题设置

很多时候我们要给每个子图取名,用subplot_titles来实现

fig = make_subplots(rows=2, cols=2,
                    start_cell="bottom-left", # 'bottom-left', 'top-left
                    subplot_titles=["子图1","子图2","子图3","子图4"]  # 每个子图的名字
                   )  

# 添加4个数据轨迹
fig.add_trace(
    go.Bar(x=[1, 2, 3], y=[5, 10, 15]),
    row=1, col=1  # 1*1
)

fig.add_trace(
    go.Scatter(x=[20, 30, 40], y=[60, 70, 80]),
    row=1, col=2  # 1*2
)

fig.add_trace(
    go.Scatter(x=[50, 60, 70], y=[110, 120, 130]),
    row=2, col=1  # 2*1
)
fig.add_trace(
    go.Bar(x=[50, 60, 70], y=[110, 120, 130]),
    row=2, col=2  # 2*2
)

fig.update_layout(height=600, 
                  width=800, 
                  title_text="多行多列子图制作")
fig.show()

多子图标注Annotations

在子图中我们还可以给数据添加标注:

fig = make_subplots(rows=1, cols=2,
                    subplot_titles=["子图1","子图2"]  # 子图名字
                   )  

# 添加数据
fig.add_trace(
    go.Bar(x=[1, 2, 3], 
           y=[5, 10, 15],
           text=["文字1", "文字2", "文字3"], # 标注内容
           textposition="inside"    # 位置
          ),
    row=1, col=1  # 1*1
)

# 添加数据
fig.add_trace(
    go.Scatter(x=[1, 2, 3], 
           y=[5, 10, 15],
           mode="markers+text",  # 散点图的数据显示形式
           text=["文字4", "文字5", "文字6"],  # 标注内容
           textposition="bottom center"    # 位置
          ),
    row=1, col=2  # 1*2
)


fig.update_layout(height=600, 
                  width=800, 
                  title_text="多子图添加标注")
fig.show()

子图宽度设置

上面绘制的多子图都是大小相同的,我们可以通过参数来进行设置显示不同的大小:column_widths

fig = make_subplots(rows=1, 
                    cols=2,
                    column_widths=[0.35,0.65],  # 重点:两个子图的宽度占比
                    subplot_titles=["子图1","子图2"]  # 名字
                   )  

fig.add_trace(
    go.Bar(x=[1, 2, 3], 
           y=[5, 10, 15],
           text=["文字1", "文字2", "文字3"], # 标注内容
           textposition="inside"    # 位置
          ),
    row=1, col=1  # 1*1
)

# 添加数据
fig.add_trace(
    go.Scatter(x=[1, 2, 3], 
           y=[5, 10, 15],
           mode="markers+text",  # 散点图的数据显示形式
           text=["文字4", "文字5", "文字6"],  # 标注内容
           textposition="bottom center"    # 位置
          ),
    row=1, col=2  # 1*2
)

fig.update_layout(height=600, 
                  width=800, 
                  title_text="多子图添加标注")
fig.show()

共享x轴

共享x轴指的是针对在同列行中的多个图形共享x轴:

fig = make_subplots(rows=3, 
                    cols=1,
                    # 重点参数
                    shared_xaxes=True,  # 设置共享x轴
                    vertical_spacing=0.03,  # 图之间的间隙大小
                    subplot_titles=["子图1","子图2","子图3"]  # 名字
                   )  

fig.add_trace(
    go.Bar(x=[1, 2, 3], 
           y=[5, 10, 15],
           text=["文字1", "文字2", "文字3"], 
           textposition="inside"    # 位置
          ),
    row=1, col=1  # 1*1
)

# 添加数据
fig.add_trace(
    go.Scatter(x=[4, 5, 6], 
           y=[5, 10, 15],
           mode="markers+text",  
           text=["文字4", "文字5", "文字6"],  
           textposition="bottom center"    
          ),
    row=2, col=1  # 2*1
)


# 添加数据
fig.add_trace(
    go以上是关于可视化神器Plotly玩转多子图绘制的主要内容,如果未能解决你的问题,请参考以下文章

plotly可视化绘制多子图(subplots)

plotly可视化绘制多子图(subplots)并自定义子图

plotly可视化绘制多子图(subplots)并自定义坐标轴

plotly可视化绘制多子图(subplots)共享坐标轴

可视化神器Plotly玩转桑基图

可视化神器Plotly玩转甘特图