使用 Plotly 创建一条线作为次轴

Create a line as a secondary axis with Plotly

我有以下数据框:

         date type   value
1  2020-01-01    N    7956
2  2020-01-01    R   55709
3  2020-02-01    N    2513
4  2020-02-01    R   62325
5  2020-03-01    N    1419
6  2020-03-01    R   63745
7  2020-04-01    N     350
8  2020-04-01    R   65164
9  2020-05-01    N   11500
10 2020-05-01    R   65050
11 2020-06-01    N    7208
12 2020-06-01    R   74550
13 2020-07-01    N    2904
14 2020-07-01    R   81158
15 2020-08-01    N   11054
16 2020-08-01    R   80841
17 2020-09-01    N    7020
18 2020-09-01    R   91445
19 2020-10-01    N   25448
20 2020-10-01    R   97776
21 2020-11-01    N    8497
22 2020-11-01    R  122479
23 2020-12-01    N   11154
24 2020-12-01    R  129813

我正在使用此数据框构建下面的可视化。到目前为止我的代码是:

fig = px.bar(df_vintage, x='date', y='value', color='type',  
             labels={'type': 'value'}, category_orders={"type": ["R", "N"]})

fig.update_layout(
    title_text='Vintage Analysis',
    template='seaborn',
    margin=dict(l=50, r=50, t=50, b=50),
    legend=dict(yanchor="top", y=0.98, xanchor="left", x=0.02),
    
)

fig.update_xaxes(
    dtick="M1",
    tickformat="%b\n%Y")

fig.show()

我正在尝试插入一个线条可视化,其中包含总值的百分比变化,每个月(但不使用 Plotly 中的 make_subplots)。从百分比变化创建矢量:

pct_change = df_vintage.groupby('dates').sum().pct_change().reset_index()

我指的是我在可视化中绘制的蓝线。有任何想法吗?提前致谢。

如果您必须避免使用 make_subplots,那么您可以使用 shapes 模块画线并遍历 pct_change DataFrame 以在 i 之间画线和 i+1 元素。

不幸的是没有第二个 y-axis 所以我能做的最好的就是将 y-axis 的引用设置为“纸”,这将像 y-axis 一样画线从 0 到 1(例如 pct_change 中的值 0.5 将出现在 y-axis 的中间)。

由于您的大部分百分比变化都很低,我向百分比变化添加了一个常数值 base_pct_value(我设置为 0.5),因此它们显示在条形图上方,同时仍显示百分比变化的总体趋势(我假设这条线的趋势对你来说比它们在 y-axis 上的确切位置更重要)

import pandas as pd
import plotly.express as px
import io

df_vintage = pd.read_csv(
    io.StringIO(
        """date type   value
1  2020-01-01    N    7956
2  2020-01-01    R   55709
3  2020-02-01    N    2513
4  2020-02-01    R   62325
5  2020-03-01    N    1419
6  2020-03-01    R   63745
7  2020-04-01    N     350
8  2020-04-01    R   65164
9  2020-05-01    N   11500
10 2020-05-01    R   65050
11 2020-06-01    N    7208
12 2020-06-01    R   74550
13 2020-07-01    N    2904
14 2020-07-01    R   81158
15 2020-08-01    N   11054
16 2020-08-01    R   80841
17 2020-09-01    N    7020
18 2020-09-01    R   91445
19 2020-10-01    N   25448
20 2020-10-01    R   97776
21 2020-11-01    N    8497
22 2020-11-01    R  122479
23 2020-12-01    N   11154
24 2020-12-01    R  129813"""
    ),
    sep="\s+",
)

fig = px.bar(df_vintage, x='date', y='value', color='type',  
             labels={'type': 'value'}, category_orders={"type": ["R", "N"]})

fig.update_layout(
    title_text='Vintage Analysis',
    template='seaborn',
    margin=dict(l=50, r=50, t=50, b=50),
    legend=dict(yanchor="top", y=0.98, xanchor="left", x=0.02),
    
)

fig.update_xaxes(
    dtick="M1",
    tickformat="%b\n%Y")

pct_change = df_vintage.groupby('date').sum().pct_change().reset_index()

## however far up on the y-axis you want the pct_change values to be drawn from, some value between 0 and 1
base_pct_value = 0.5

for i in range(1,len(pct_change)-1):
    fig.add_shape(type="line",
        x0=pct_change.iloc[i]['date'], 
        y0=pct_change.iloc[i]['value'] + base_pct_value, 
        x1=pct_change.iloc[i+1]['date'], 
        y1=pct_change.iloc[i+1]['value'] + base_pct_value,
        yref="paper",
        line=dict(
            color="skyblue",
            width=10,
        )
    )
    fig.add_annotation(
        x=pct_change.iloc[i]['date'], 
        y=pct_change.iloc[i]['value'] + base_pct_value,
        text=f"{pct_change.iloc[i]['value']:.2f}",
        showarrow=False,
        yref="paper",
        yshift=10
    )
    ## last iteration of loop
    if i+1 == len(pct_change)-1:
        fig.add_annotation(
        x=pct_change.iloc[i+1]['date'], 
        y=pct_change.iloc[i+1]['value'] + base_pct_value,
        text=f"{pct_change.iloc[i+1]['value']:.2f}",
        showarrow=False,
        yref="paper",
        yshift=10
    )

fig.show()