Plot two different datasets into plotly using drop down menu - python

I have two different datasets (x0,y0), (x1,y1). I need to create two plots and use a drop down menu to select between them.
I am using this code:
import plotly
import plotly.graph_objs as go
import random
x0 = [x for x in range(0,20)]
x1 = [x for x in range(5,100)]
y0 = [random.randint(0,20) for x in range(len(x0))]
y1 = [random.randint(0,50) for x in range(len(x1))]
trace1 = go.Scatter(x=x0,y=y0,line=dict(shape='vh'))
trace2 = go.Scatter(x=x1,y=y1,line=dict(shape='vh'))
data = [trace1,trace2]
updatemenus = list([
dict(active=0,
buttons=list([
dict(label = "4 Aug 1",
method = "update",
args= [data[0]]),
dict(label = "4 Aug 2",
method = "update",
args= [data[1]])]))])
layout = dict(title="Dropdown",
showlegend=True,
xaxis=dict(title="Hours"),
yaxis=dict(title="Number"),
updatemenus=updatemenus)
fig=dict(data=data, layout=layout)
plotly.offline.plot(fig)
Using this code, it plots two datasets into one area, which I would not like to do. And when I select a proper chart on dropdown menu, it just fails to load proper chart.

The problem is that you're directly assigning traces to args. Instead, you should be using the visible property to control which traces in data are visible:
updatemenus = list([
dict(active=0,
showactive = True,
buttons=list([
dict(label = "4 Aug 1",
method = "update",
args = [{"visible": [True, False]}]), # hide trace2
dict(label = "4 Aug 2",
method = "update",
args = [{"visible": [False, True]}]) # hide trace1
]))])
If you only want to show the first trace when the page is loaded, you also need to explicitly set the visible attribute of the second trace to False:
trace1 = go.Scatter(x=x0,y=y0,line=dict(shape='vh'))
trace2 = go.Scatter(x=x1,y=y1,line=dict(shape='vh'), visible=False)
data = [trace1,trace2]
See the official Plotly example.

Related

currently trying to create a box plot for my class and cannot find problem with my code

Here is my code:
df=read.csv("group.csv",header=TRUE)
plt.boxplot(df.group_a,
main = "Sales Data",xlab = "Group A",ylab = "Sales",col = "yellow",border = "red",notch = TRUE)
plt.boxplot(df.group_b,
main = "Sales Data",xlab = "Group B",ylab = "Sales",col = "blue",border = "red",notch = TRUE)
plt.boxplot(df.group_c,
main = "Sales Data",xlab = "Group C",ylab = "Sales",col = "black",border = "red",notch = TRUE)
plt.boxplot(df.group_d,
main = "Sales Data",xlab = "Group D",ylab = "Sales",col = "green",border = "red",notch = TRUE)
It would be very helpful if you reformatted this answer as code. You can do that by simply typing ```python, then hitting Return to go to the next line, pasting in your code, hitting Return again, and then typing ``` once more.
If I do that to your question and move things around a bit, it formats as
import pandas as pd
import matplotlib.pyplot as plt
df=read.csv("group.csv",header=TRUE)
plt.boxplot(df.group_a, main = "Sales Data", xlab = "Group A", ylab = "Sales",
col = "yellow", border = "red", notch = TRUE)
plt.boxplot(df.group_b, main = "Sales Data", xlab = "Group B", ylab = "Sales",
col = "blue", border = "red", notch = TRUE)
plt.boxplot(df.group_c, main = "Sales Data", xlab = "Group C", ylab = "Sales",
col = "black", border = "red", notch = TRUE)
plt.boxplot(df.group_d, main = "Sales Data", xlab = "Group D", ylab = "Sales",
col = "green", border = "red", notch = TRUE)
This has the advantage of making your question readable and even gives you some attractive syntax highlighting. To learn more about how to format questions like this check out https://www.markdownguide.org/.
Now, as for your question, your issue is that your syntax and function calls are mostly incorrect.
df = read.csv("group.csv", header=TRUE) should be df = pd.read_csv("group.csv"). You could theoretically pass True to the header argument since Python interprets that as the integer value 1, but...don't. That's not what that argument is for. Refer to the documentation for this function at https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html to learn more.
notch=TRUE should be notch=True. In Python the boolean values are True and False, and the capitalization is important. You can learn more about these at https://docs.python.org/2.3/whatsnew/section-bool.html.
Lastly, you have a pile of arguments to these plt.boxplot() functions that don't exist. You can learn more about the arguments accepted by this function at https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.pyplot.boxplot.html.
I can't really troubleshoot your answer without a copy of the dataset, but here's a working example that I took straight from https://matplotlib.org/3.3.2/gallery/pyplots/boxplot_demo_pyplot.html#sphx-glr-gallery-pyplots-boxplot-demo-pyplot-py.
import numpy as np
import matplotlib.pyplot as plt
# Fixing random state for reproducibility
np.random.seed(19680801)
# fake up some data
spread = np.random.rand(50) * 100
center = np.ones(25) * 50
flier_high = np.random.rand(10) * 100 + 100
flier_low = np.random.rand(10) * -100
data = np.concatenate((spread, center, flier_high, flier_low))
fig2, ax2 = plt.subplots()
ax2.set_title('Notched boxes')
ax2.boxplot(data, notch=True)
This gives us the following:
Notched Boxplot
I hope this helps! Good luck on your data science adventures.

Plotly slider function only updates one argument

I am trying to build a heatmap with annotations and a title. This title and the annotations should update when the slider is moved. I get this to work, but only for one of the two arguments at the same time. The argument that is at index [1] is being updated, but the other one isn't
Below is a snippet of my code and the error happens in the step for loop:
from plotly.offline import init_notebook_mode, iplot
import plotly.graph_objs as go
import numpy as np
# initialize notebook for offline plotting
init_notebook_mode()
# Set initial slider/title index
start_index = 0
# Build all traces with visible=False
timestep = 5
#df2 = np.random.rand(18,365)*70
data = [go.Heatmap(
visible = False,
x = ['P', 'C', 'S'],
y = [11,10,9,8,7,6],
z = df.iloc[:18,[step]].to_numpy().reshape(6,3),
# z = df2[:,step].reshape(6,3),
zmin = 0,
zmax = 70)
for step in np.arange(0, len(df2.transpose())-1, timestep)
]
# Make initial trace visible
data[start_index]['visible'] = True
# Build slider steps
steps = []
for i in range(len(data)):
step = dict(
# Update method allows us to update both trace and layout properties
method = 'update',
args = [
# Make the ith trace visible
{'visible': [t == i for t in range(len(data))]},
{'annotations' : [dict(
x = x,
y = y,
text = str(round(df.iloc[:18,[i]].to_numpy().reshape(6,3)[-y+11,x],1)),
# text = str(df2[:,i].reshape(6,3)[-y+11,x]),
showarrow = False)
for x in range(3) for y in range(6,12)]},
{'title.text': str(df.columns[i*timestep])},]
)
steps.append(step)
# Build sliders
sliders = [go.layout.Slider(
active = start_index,
currentvalue = {"prefix": "Timestep: "},
pad = {"t": 72},
steps = steps
)]
layout = go.Layout(
sliders=sliders,
title={'text': str(df.columns[start_index])},
yaxis = dict(
tickmode = 'array',
tickvals = [11,10,9,8,7,6],
ticktext = ['06','07','08','09','10','11']
),
annotations = steps[start_index]['args'][1]['annotations']
)
fig = go.Figure(
data=data,
layout=layout)
iplot(fig)
I found the problem. Apparently you need to specify 'annotations' and 'title.text in the same dictionary, instead of seperate ones. The code should thus be changed to:
{'annotations' : [dict(
x = x,
y = y,
text = str(round(df.iloc[:18,[i]].to_numpy().reshape(6,3)[-y+11,x],1)),
# text = str(df2[:,i].reshape(6,3)[-y+11,x]),
showarrow = False)
for x in range(3) for y in range(6,12)],
'title.text': str(df.columns[i*timestep])}

How to show only one trace when plotly updatemenus load on Jupyter Notebook?

I have two graphs that I want to show using plotly's updatemenus feature. I am able to populate and display the data using the updatemenus feature. However, when the plot loads, both the graphs are displayed initially. Is there a way to show only one graph when the plot loads initially?
I went through the documentation for updatemenus on plotly but could not find any attribute that will help me in achieving this.
trace28 = go.Bar(x=for1.head()['Name'],
y=for1.head()['G'],
name='Goals',
opacity=0.8
)
trace29 = go.Bar(x=for1.head()['Name'],
y=for1.head()['A'],
name='Assists',
opacity=0.8
)
trace30 = go.Bar(x=for2.head()['Name'],
y=for2.head()['G'],
name='Goals',
opacity=0.8
)
trace31 = go.Bar(x=for2.head()['Name'],
y=for2.head()['A'],
name='Assists',
opacity=0.8
)
updatemenus = list([dict(active=-1,
type='buttons',
buttons=list([dict(label='2011/12',
method='update',
args=[dict(visible=[True, True, False, False]),
dict(title='<b>Forward Stats 2011/12</b>')
]
),
dict(label='2012/13',
method='update',
args=[{'visible':[False, False, True, True]},
{'title':'<b>Forward Stats 2012/13</b>'}
]
),
])
),
])
layout = go.Layout(title='<b>Forward Stats</b>',
xaxis=dict(title='<b><i>Player Name</b></i>'),
yaxis=dict(title='<b><i>Goals/Assists</b></i>'),
updatemenus=updatemenus,
showlegend=False,
barmode='group'
)
data = [trace28, trace29, trace30, trace31]
fig = go.Figure(data=data, layout=layout)
py.iplot(fig)
I want to display only trace28 and trace29 when the plot loads. Right now, all the traces are being shown when the plot loads.
While making the trace, you can set visible = "legendonly". Then you can toggle the trace by clicking on the line in the legend. Does that do what you want?
So you would change trace30 and trace31
trace30 = go.Bar(x=for2.head()['Name'],
y=for2.head()['G'],
name='Goals',
opacity=0.8,
visible = "legendonly"
)
trace31 = go.Bar(x=for2.head()['Name'],
y=for2.head()['A'],
name='Assists',
opacity=0.8,
visible = "legendonly"
)
Does that get you your desired functionality?

How do I create an interactive plot in python that generates a new plot depending on where i clicked?

I have sales data across stores, for each month and for different categories of products.
Say I have a heatmap of sales quantities across stores and months on either axes.
Now when I click on heatmap at a spot corresponding to a particular store and month, I need a new barplot generated which shows sales quantities of each category in that month and store.
I have done something similar in SAS VA. I believe its called an interaction effect.
I have tried searching documentation of matplotlib and plotly didnt get anything useful yet.
Here is an example how you could do this in Bokeh v1.1.0
from bokeh.plotting import figure, show
from bokeh.models import TapTool, CustomJS, ColumnDataSource, Row, ColorBar, LinearColorMapper, BasicTicker
from bokeh.models.sources import ColumnDataSource
from bokeh.transform import transform
from bokeh.palettes import Viridis256
import random
stores = ["store 1", "store 2", "store 3"]
months = ["january", "fabruary", "march"]
x = ["store 1", "store 2", "store 3", "store 1", "store 2", "store 3", "store 1", "store 2", "store 3"]
y = ["january", "january", "january", "fabruary", "fabruary", "fabruary", "march", "march", "march"]
colors = ["#0B486B", "#79BD9A", "#CFF09E", "#79BD9A", "#0B486B", "#79BD9A", "#CFF09E", "#79BD9A", "#0B486B" ]
p1 = figure(title = "Categorical Heatmap", tools = "tap", toolbar_location = None,
x_range = stores, y_range = months)
p1.rect(x = x, y = y, color = colors, width = 1, height = 1)
categories = ['shoes', 'pants', 'suits']
category_sales = {}
for store in stores:
category_sales[store] = {}
for month in months:
category_sales[store][month] = [random.choice([i for i in range(10000)]) for r in range(3)]
dummy_category_sales = [1000, 1100, 1200]
data = {'x': categories, 'y': dummy_category_sales}
source = ColumnDataSource(data)
p2 = figure(x_range = categories)
bars = p2.vbar(x = 'x', top = 'y', source = source, bottom = 0, width = 0.5)
bars.visible = False
code = '''if (cb_data.source.selected.indices.length > 0){
bars.visible = true;
selected_index = cb_data.source.selected.indices[0];
store = cb_data.source.data['x'][selected_index]
month = cb_data.source.data['y'][selected_index]
bars.data_source.data['y'] = category_sales[store][month]
bars.data_source.change.emit();
}'''
p1.select_one(TapTool).callback = CustomJS(args = dict(bars = bars, category_sales = category_sales), code = code)
plots = Row(p1, p2)
show(plots)
Result:

Python Plotly: Using dropdown menu to switch between choropleth map and scatterplot

I am new to using plotly and I am attempting to build a dynamic visualisation using python and plotly. I hope to be able to switch between a world choropleth map and a scatter plot using a drop-down menu.
So far I have been able to successfully get a dropdown menu to appear and show the required labels and even show a single plot by removing either the choropleth map or scatter plot trace from the data variable. The problem is that I when I try to have both plots implemented the choropleth map is drawn over the top of the scatterplot regardless of the menu option I choose.
A screenshot of the output.
Areas I Have Looked For A Solution
The plotly reference and looked through the updatemenus and layout sections among many others.
Reviewed the ploty python tutorial page for dropdowns and implementing parts of the suggestion in my code with a focus on the update method.
I have found a StackOverflow page that seemed to be very close to the answer I needed however not quite.
Finally, I also searched the plotly community forum.
The Code
Note I have removed a portion of the code such as imports and data at the beginning.
scatterplot = go.Scatter(
y = df2['Renewable energy consumption (% of total final energy consumption) 2015'],
x = df2['GDP per capita, PPP (constant 2011 international $) 2015'],
mode='markers',
ids=df2['Country Name'],
showlegend = False,
marker = dict(
size = 8,
color = np.random.randn(500),
),
textfont = dict(
size = 14,
color = 'black')
)
choropleth_map = dict(
type = 'choropleth',
locations = df['ISO3166_alpha3'],
z = df['renewables_mtoe'],
text = df['Country'],
colorscale = [[0,"rgb(106, 240, 255)"],[0.10,"rgb(106, 199, 255)"],[0.70,"rgb(50, 100, 255)"],[0.93,"rgb(0, 43, 198)"],\
[0.99999,"rgb(0, 24, 109)"],[1,"rgb(220, 220, 220)"]],
autocolorscale = False,
reversescale = True,
marker = dict(
line = dict (
color = 'rgb(180,180,180)',
width = 0.5
) ),
colorbar = dict(
title = 'mtoe<br>',
tickfont = dict(
size = 16),
titlefont = dict(
size = 16)),
)
data = [choropleth_map, scatterplot]
updatemenus = list([
dict(active=0,
buttons=list([
dict(label = 'choropleth_map',
method = 'update',
args = [{'visible': [True,False]},
{'title': 'The Map'}]),
dict(label = 'scatterplot',
method = 'update',
args = [{'visible': [False,True]},
{'title': 'Scatterplot'}]),
]),
)
])
layout = dict(title='default', showlegend=False,
updatemenus=updatemenus,
geo = dict(showframe = True,
showcoastlines = False,
showland = True,
landcolor = '#dcdcdc',
projection = dict(type = 'natural earth'))
)
fig = dict( data=data, layout=layout )
plotly.offline.iplot(fig, validate=True)
A big thank you in advance to anyone who can help. I have spent days trying to solve this problem, it has even driven me to make my first post on StackOverflow.

Categories

Resources