Plotly charts in a for loop
It turns out the problem is solved here
https://github.com/ropensci/plotly/issues/273
knitr has known issues printing plotly charts in a loop.
Quoting the final answer cpsievert from here
```{r}
l <- htmltools::tagList()
for (i in 1:3) {
l[[i]] <- as.widget(plot_ly(x = rnorm(10)))
}
l
```
This solved my problem. Though I ended up porting everything from ggplot2 to plotly R api before I found this solution.
MLavoie, thanks for your help. I had generated a dummy dataset just to create a reproducible example. Though your solution probably solves the dummy example, it is not all that relevant to me in the current problem. I think the solution provided here should be generic.
Thanks,
Kaustubh
Unable to make multiple plotly graphs in for loop
- have coded placeholders for two functions used in your code
create_model()
andassign_model()
- you create
fig = make_subplots(rows=len(float_range_list), cols=1)
then in loop overwrite it withfig = px.line()
. Changed to use variable namefig_
for figure created within loop - also then added traces from
fig_
tofig
within loop
import plotly.express as px
import plotly.graph_objs as go
from plotly.subplots import make_subplots
import pandas as pd
import numpy as np
def create_model(a,fraction=.1):
return 1
def assign_model(n):
return pd.DataFrame({"timestamp":pd.date_range("1-mar-2022", freq="1H", periods=100),
"value":np.random.uniform(1,10,100),
"Anomaly":np.full(100, 1)})
start = 0.01
stop = 0.26
step = 0.05
float_range_array = np.arange(start, stop, step)
float_range_list = list(float_range_array)
fig = make_subplots(rows=len(float_range_list), cols=1)
for x1, i in enumerate(float_range_list):
iforest1 = create_model("pca", fraction=i)
iforest_results = assign_model(iforest1)
fig_ = px.line(
iforest_results,
x="timestamp",
y="value",
title="Principal Component Analysis: Fraction={}".format(round(i, 2)),
template="plotly",
labels={"timestamp": "Stay Date", "value": "Number of Bookings"},
)
outlier_dates = iforest_results[iforest_results["Anomaly"] == 1].index
outlier_dates1 = iforest_results.iloc[outlier_dates]["timestamp"]
y_values = [iforest_results.loc[i]["value"] for i in outlier_dates]
fig.add_trace(
go.Scatter(
x=outlier_dates1,
y=y_values,
mode="markers",
name="Anomaly",
marker=dict(color="red", size=6),
),
row=x1 + 1,
col=1,
)
for t in fig_.data:
fig.add_trace(t, row=x1+1,col=1)
fig.show()
how to loop to create subplots in Plotly, where each subplot has a few curves on it?
To use subplots in plotly you need to:
- use
make_subplots
to initialize the layout specifying therow
andcolumn
- then use
row
andcol
as arguments tofig.add_trace
. NOTE: subplots row and columns start at 1 (not zero)
In your case, step2 is where you are getting stuck. Initially this part was missing (first post), but now in your update it's added in as an argument to go.Scatter
. Carefully look over the examples here as the differences are just commas and parentheses and their placement.
To clarify, this:
fig.add_trace(go.Scatter(x=month,
y=workingGasVolume_peryear,
name=f'workingGasVolume{year}',
row=i,
col=1,
line=dict(width=4,dash='dash')))
should be:
fig.add_trace(go.Scatter(x=month,
y=workingGasVolume_peryear,
name=f'workingGasVolume{year}',
line=dict(width=4,dash='dash')),
row=i+1,
col=1)
I'm having difficulty with your code and data, which could be on my end as I do not use dictionaries like this, but here is a working example with your data in a csv and the use of pandas
. Also, I changed one of the years to a different country so that there would be another plot.
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
df = pd.read_csv('someData.csv')
countries = df.country.unique()
# STEP 1
fig = make_subplots(
rows=len(countries), cols=1,
subplot_titles=(countries))
for i, country in enumerate(countries): #enumerate here to get access to i
years = df.year[df.country==country].unique()
for yrs in years:
focus = (df.country==country) & (df.year==yrs)
month = df.month[focus]
workingGasVolume_peryear = df.workingGasVolume[focus]
gasInStorage_peryear = df.gasInStorage[focus]
# STEP 2, notice position of arguments!
fig.add_trace(go.Scatter(x=month,
y=workingGasVolume_peryear,
name=f'workingGasVolume{yrs}',
line=dict(width=4,dash='dash')
),
row=i+1, #index for the subplot, i+1 because plotly starts with 1
col=1)
fig.add_trace(go.Scatter(x=month,
y=gasInStorage_peryear,
name=f'gasInStorage{yrs}',
line = dict(width=4)),
row=i+1,
col=1)
fig.show()
Plotly: How to use for loop or list for name attribute in bar charts?
Expected graph is like the legends(ie the name attribute 'Domain A'
,'Domain B', 'Domain C' etc should come in x-axisand the status such
as 'Completed' , 'Not completed' etc should come in the legends or the
name attribute for the bar chart.
Like this?
I would like to achieve this within the for loop, is that possible ?
It probably is. But there are much easier ways to get what you want. Take a look at one of the many great answer to the question Pandas: How to find percentage of group members type per subgroup? to see how you can cut your code down to one or two lines. And then build a complete plotly figure with a few additional lines like this:
# data restructuring
df_ply = pd.crosstab(df['Domain'], df['Course1 completion'], normalize='index')
# plotly setup
fig = go.Figure()
# add trace for eat
for col in df_ply.columns:
#print(col)
fig.add_trace(go.Bar(x=df_ply.index, y=df_ply[col], name = col))
fig.update_layout(title=dict(text='Completion status per domain'))
fig.show()
This loops through the columns of the re-structured dataframe and adds a column per Course1 Completion
status and displays them per Domain
.
Complete code with data:
# imports
import pandas as pd
import plotly.graph_objects as go
from plotly.graph_objs import Pie, Layout,Figure
import plotly.offline as py
# data
df = pd.DataFrame({'HC No.': {0: 1,
1: 2,
2: 3,
3: 4,
4: 5,
5: 6,
6: 7,
7: 8,
8: 9,
9: 10,
10: 11,
11: 12,
12: 13,
13: 14,
14: 15,
15: 16,
16: 17,
17: 18,
18: 19,
19: 20,
20: 21,
21: 22,
22: 23,
23: 24,
24: 25,
25: 26},
'Domain': {0: 'Domain A',
1: 'Domain A',
2: 'Domain A',
3: 'Domain A',
4: 'Domain A',
5: 'Domain B',
6: 'Domain B',
7: 'Domain B',
8: 'Domain B',
9: 'Domain B',
10: 'Domain B',
11: 'Domain C',
12: 'Domain C',
13: 'Domain C',
14: 'Domain C',
15: 'Domain C',
16: 'Domain D',
17: 'Domain D',
18: 'Domain D',
19: 'Domain D',
20: 'Domain D',
21: 'Others',
22: 'Others',
23: 'Others',
24: 'Others',
25: 'Others'},
'Project': {0: 'Dog',
1: 'Dog',
2: 'Cat',
3: 'Cat',
4: 'Bird',
5: 'Tree',
6: 'Tree',
7: 'Plant',
8: 'Seed',
9: 'Seed',
10: 'Soil',
11: 'Liquid',
12: 'Solid',
13: 'Solid',
14: 'Solid',
15: 'Gas',
16: 'Gas',
17: 'Gas',
18: 'Gas',
19: 'Slime',
20: 'Slime',
21: 'Metal',
22: 'Metal',
23: 'wood',
24: 'wood',
25: 'Plastic'},
'Sub Project\n': {0: '',
1: '',
2: '',
3: '',
4: '',
5: '',
6: '',
7: '',
8: '',
9: '',
10: '',
11: '',
12: '',
13: '',
14: '',
15: '',
16: '',
17: '',
18: '',
19: '',
20: '',
21: '',
22: '',
23: '',
24: '',
25: ''},
'Emp Name': {0: 'Associate 1',
1: 'Associate 2',
2: 'Associate 3',
3: 'Associate 4',
4: 'Associate 5',
5: 'Associate 6',
6: 'Associate 7',
7: 'Associate 8',
8: 'Associate 9',
9: 'Associate 10',
10: 'Associate 11',
11: 'Associate 12',
12: 'Associate 13',
13: 'Associate 14',
14: 'Associate 15',
15: 'Associate 16',
16: 'Associate 17',
17: 'Associate 18',
18: 'Associate 19',
19: 'Associate 20',
20: 'Associate 21',
21: 'Associate 22',
22: 'Associate 23',
23: 'Associate 24',
24: 'Associate 25',
25: 'Associate 26'},
'Education mark': {0: '1,46975374',
1: '0,4285622',
2: '1,13064316',
3: '1,29683695',
4: '1,18009194',
5: '1,99',
6: '0,73110463',
7: '1,08737382',
8: '1,72600086',
9: '0,35357572',
10: '0,19593062',
11: '1,96790904',
12: '1,02216422',
13: '1,92464914',
14: '1,57124406',
15: '1,65805295',
16: '0,19593062',
17: '0',
18: '0,93860653',
19: '0,41443375',
20: '0,90421186',
21: '1,54062763',
22: '1,3367975',
23: '0,41977105',
24: '1,99',
25: '1,99'},
'Course1 completion': {0: 'Completed',
1: 'Completed',
2: 'Completed',
3: 'Not Completed',
4: 'Completed',
5: 'Not Completed',
6: 'Completed',
7: 'Completed',
8: 'Not Completed',
9: 'Completed',
10: "Planned in Q4 FY'20",
11: 'Completed',
12: 'Completed',
13: 'Not Completed',
14: 'Not Required',
15: 'Completed',
16: 'Completed',
17: 'Not Required',
18: 'Completed',
19: 'Completed',
20: 'Completed',
21: 'Not Completed',
22: 'Not Completed',
23: 'Completed',
24: 'Completed',
25: 'Not Completed'},
'Course2 completion': {0: 'Completed',
1: 'Completed',
2: '',
3: '',
4: '',
5: '',
6: '',
7: '',
8: '',
9: '',
10: '',
11: '',
12: '',
13: '',
14: '',
15: '',
16: 'Completed',
17: '',
18: '',
19: 'Completed',
20: '',
21: '',
22: '',
23: '',
24: '',
25: ''}})
# data restructuring
df_ply = pd.crosstab(df['Domain'], df['Course1 completion'], normalize='index')
# plotly setup
fig = go.Figure()
# add trace for eat
for col in df_ply.columns:
#print(col)
fig.add_trace(go.Bar(x=df_ply.index, y=df_ply[col], name = col))
fig.update_layout(title=dict(text='Completion status per domain'))
fig.show()
Create Plotly plot for each column in df with a 'for' loop
You can add the plots to a dict like
plots = {i: px.scatter(df, x="A", y=i) for i in df.columns}
which is equivalent but shorter than
plots = {}
for i in df.columns:
plots[i] = px.scatter(df, x="A", y=i)
and then you can show each plot with plots['A']
, plots['B']
and plots['C']
How do I loop over multiple figures in plotly?
Approach
There are a number of ways you can do this. The real challenge is rather how to reference them later. Here's how you do it:
- Slice your dataframe using
frames = df['a'].unique()
, - loop through your subsets using
for i, f in enumerate(frames):
, - build figures as normal using
fig=go.Figure()
- add each new figure to a dictionary using
figs['fig'+str(i)] = fig
Now you can reference and show, for example, figure 1
using:
figs['fig1'].show()
Plot
Complete code
import pandas as pd
from plotly import graph_objects as go
df = pd.DataFrame({
"a": ["a1", "a1", "a1", "a2", "a2", "a2", "a3", "a3", "a3"],
"b": ["b1", "b2", "b3", "b1", "b2", "b3", "b1", "b2", "b3"],
"c": [10, 20, 30, 40, 50, 60, 80, 90, 100],
"d": [100, 200, 300, 400, 500, 600, 1000, 2000, 3000]
})
frames = df['a'].unique() # use to slice dataframe
figs = {} # container for figures
for i, f in enumerate(frames, start = 1):
di = df[df['a']==f]
fig = go.Figure()
fig.add_bar(name = "ccc", x=di.b, y=di.c)
fig.add_bar(name = "ddd", x=di.b, y=di.d)
fig.update_layout(barmode='group', title="fig" + str(i) + " for a" + str(i))
figs['fig'+str(i)] = fig
figs['fig1'].show()
Plotly displayed nothing when using for loop in a notebook
I don't know why first version shows without fig.show()
but sencond not but mostly using matplotlib
or plotly
or other module (in script, python's shell or notebook) I have to use fig.show()
(or plt.show()
for matplotlib
) to see plot.
After changing few mistakes - y = data[i]
instead of y = data[:, i]
and range(3)
instead ofrange(0, 2)
- this code works for me in notebook
from random import randint
import plotly.graph_objects as go
x1 = [randint(0, 9) for p in range(10)]
x2 = [randint(0, 9) for p in range(10)]
x3 = [randint(0, 9) for p in range(10)]
time = list(range(len(x1)))
data = [x1, x2, x3]
fig = go.Figure()
for i in range(3):
fig.add_trace(go.Scatter(x=time, y=data[i], mode='markers+lines', name='X{}'.format(i)))
fig.show()
Related Topics
How to Create a R Timeseries for Hourly Data
How to Not Run an Example Using Roxygen2
Split a String Vector at Whitespace
Calculating Weighted Mean and Standard Deviation
Why Do Logicals (Booleans) in R Require 4 Bytes
How to Extract a Few Random Rows from a Data.Table on the Fly
How to Replace Empty String with Na in R Dataframe
Copy/Move One Environment to Another
Ggplot2: Different Legend Symbols for Points and Lines
Minimal Example of Rpy2 Regression Using Pandas Data Frame
Dynamic Position for Ggplot2 Objects (Especially Geom_Text)
R Scoping: Disallow Global Variables in Function
K-Means Clustering in R on Very Large, Sparse Matrix
Count Consecutive Numbers in a Vector
Range Join Data.Frames - Specific Date Column with Date Ranges/Intervals in R