Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Plotly - Multiple dropdown plots, each of which have subplots

Problem

I'm trying to combine two Python Plotly features. One of them is a drop down menu where a user can switch between plots (link to examples). The other feature is subplots.

My attempt

I have working code that uses the dropdown menu, but it doesn't have subplots. So I looked up how to create subplots here and I thought I could treat a tools.make_subplots figure the same way I treated a go.Box figure. I'm sorry if this seems naive, I'm actually fairly new to Plotly.

However, this attempt is not working at all, I'm seeing two exceptions rise which I've put at the very bottom.

My Working Code (no subplots)

# NOTE: This code goes in between 'START' and 'END' below
traces = []
for data in datas:
    traces.append(go.Box(
                            x=data.index,
                            y=data.values, 
                            showlegend=False
                        ))

My Subplot Code

import plotly.offline as py
import plotly.graph_objs as go
from plotly.offline import init_notebook_mode, iplot, plot
from plotly import tools
init_notebook_mode(connected=True)

### Create individual figures
# START
traces = []
for data in datas:
    fig = tools.make_subplots(rows=1, cols=2)

    trace1 = go.Box(
                    x=data.head(10).index,
                    y=data.head(10).values, 
                    showlegend=False
                )
    trace2 = go.Box(
                    x=data.tail(10).index,
                    y=data.tail(10).values, 
                    showlegend=False
                )   
    fig.append_trace(trace1, 1, 1)
    fig.append_trace(trace2, 1, 2)
    traces.append(fig)
# END

### Create buttons for drop down menu
buttons = []
for i, label in enumerate(labels):
    visibility = [i==j for j in range(len(labels))]
    button = dict(
                 label =  label,
                 method = 'update',
                 args = [{'visible': visibility},
                     {'title': label}])
    buttons.append(button)

updatemenus = list([
    dict(active=-1,
         x=-0.15,
         buttons=buttons
    )
])

layout = dict(title='Title', 
              showlegend=False,
              updatemenus=updatemenus)

fig = dict(data=traces, layout=layout)

iplot(fig, filename='dropdown')

Error 1

'layout' is not allowed in 'scatter'

Path To Error: ['data'][0]['layout']

Error 2

PlotlyError: Invalid 'figure_or_data' argument. Plotly will not be
able to properly parse the resulting JSON. If you want to send this 'figure_or_data' to Plotly anyway (not recommended), you can set 'validate=False' as a plot option.

Here's why you're seeing this error:

'layout' is not allowed in 'scatter'

...

NOTE: When I pass validate=False as a plot option, all I see is an empty plot with drop down menu functionality

like image 943
Patrick Stetz Avatar asked May 24 '18 20:05

Patrick Stetz


People also ask

How do you use subplots in Plotly?

Simple SubplotFigures with subplots are created using the make_subplots function from the plotly. subplots module. Here is an example of creating a figure that includes two scatter traces which are side-by-side since there are 2 columns and 1 row in the subplot layout.

What does Add_trace do in Plotly?

Adding Traces New traces can be added to a plot_ly figure using the add_trace() method. This method accepts a plot_ly figure trace and adds it to the figure. This allows you to start with an empty figure, and add traces to it sequentially.

What is a trace in Plotly?

A plotly. graph_objects. Image trace is a graph object in the figure's data list with any of the named arguments or attributes listed below. Display an image, i.e. data on a 2D regular raster. By default, when an image is displayed in a subplot, its y axis will be reversed (ie.


2 Answers

Naren is right, only one subplots figure needs to be made. And to create the drop down menu effect, you just need to add two traces to the same position like this..

fig.append_trace(trace1, 1, 1)
fig.append_trace(trace2, 1, 1)

Working code

import plotly.offline as py
import plotly.graph_objs as go
from plotly.offline import init_notebook_mode, iplot, plot
from plotly import tools
init_notebook_mode(connected=True)

x = [i for i in range(100)]
df_1 = pd.DataFrame([(i, 1+i) for i in range(100)], columns=["X", "Y"])
df_2 = pd.DataFrame([(i, i*i) for i in range(100)], columns=["X", "Y"])
labels = ["Plus one", "Square"]

### Create individual figures
# START
fig = tools.make_subplots(rows=1, cols=2)

trace1 = go.Bar(
                x=df_1.head(10).X,
                y=df_1.head(10).Y, 
                showlegend=False
            )
trace2 = go.Bar(
                x=df_2.head(10).X,
                y=df_2.head(10).Y, 
                showlegend=False
            )

fig.append_trace(trace1, 1, 1)
fig.append_trace(trace2, 1, 1)

trace1 = go.Bar(
                x=df_1.tail(10).X,
                y=df_1.tail(10).Y, 
                showlegend=False
            )
trace2 = go.Bar(
                x=df_2.tail(10).X,
                y=df_2.tail(10).Y, 
                showlegend=False
            )   
fig.append_trace(trace1, 1, 2)
fig.append_trace(trace2, 1, 2)
# END

### Create buttons for drop down menu
buttons = []
for i, label in enumerate(labels):
    visibility = [i==j for j in range(len(labels))]
    button = dict(
                 label =  label,
                 method = 'update',
                 args = [{'visible': visibility},
                     {'title': label}])
    buttons.append(button)

updatemenus = list([
    dict(active=-1,
         x=-0.15,
         buttons=buttons
    )
])

fig['layout']['title'] = 'Title'
fig['layout']['showlegend'] = False
fig['layout']['updatemenus'] = updatemenus

iplot(fig, filename='dropdown')

Thank you

So much to Naren Murali for your help! Editing your code a bit gave me the answer.

I was looking to create this.. enter image description here enter image description here

However your code was giving me these plots... enter image description here enter image description here

like image 154
Patrick Stetz Avatar answered Oct 23 '22 19:10

Patrick Stetz


I think you have misunderstood the concept of subplots, the reason you are getting the error is because the make_subplots() function will create a layout object of its own, hence you are getting the error.

'layout' is not allowed in 'scatter'

Path To Error: ['data'][0]['layout']

The proper way to modify the layout of a subplot is to create the subplot and access the individual object properties and set them, like shown below.

updatemenus = list([
    dict(active=-1,
         x=-0.15,
         buttons=buttons
    )
])

fig['layout']['title'] = 'Title'
fig['layout']['showlegend'] = False
fig['layout']['updatemenus'] = updatemenus

Also you are creating a new subplot object each time the for loop is run, which is wrong. I am talking about the below line.

traces = []
for data in datas:
    fig = tools.make_subplots(rows=1, cols=2)

You need to assign it only once, please refer the below working example and try to implement the same method to your usecase.

import plotly.offline as py
import plotly.graph_objs as go
from plotly.offline import init_notebook_mode, iplot, plot
from plotly import tools
init_notebook_mode(connected=True)
df = pd.DataFrame([[1, 2], [3, 4], [5, 6], [7, 8]], columns=["A", "B"])
labels = ["A", "B"]
datas = [df, df]
### Create individual figures
# START
fig = tools.make_subplots(rows=2, cols=2)

for i, data in enumerate(datas):

    trace1 = go.Bar(
                    x=data.head(10).A,
                    y=data.head(10).B, 
                    showlegend=False
                )
    trace2 = go.Bar(
                    x=data.tail(10).A,
                    y=data.tail(10).B, 
                    showlegend=False
                )   
    fig.append_trace(trace1, i + 1, 1)
    fig.append_trace(trace2, i + 1, 2)

### Create buttons for drop down menu
buttons = []
for i, label in enumerate(labels):
    visibility = [i==j for j in range(len(labels))]
    button = dict(
                 label =  label,
                 method = 'update',
                 args = [{'visible': visibility},
                     {'title': label}])
    buttons.append(button)

updatemenus = list([
    dict(active=-1,
         x=-0.15,
         buttons=buttons
    )
])

fig['layout']['title'] = 'Title'
fig['layout']['showlegend'] = False
fig['layout']['updatemenus'] = updatemenus

iplot(fig, filename='dropdown')

Please do let me know if this solves your issue!

like image 41
Naren Murali Avatar answered Oct 23 '22 20:10

Naren Murali