【问题标题】:Plotly: Plot multiple figures as subplotsPlotly:将多个图形绘制为子图
【发布时间】:2018-01-16 13:13:28
【问题描述】:

这些资源展示了如何从单个 Pandas DataFrame 中获取数据,并在 Plotly 图上绘制不同的列子图。我有兴趣从单独的 DataFrames 创建图形并将它们绘制到与子图相同的图形上。这对 Plotly 可行吗?

https://plot.ly/python/subplots/

https://plot.ly/pandas/subplots/

我正在从这样的数据框创建每个图形:

import pandas as pd
import cufflinks as cf
from plotly.offline import download_plotlyjs, plot,iplot
cf.go_offline()

fig1 = df.iplot(kind='bar',barmode='stack',x='Type',
                       y=mylist,asFigure=True)

编辑: 下面是一个基于 Naren 反馈的示例:

创建数据框:

a={'catagory':['loc1','loc2','loc3'],'dogs':[1,5,6],'cats':[3,1,4],'birds':[4,12,2]}
df1 = pd.DataFrame(a)
b={'catagory':['loc1','loc2','loc3'],'dogs':[12,3,5],'cats':[4,6,1],'birds':[7,0,8]}
df2 = pd.DataFrame(b)

情节将只显示狗的信息,而不是鸟或猫:

fig = tls.make_subplots(rows=2, cols=1)

fig1 = df1.iplot(kind='bar',barmode='stack',x='catagory',
                       y=['dogs','cats','birds'],asFigure=True)

fig.append_trace(fig1['data'][0], 1, 1)

fig2 = df2.iplot(kind='bar',barmode='stack',x='catagory',
                       y=['dogs','cats','birds'],asFigure=True)

fig.append_trace(fig2['data'][0], 2, 1)

iplot(fig)

【问题讨论】:

    标签: python plotly plotly-python


    【解决方案1】:

    新答案:

    我们需要遍历每一个动物并附加一个新的跟踪来生成你需要的东西。这将提供我希望的所需输出。

    import pandas as pd
    import numpy as np
    import cufflinks as cf
    import plotly.tools as tls
    from plotly.offline import download_plotlyjs, plot,iplot
    cf.go_offline()
    import random
    
    def generate_random_color():
        r = lambda: random.randint(0,255)
        return '#%02X%02X%02X' % (r(),r(),r())
    
    a={'catagory':['loc1','loc2','loc3'],'dogs':[1,5,6],'cats':[3,1,4],'birds':[4,12,2]}
    df1 = pd.DataFrame(a)
    b={'catagory':['loc1','loc2','loc3'],'dogs':[12,3,5],'cats':[4,6,1],'birds':[7,0,8]}
    df2 = pd.DataFrame(b)
    
    #shared Xaxis parameter can make this graph look even better
    fig = tls.make_subplots(rows=2, cols=1)
    
    for animal in ['dogs','cats','birds']: 
        animal_color = generate_random_color()
        fig1 = df1.iplot(kind='bar',barmode='stack',x='catagory',
                           y=animal,asFigure=True,showlegend=False, color = animal_color)
        fig.append_trace(fig1['data'][0], 1, 1)
    
        fig2 = df2.iplot(kind='bar',barmode='stack',x='catagory',
                           y=animal,asFigure=True, showlegend=False, color = animal_color)
        #if we do not use the below line there will be two legend
        fig2['data'][0]['showlegend'] = False
    
        fig.append_trace(fig2['data'][0], 2, 1)
        #additional bonus
        #use the below command to use the bar chart three mode
        # [stack, overlay, group]
        #as shown below
        #fig['layout']['barmode'] = 'overlay'
    iplot(fig)
    

    输出:

    旧答案:

    这将是解决方案

    解释:

    Plotly 工具具有创建子图的子图功能,您应该阅读文档以了解更多详细信息 here。所以我首先使用袖扣来创建条形图的图形。需要注意的一件事是袖扣使用数据和布局创建和对象。 Plotly 只会将一个布局参数作为输入,因此我只从 cufflinks 图中获取 data 参数并将其 append_trace 到 make_suplots 对象。所以 fig.append_trace() 第二个参数是行号,第三个参数是列号

    import pandas as pd
    import cufflinks as cf
    import numpy as np
    import plotly.tools as tls
    from plotly.offline import download_plotlyjs, plot,iplot
    cf.go_offline()
    
    fig = tls.make_subplots(rows=2, cols=1)
    
    df = pd.DataFrame(np.random.randint(0,100,size=(100, 4)), columns=list('ABCD'))
    fig1 = df.iplot(kind='bar',barmode='stack',x='A',
                           y='B',asFigure=True)
    fig.append_trace(fig1['data'][0], 1, 1)
    df2 = pd.DataFrame(np.random.randint(0,100,size=(100, 4)), columns=list('EFGH'))
    fig2 = df2.iplot(kind='bar',barmode='stack',x='E',
                           y='F',asFigure=True)
    fig.append_trace(fig2['data'][0], 2, 1)
    iplot(fig)
    

    如果你想在子图中添加一个通用布局,我建议你这样做

    fig.append_trace(fig2['data'][0], 2, 1)
    fig['layout']['showlegend'] = False
    iplot(fig)
    

    甚至

    fig.append_trace(fig2['data'][0], 2, 1)
    fig['layout'].update(fig1['layout'])
    iplot(fig)
    

    所以在绘制之前的第一个例子中,我访问了布局对象的各个参数并进行了更改,您需要通过布局对象属性进行参考。

    在绘制之前的第二个示例中,我使用袖扣生成的布局更新图形的布局,这将产生与我们在袖扣中看到的相同的输出。

    【讨论】:

    • 谢谢@Naren,我试过了,但它只显示了两个子图中的一些数据。我添加了一个示例来说明我的问题中发生了什么。
    • @sparrow 根据您的新更新更新我的答案。
    • 您甚至可以通过遍历 fig1['data'] 元素并将它们全部写入同一行,col 位置,将多条轨迹放在同一个图表中。
    【解决方案2】:

    您也可以尝试以下使用袖扣:

    cf.subplots([df1.figure(kind='bar',categories='category'),
             df2.figure(kind='bar',categories='category')],shape=(2,1)).iplot()
    

    这应该给你:

    【讨论】:

    • 我注意到,当我使用堆叠条形图执行此操作时,“堆叠”质量被删除。有没有办法将数字放入子图中而不删除它们的任何属性?我试过这个: iplot(cf.subplots([fig1,fig2],shape=(2,1)))
    • 同样,如果我添加一堆分布图,那么地毯不会被绘制,但图形的主要部分会。
    • @jorge santos - 在上面使用 - cufflinks.subplots([fig1],shape=(1,1)).iplot() 我收到以下错误:AttributeError: 'dict' object has没有属性 'iplot' 知道有什么替代方法或错误吗?
    【解决方案3】:

    您可以获得一个仪表板,其中包含多个图表,每个图表旁边都有图例:

    import plotly
    import plotly.offline as py
    import plotly.graph_objs as go
    fichier_html_graphs=open("DASHBOARD.html",'w')
    fichier_html_graphs.write("<html><head></head><body>"+"\n")
    
    i=0
    while 1:
        if i<=40:
            i=i+1
    
    
            #______________________________--Plotly--______________________________________
    
    
            color1 = '#00bfff'
            color2 = '#ff4000'
    
            trace1 = go.Bar(
                x = ['2017-09-25','2017-09-26','2017-09-27','2017-09-28','2017-09-29','2017-09-30','2017-10-01'],
                y = [25,100,20,7,38,170,200],
                name='Debit',
                marker=dict(
                    color=color1
                )
    
            )
            trace2 = go.Scatter(
    
                x=['2017-09-25','2017-09-26','2017-09-27','2017-09-28','2017-09-29','2017-09-30','2017-10-01'],
                y = [3,50,20,7,38,60,100],
                name='Taux',
                yaxis='y2'
    
            )
            data = [trace1, trace2]
            layout = go.Layout(
                title= ('Chart Number: '+str(i)),
                titlefont=dict(
                family='Courier New, monospace',
                size=15,
                color='#7f7f7f'
                ),
                paper_bgcolor='rgba(0,0,0,0)',
                plot_bgcolor='rgba(0,0,0,0)',
    
                yaxis=dict(
                    title='Bandwidth Mbit/s',
                    titlefont=dict(
                        color=color1
                    ),
                    tickfont=dict(
                        color=color1
                    )
                ),
                yaxis2=dict(
                    title='Ratio %',
                    overlaying='y',
                    side='right',
                    titlefont=dict(
                        color=color2
                    ),
                    tickfont=dict(
                        color=color2
                    )
    
                )
    
            )
            fig = go.Figure(data=data, layout=layout)
            plotly.offline.plot(fig, filename='Chart_'+str(i)+'.html',auto_open=False)
            fichier_html_graphs.write("  <object data=\""+'Chart_'+str(i)+'.html'+"\" width=\"650\" height=\"500\"></object>"+"\n")
        else:
            break
    
    
    fichier_html_graphs.write("</body></html>")
    print("CHECK YOUR DASHBOARD.html In the current directory")
    

    结果:

    【讨论】:

    • 最后一行有bug,我得到这样的文字="Chart_12.html" width="650" height="500"&gt;'
    【解决方案4】:

    这是一个工作示例中的一个简短函数,用于将图形列表全部保存到单个 HTML 文件中。

    def figures_to_html(figs, filename="dashboard.html"):
        dashboard = open(filename, 'w')
        dashboard.write("<html><head></head><body>" + "\n")
        for fig in figs:
            inner_html = fig.to_html().split('<body>')[1].split('</body>')[0]
            dashboard.write(inner_html)
        dashboard.write("</body></html>" + "\n")
    
    
    # Example figures
    import plotly.express as px
    gapminder = px.data.gapminder().query("country=='Canada'")
    fig1 = px.line(gapminder, x="year", y="lifeExp", title='Life expectancy in Canada')
    gapminder = px.data.gapminder().query("continent=='Oceania'")
    fig2 = px.line(gapminder, x="year", y="lifeExp", color='country')
    gapminder = px.data.gapminder().query("continent != 'Asia'")
    fig3 = px.line(gapminder, x="year", y="lifeExp", color="continent",
                   line_group="country", hover_name="country")
    
    figures_to_html([fig1, fig2, fig3])
    

    【讨论】:

    • 这解决了我遇到的一个问题。有没有办法启动/打开dashboard.html,而不是将其写入文件然后必须找到并打开它?类似于 plotly express 在浏览器中自动打开的方式。有没有办法让地块并排而不是堆叠?
    【解决方案5】:

    您已经收到了一些非常有效的建议。但是,它们确实需要大量编码。 Facet / trellis plots using px.bar() 将让您仅使用 (almost) 生成下面的图:

    px.bar(df, x="category", y="dogs", facet_row="Source")
    

    您必须采取的唯一额外步骤是引入一个用于拆分数据的变量,然后像这样收集或连接您的数据框:

    df1['Source'] = 1
    df2['Source'] = 2
    df = pd.concat([df1, df2])
    

    如果您还想包含其他变量,请执行以下操作:

    fig = px.bar(df, x="category", y=["dogs", "cats", "birds"], facet_row="Source")
    fig.update_layout(barmode = 'group')
    

    完整代码:

    # imports
    import plotly.express as px
    import pandas as pd
    
    # data building
    a={'category':['loc1','loc2','loc3'],'dogs':[1,5,6],'cats':[3,1,4],'birds':[4,12,2]}
    df1 = pd.DataFrame(a)
    b={'category':['loc1','loc2','loc3'],'dogs':[12,3,5],'cats':[4,6,1],'birds':[7,0,8]}
    df2 = pd.DataFrame(b)
    
    # data processing 
    df1['Source'] = 1
    df2['Source'] = 2
    df = pd.concat([df1, df2])
    
    # plotly figure
    fig = px.bar(df, x="category", y="dogs", facet_row="Source")
    fig.show()
    
    #fig = px.bar(df, x="category", y=["dogs", "cats", "birds"], facet_row="Source")
    #fig.update_layout(barmode = 'group')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-02
      • 1970-01-01
      • 1970-01-01
      • 2021-11-03
      • 1970-01-01
      • 2021-12-21
      • 1970-01-01
      • 2020-07-22
      相关资源
      最近更新 更多