36

been loving the plotly express graphs but want to create a dashboard with them now. Did not find any documentation for this. Is this possible?

Animesh Dwivedi
  • 461
  • 1
  • 4
  • 4

6 Answers6

28

I was struggling to find a response on this as well so I ended up having to create my own solution (see my full breakdown here: How To Create Subplots Using Plotly Express)

Essentially make_subplots() takes in plot traces to make the subplots instead of figure objects like that which Express returns. So what you can do is, after creating your figures in Express, is break apart the Express figure objects into their traces and then re-assemble their traces into subplots.

Code:

import dash_core_components as dcc
import plotly.express as px
import plotly.subplots as sp


# Create figures in Express
figure1 = px.line(my_df)
figure2 = px.bar(my_df)

# For as many traces that exist per Express figure, get the traces from each plot and store them in an array.
# This is essentially breaking down the Express fig into it's traces
figure1_traces = []
figure2_traces = []
for trace in range(len(figure1["data"])):
    figure1_traces.append(figure1["data"][trace])
for trace in range(len(figure2["data"])):
    figure2_traces.append(figure2["data"][trace])

#Create a 1x2 subplot
this_figure = sp.make_subplots(rows=1, cols=2) 

# Get the Express fig broken down as traces and add the traces to the proper plot within in the subplot
for traces in figure1_traces:
    this_figure.append_trace(traces, row=1, col=1)
for traces in figure2_traces:
    this_figure.append_trace(traces, row=1, col=2)

#the subplot as shown in the above image
final_graph = dcc.Graph(figure=this_figure)

Output:

enter image description here

Mike_H
  • 1,343
  • 1
  • 14
  • 31
mmarion
  • 859
  • 8
  • 20
  • 2
    what is dcc in final line? – Sam Murphy Apr 29 '21 at 14:12
  • 1
    @SamMurphy sorry that's a Dash Core Component, I'm using this figure with Plotly Dash so I'm returning the fig as a Dash Graph object in my case. The final figure `this_figure` should hold all the figure data just fine – mmarion Apr 29 '21 at 17:53
  • 2
    Nice solution, notice that it strips changes in update_layout – Oded Ben Dov Jan 01 '22 at 20:41
  • Hi, thank you for your answer, it works. However, when i tried it for subplots of pie charts i got an error: ValueError: Trace type 'pie' is not compatible with subplot type 'xy' at grid position (1, 1). Can you advise smth, please? Thank you! – Demi May 18 '22 at 07:31
15

Working off @mmarion's solution:

import plotly.express as px
from plotly.offline import plot
from plotly.subplots import make_subplots

figures = [
            px.line(df1),
            px.line(df2)
    ]

fig = make_subplots(rows=len(figures), cols=1) 

for i, figure in enumerate(figures):
    for trace in range(len(figure["data"])):
        fig.append_trace(figure["data"][trace], row=i+1, col=1)
        
plot(fig)

This is easily extended into the column dimension.

XiB
  • 620
  • 6
  • 19
2

I solved it by combining all the data in a single dataframe, with a column called "type" that distinguishes the two plots. Then I used facet_col to create (some kind of) subplot:

px.scatter(df3, x = 'dim1', y = 'dim2', color = 'labels', facet_col='type')

enter image description here

Alessandra
  • 86
  • 1
  • 4
  • 2
    This is probably the best way as long as all graphs are of the same type. You wouldn't be able to use facets if they needed to be different. – Steven Oct 27 '22 at 01:01
1

From the docs:

**facet_row**
(string: name of column in data_frame) Values from this column are used to assign marks to facetted subplots in the vertical direction.
**facet_col**
(string: name of column in data_frame) Values from this column are used to assign marks to facetted subplots in the horizontal direction.

Get here some examples too.

https://medium.com/@plotlygraphs/introducing-plotly-express-808df010143d

PythonNoob
  • 914
  • 1
  • 7
  • 15
  • 1
    Thanks for this. facet_row allows for panels which are useful but they are usually the same view for different segments (for example). I am looking to combine several unrelated views in to a dashboard. Plotly examples here for reference. https://plot.ly/dashboard/jackp:16823/present#/ – Animesh Dwivedi Jun 26 '19 at 03:06
1

Unfortunately, it is not at the moment. See the following issue to get updated: https://github.com/plotly/plotly_express/issues/83

hrng
  • 51
  • 7
1

Try this function out. You have to pass in the plotly express figures into the function and it returns a subplot figure.

#quick_subplot function
def quick_subplot(n,nrows,ncols, *args): #n:number of subplots, nrows:no.of. rows, ncols:no of cols, args
    from dash import dcc
    import plotly.subplots as sp
    from plotly.subplots import make_subplots

    fig=[] #list to store figures
    for arg in args:
        fig.append(arg)

    
    combined_fig_title=str(input("Enter the figure title: "))
    tok1=int(input("Do you want to disable printing legends after the first legend is printed ? {0:Disable, 1:Enable} : "))

    fig_traces={} #Dictionary to store figure traces
    subplt_titles=[]

    #Appending the traces of the figures to a list in fig_traces dictionary
    for i in range(n):
        fig_traces[f'fig_trace{i}']=[]

        for trace in range(len(fig[i]["data"])):
            fig_traces[f'fig_trace{i}'].append(fig[i]["data"][trace])
            if(i!=0 & tok1==0):
                fig[i]["data"][trace]['showlegend'] = False #Disabling other legends

        subplt_titles.append(str(input(f"Enter subplot title for subplot-{i+1}: ")))
    
    #Creating a subplot
        #Change height and width of figure here if necessary
    combined_fig=sp.make_subplots(rows = nrows, cols = ncols, subplot_titles = subplt_titles)
    combined_fig.update_layout(height = 500, width = 1200, title_text = '<b>'+combined_fig_title+'<b>', title_font_size = 25)
    
    #Appending the traces to the newly created subplot
    i=0
    for a in range(1,nrows+1):
        for b in range(1, ncols+1):
            for traces in fig_traces[f"fig_trace{i}"]:
                combined_fig.append_trace(traces, row=a, col=b)
            i+=1
            
            
    #Setting axis titles       
        #X-axis
    combined_fig['layout']['xaxis']['title']['font']['color']='blue'
    tok2=int(input("Separate x-axis titles?{0:'No',1:'Yes'}: "))
    
    for i in range(max(nrows,ncols)):
        if i==0:
            combined_fig['layout']['xaxis']['title']=str(input(
            f"Enter x-axis's title: "))

        if tok2 & i!=0:
            combined_fig['layout'][f'xaxis{i+1}']['title']=str(input(
            f"Enter x-axis {i+1}'s title: "))
            combined_fig['layout'][f'xaxis{i+1}']['title']['font']['color']='blue'
                
            
        
        #Y-axis
    combined_fig['layout']['yaxis']['title']['font']['color']='blue'
    tok3=int(input("Separate y-axis titles?{0:'No',1:'Yes'}: "))
    
    for i in range(max(nrows,ncols)):
        if i==0:
            combined_fig['layout']['yaxis']['title']=str(input(
            f"Enter y-axis's title: "))
            
        if tok3 & i!=0:
            combined_fig['layout'][f'yaxis{i+1}']['title']=str(input(
            f"Enter y-axis {i+1}'s title: "))

            combined_fig['layout'][f'yaxis{i+1}']['title']['font']['color']='blue'

                
                
    combined_fig['layout']['xaxis']['title']['font']['color']='blue'               
    combined_fig['layout']['yaxis']['title']['font']['color']='blue'
    
    
    return combined_fig


f=quick_subplot(2,1,2,fig1,fig2)
f.show()