Aim: Having two scatter plots in the same figure while using a slider in Plotly.
Expected behavior: Show a figure with two plots updating simultaneously and sharing the same "slider step".
Current behavior: The slider steps over both scatter plots, separating them and showing one result at a time.
I attach below a minimal reproducible example adapted from the plotly documentation. Instead of simply plotting the sin(x), I also added a second plot with cos(x).
I tried using add_traces(), and also creating two separate traces and the updating them with fig = go.Figure(data=trace_list1+trace_list2) as shown here.
Any help would be much appreciated!
import plotly.graph_objects as go
import numpy as np
# Create figure
fig = go.Figure()
# Add traces, one for each slider step
for step in np.arange(0, 5, 0.5):
fig.add_traces([
go.Scatter(
x=np.arange(0, 10, 0.01),
y=np.sin(step * np.arange(0, 10, 0.01))),
go.Scatter(
x=np.arange(0, 10, 0.01),
y=np.cos(step * np.arange(0, 10, 0.01)))])
# Make 10th trace visible
fig.data[10].visible = True
# Create and add slider
steps = []
for i in range(len(fig.data)):
step = dict(
method="update",
args=[{"visible": [False] * len(fig.data)},
{"title": "Slider switched to step: " + str(i)}], # layout attribute
)
step["args"][0]["visible"][i] = True # Toggle i'th trace to "visible"
steps.append(step)
sliders = [dict(
active=10,
currentvalue={"prefix": "Frequency: "},
pad={"t": 50},
steps=steps
)]
fig.update_layout(
sliders=sliders
)
fig.show()
I enclose the answer given on the forum maintained by the Plotly community.
# Create and add slider
steps = []
for i in range(len(fig.data)):
if i % 2 == 0:
step = dict(
method="update",
args=[{"visible": [False] * len(fig.data)},
{"title": "Slider switched to step: " + str(i/2)}], # layout attribute
)
step["args"][0]["visible"][i] = True # Toggle i'th trace to "visible"
step["args"][0]["visible"][i+1] = True
steps.append(step)
Related
I am trying to use plotly to plot a graph similar to the one here below:
Unfortunately I am only able to plot something like this
What I would like is to have normal boundaries (upper and lower defined by two dataframe columns and only one entry in the legend.
import plotly.graph_objs as go
# Create a trace for the lower bound
trace1 = go.Scatter(x=df.index,
y=df['lower'],
name='Lower Bound',
fill='tonexty',
fillcolor='rgba(255,0,0,0.2)',
line=dict(color='blue'))
# Create a trace for the median
trace2 = go.Scatter(x=df.index,
y=df['median'],
name='median',
line=dict(color='blue', width=2))
# Create a trace for the upper bound
trace3 = go.Scatter(x=df.index,
y=df['upper'],
name='Upper Bound',
fill='tonexty',
fillcolor='rgba(255,0,0,0.2)',
line=dict(color='blue'))
# Create the layout
layout = go.Layout(xaxis=dict(title='Date'),
yaxis=dict(title='title'))
# Create the figure with the three traces and the layout
fig = go.Figure(data=[trace1, trace2, trace3], layout=layout)
context['pltyplot'] = pltyplot(fig, output_type="div")
I want to use plotly because I am integrating the resulting figure into a django web page and plotly enables, with the las line, to import the whole object in a clean, simple and interactive way into the poge.
Any ideas?
You can try this code:
import plotly.graph_objs as go
x = [1, 2, 3, 4, 5]
y = [2, 4, 5, 3, 6]
# Define the confidence interval
interval = 0.6 * np.std(y) / np.mean(y)
fig = go.Figure()
fig.add_trace(go.Scatter(x=x, y=y, mode='lines', name='Line'))
fig.add_trace(go.Scatter(x=x+x[::-1],
y=y+[i + interval for i in y[::-1]],
fill='toself',
fillcolor='rgba(0,100,80,0.2)',
line=dict(width=0),
showlegend=False))
fig.add_trace(go.Scatter(x=x+x[::-1],
y=y+[i - interval for i in y[::-1]],
fill='toself',
fillcolor='rgba(0,100,80,0.2)',
line=dict(width=0),
showlegend=False))
fig.show()
With this code on the plotly website : https://plotly.com/python/sliders/
Is it possible to add a trace, one for each slider step, once the step is selected? Because if we have a large number of step, it could affect the performance. I have a project and I can't use this method...
import plotly.graph_objects as go
import numpy as np
# Create figure
fig = go.Figure()
# Add traces, one for each slider step
for step in np.arange(0, 5, 0.1):
fig.add_trace(
go.Scatter(
visible=False,
line=dict(color="#00CED1", width=6),
name="𝜈 = " + str(step),
x=np.arange(0, 10, 0.01),
y=np.sin(step * np.arange(0, 10, 0.01))))
# Make 10th trace visible
fig.data[10].visible = True
# Create and add slider
steps = []
for i in range(len(fig.data)):
step = dict(
method="update",
args=[{"visible": [False] * len(fig.data)},
{"title": "Slider switched to step: " + str(i)}], # layout attribute
)
step["args"][0]["visible"][i] = True # Toggle i'th trace to "visible"
steps.append(step)
sliders = [dict(
active=10,
currentvalue={"prefix": "Frequency: "},
pad={"t": 50},
steps=steps
)]
fig.update_layout(
sliders=sliders
)
fig.show()
This is relatively straightforward question but I cannot find adequate documentation to do what I want. I want the x-axis to remain constant when the slider is moved from day to day.
Here is the figure and slider for reference. Note that the x-axis ranges from appx. -3.25 to 3:
and then if I move the slider the x-axis now ranges from approx. -3 to 4.
How do I force the min and max x-axis values to remain constant?
Here is code for the example:
import numpy as np
import plotly.express as px
from plotly.offline import plot
total_days = 3
data = list()
for day in range(total_days):
data.append(plotly.graph_objs.Histogram(
x=np.random.randn(500) + day * 0.5,
name='Day {}, control'.format(day),
visible=day < 1
)
)
steps = list()
for i in range(total_days):
step = dict(
method='restyle',
args=['visible', [False] * total_days * 2],
label='Day {}'.format(i)
)
step['args'][1][i] = True
steps.append(step)
sliders = [dict(
active=0,
steps=steps
)]
layout = dict(sliders=sliders)
fig = dict(data=data, layout=layout)
plot(fig)
Try updating the layout dictionary as follows:
layout = dict(sliders=sliders,
xaxis=dict(range=[-3, 3],
autorange=False))
where:
range defines the minimum and maximum value of the x-axis (in this example -3 and 3), see https://plotly.com/python/reference/layout/xaxis/#layout-xaxis-range.
autorange = False ensures that the range is kept fixed instead of being recalculated based on the input data, see https://plotly.com/python/reference/layout/xaxis/#layout-xaxis-autorange.
In python3, I am trying to edit a specific add_trace() plot. For context, I create a Plotly graph with dropdown menus to change/update the plot itself.
I am plotting a 3D scatter which takes x, y, z. But then I added a planar graph to the same figure, go.Surface, which is the planar estimation for the data.
The problem with this is that when I change an attribute, say 'x' for the X-axis, it also changes the 'x' attribute on the go.Surface, which should only be the estimation of the data rather than the data itself.
Is there a way to separate specific add_trace() attributes, so that updating a data parameter won't effect the go.Surface parameter?
Here is an example is used for editing the left and right y axis
in the arg of the menu you need to add a list with a index. [0] is the first trace added [1] the second etc.
ps I'm not a 'code' expert just 'learned' python last week for ChemE thesis so my code works but it probably isn't the best/most efficient
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
import numpy as np
# Data
x = np.linspace(-np.pi, np.pi, 200)
y1 = np.sin(x) # f(x) = sin(x*pi)
y2 = np.cos(x) #f(x) = cos(x*pi)
y3 = np.tan(x) #f(x) = tan(x*pi)
d = {'x': x, 'y1': y1,'y2': y2,'y3': y3}
df = pd.DataFrame(data=d)
name = 'Test'
def Graph(df,name):
#Make fig
fig = make_subplots(specs=[[{"secondary_y": True}]])
#Add first trace
fig.add_trace(
go.Scatter(x=df['x'],
y=df['y1'],
),
secondary_y=False,)
#Add second trace
fig.add_trace(
go.Scatter(x=df['x'],
y=df['y2'],
),
secondary_y=True,)
# buttons for menu 1, contolling first trace
buttons1=[]
#Dynamic list based on df keys
for dfk in df.keys():
buttons1.append(dict(method='restyle',
label=dfk,
visible=True,
args=[{'y':[df[dfk].values]}, [0]], #The [0] 'locks' it to the first trace
)
)
# buttons for menu 2, contolling seccond trace
buttons2=[]
#Dynamic list based on df keys
for dfk in df.keys():
buttons2.append(dict(method='restyle',
label=dfk,
visible=True,
args=[{'y':[df[dfk].values]}, [1]], #The [1] 'locks' it to the second trace
)
)
#Delete x-axis from dropdown
del buttons1[0]
del buttons2[0]
#List for menus
updatemenu=[]
#add dict for buttons
your_menu1=dict()
updatemenu.append(your_menu1)
your_menu2=dict()
updatemenu.append(your_menu2)
#Fill dict
updatemenu[0]['buttons']=buttons1
updatemenu[0]['x']=0.15 #Some styling
updatemenu[0]['y']=1.12 #Some styling
updatemenu[1]['buttons']=buttons2
updatemenu[1]['x']=0.33 #Some styling
updatemenu[1]['y']=1.12 #Some styling
# add dropdown menus to the figure
fig.update_layout(showlegend=True, updatemenus=updatemenu)
# add notations to the dropdown menus
fig.update_layout(
annotations=[
dict(text="Left y-axis:", x=0, xref="paper", y=1.10, yref="paper",
align="left", showarrow=False),
dict(text="Right y-axis::", x=0.17, xref="paper", y=1.10,
yref="paper", showarrow=False)])
name = str(name)+'.html'
fig.write_html(name, auto_open=True)
Graph(df,name)
I generate daily two histograms from data, one with the needed values and the other with the reached values for different stations. I want to plot these histograms side by side, like the bottom pink example in Plotly here (see link for source code). However, since both histograms are generated daily, I need to add a time slider to the graph, like the bottom example 'Simple Slider' from Plotly (see link for source code).
My problem is that the first example uses
fig = dict(data=data, layout=layout)
plotly.offline.plot(fig, filename='Sine Wave Slider')
to plot the histogram, while for the slider the following is used:
import plotly.graph_objs as go
fig = go.Figure(data=data, layout=layout)
plotly.offline.plot(fig, filename='styled histogram')
My (not functioning) code right now is looking like this, where I try to plot the same 2 histograms 3 times. How can I change the code to generate a figure that uses both histograms (both with different random data) and the slider at the same time?
import plotly
import plotly.graph_objs as go
import numpy as np
x0 = np.random.randn(500)
x1 = np.random.randn(500)+1
trace1 = go.Histogram(
x=x0,
histnorm='count',
name='control',
autobinx=False,
xbins=dict(
start=-3.5,
end=3.0,
size=0.5
),
marker=dict(
color='#FFD7E9',
),
opacity=0.75
)
trace2 = go.Histogram(
x=x1,
name='experimental',
autobinx=False,
xbins=dict(
start=-2.0,
end=5,
size=0.5
),
marker=dict(
color='#EB89B5'
),
opacity=0.75
)
data = [trace1, trace2]
layout = go.Layout(
title='Sampled Results',
xaxis=dict(
title='Value'
),
yaxis=dict(
title='Count'
),
bargap=0.2,
bargroupgap=0.1
)
steps = []
for i in range(len(trace1)):
step = dict(
method = 'restyle',
args = ['visible', [False] * len(trace1)],
)
step['args'][1][i] = True # Toggle i'th trace to "visible"
steps.append(step)
sliders = [dict(
active = 20,
currentvalue = {"prefix": "Frequency: "},
pad = {"t": 3},
steps = steps
)]
layout = dict(sliders=sliders)
fig = dict(data=data, layout=layout)
plotly.offline.plot(fig, filename='Histogram Slider')
You could create a list of histograms, let's say 3 days (total_days = 3, odd numbers are experimental, even numbers are control).
Only the first traces are shown (visible = day < 1).
Each step in the slider shows/hides another pair of traces.
import plotly
import numpy as np
plotly.offline.init_notebook_mode()
total_days = 3
data = list()
for day in range(total_days):
data.append(plotly.graph_objs.Histogram(
x=np.random.randn(500) + day * 0.5,
histnorm='count',
name='Day {}, control'.format(day),
visible=day < 1
)
)
data.append(plotly.graph_objs.Histogram(
x=np.random.randn(500) + day,
histnorm='count',
name='Day {}, experimental'.format(day),
visible=day < 1
)
)
steps = list()
for i in range(total_days):
step = dict(
method='restyle',
args=['visible', [False] * total_days * 2],
label='Day {}'.format(i)
)
step['args'][1][i * 2] = True
step['args'][1][i * 2 + 1] = True
steps.append(step)
sliders = [dict(
active=0,
steps=steps
)]
layout = dict(sliders=sliders)
fig = dict(data=data, layout=layout)
plotly.offline.iplot(fig)