Python Plotly多个直方图带平均线

6
我需要在Plotly中绘制两个直方图,每个直方图都有一条绘制在平均值处的线,并显示平均值标签。目前我的代码可以绘制两个直方图,但我不知道如何添加平均线和标签。有什么建议吗?
    import numpy as np
    import random
    from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
    import plotly.graph_objs as go

    init_notebook_mode() # run at the start of every ipython notebook

    a = np.random.normal(1500, 100, 1000)
    b = np.random.normal(1500, 150, 1000)

    trace1 = go.Histogram(
        x=a,
        opacity=0.75,
        histnorm='probability',
        name='> 180 t/h'
    )
    trace2 = go.Histogram(
        x=b,
        opacity=0.75,
        histnorm='probability',
        name='< 160 t/h',
        yaxis='y2'
    )

    data = [trace1, trace2]

    layout = go.Layout(
        title='title',
        barmode='overlay',
        xaxis=dict(
        title=''
        ),
        yaxis=dict(
            title='Normalized Frequency < 160 t/h'
        ),
        yaxis2=dict(
            title='Normalized Frequency > 180 t/h',
            anchor='free',
            overlaying='y',
            side='right',
            position=1
        )        
    ) 

    fig = go.Figure(data=data, layout=layout)
    iplot(fig)

1
如果您能提供数据样本以创建一个 mcve,那就太好了。 - Julien Marrec
我已经添加了一个随机正态分布来生成一些虚拟数据。为了生成一个合适的直方图需要大量的数据,因此添加原始数据源是不切实际的。 - ceds
你会使用Cufflinks吗? - Julien Marrec
是的,我会选择列并使用.mean()函数。 - ceds
让我们在聊天中继续这个讨论。点击此处进入聊天室 - Julien Marrec
显示剩余2条评论
1个回答

11

经过多个小时的尝试,我觉得我大致得到了一个可行的东西:

a = np.random.normal(1200, 100, 1000)
b = np.random.normal(1500, 150, 1000)
df = pd.DataFrame(np.transpose([a,b]), columns=['a','b'])
a = df.a
b = df.b

trace1 = go.Histogram(
    x=df.a,
    opacity=0.75,
    histnorm='probability',
    name='> 180 t/h'
)
trace2 = go.Histogram(
    x=df.b,
    opacity=0.75,
    histnorm='probability',
    name='< 160 t/h',
    yaxis='y2'
)

# Create traces


data = [trace1, trace2]

layout = go.Layout(
    title='item',
    barmode='overlay',
    xaxis=dict(
    title=''
    ),
    yaxis=dict(
        title='Normalized Frequency < 160 t/h'
    ),
    yaxis2=dict(
        title='Normalized Frequency > 180 t/h',
        anchor='free',
        overlaying='y',
        side='right',
        position=1
    ),

    # Mean lines
    shapes= [{'line': {'color': '#0099FF', 'dash': 'solid', 'width': 1},
    'type': 'line',
    'x0': df.a.mean(),
    'x1': df.a.mean(),
    'xref': 'x',
    'y0': -0.1,
    'y1': 1,
    'yref': 'paper'},
   {'line': {'color': '#FDAB5A', 'dash': 'solid', 'width': 1},
    'type': 'line',
    'x0': df.b.mean(),
    'x1': df.b.mean(),
    'xref': 'x',
    'y0': -0.1,
    'y1': 1,
    'yref': 'paper'}],

    # Annotations
    annotations=[
        dict(
            x=df.a.mean(),
            y=1,
            xref='x',
            yref='paper',
            text="Mean a = {:,.0f}".format(df.a.mean()),
            showarrow=True,
            arrowhead=7,
            ax=1,
            ay=1,
            axref='paper',
            ayref='paper'
        ),
        dict(
            x=df.b.mean(),
            y=0.95,
            xref='x',
            yref='paper',
            text="Mean b = {:,.0f}".format(df.b.mean()),
            showarrow=True,
            arrowhead=7,
            ax=1,
            ay=1,
            axref='paper',
            ayref='paper'
        )
    ]

) 
fig = go.Figure(data=data, layout=layout)
py.iplot(fig)

结果图


最初我尝试使用 cufflinks 来实现它。这个方法可以正常工作:

import cufflinks as cf

df.iplot(kind='histogram', histnorm='probability', barmode='overlay',
     vline=[dict(x=df.a.mean(),color='#5283AD'), dict(x=df.b.mean(),color='#FDAB5A')])

在此输入图片描述

但是,如果您尝试添加注释,它将会删除垂直线。

最终,我使用了asFigure方法返回具有垂直线但没有布局的plotdict。然后,我提取了shapes部分,手动创建了上面的解决方案。

# Return a dict
plotdict = df.iplot(kind='histogram', histnorm='probability', barmode='overlay',
     vline=[dict(x=df.a.mean(),color='#5283AD'), dict(x=df.b.mean(),color='#FDAB5A')],
     asFigure=True)

https://plot.ly/~jmarrec/326/


谢谢Julien!你真是太有帮助了。 - ceds

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接