Hello,
I’m trying to develop two grouped bar charts sharing an x-axis and legend but showing a different metric. I’m using a column with hex colors in them to set the colors of bars but I’m getting an error. The code is as such:
fig = go.Figure()
fig = make_subplots(rows=2, cols=1)
fig.append_trace(go.Bar(name='MAPE',
x= df_table["snapshot"],
y=df_table["MAPE"]),
row=1, col=1)
# color="model", barmode="group", title = "MAPE by Snapshot")
fig.append_trace(go.Bar(name='BIAS',
x= df_table["snapshot"],
y=df_table["BIAS"]),
row=2, col=1)
fig.update_layout(barmode='group',
marker_colors=df_final['model_color'],
labels = df_final['model']
)
The error is
ValueError: Invalid property specified for object of type plotly.graph_objs.Layout: 'marker'
What am I doing wrong?
AIMPED
April 12, 2023, 5:45pm
2
The marker is a trace property.
Hence you need to use update_traces, probably in conjunction with the selector parameter or using for_each_trace.
Here an example:
Hi,
you can do so using the selector argument of figure.update_traces()
fig.update_traces({'opacity': 0.5}, selector={'name': 'won'})
fig.update_traces({'opacity': 1.0}, selector={'name': 'lost'})
You could even change the size or marker color the same way:
fig.update_traces({'opacity': 0.5}, selector={'name': 'won'})
fig.update_traces({'opacity': 1.0, 'marker':{'color':'blue','size':10}}, selector={'name': 'lost'})
[newplot (25)]
mrep traces
I tried this:
fig = go.Figure()
fig = make_subplots(rows=2, cols=1)
fig.append_trace(go.Bar(name='MAPE',
x= df_table["snapshot"],
y=df_table["MAPE"]),
row=1, col=1)
# color="model", barmode="group", title = "MAPE by Snapshot")
fig.append_trace(go.Bar(name='BIAS',
x= df_table["snapshot"],
y=df_table["BIAS"]),
row=2, col=1)
fig.update_layout(barmode='group')
fig.update_traces({'marker':{'color':df_final['model_color']}}, selector={'name': df_final['model']})
But I get this:
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
AIMPED
April 12, 2023, 6:52pm
4
I assume you are expecting, that update_traces is looping over all traces and you apply a color to each trace (with the corresponding name as defined by df_final['model']
) - which is not the case.
Here an example which corresponds to what you are trying to do:
import plotly.graph_objects as go
import numpy as np
colors = ['red', 'green', 'blue']
names = ['A', 'B', 'C']
def data():
return np.random.randint(2, 10, 10)
fig = go.Figure()
for name in range(3):
fig.add_bar(x=np.arange(10), y=data(), name=name, marker_color='orange')
fig.show()
Now we change the marker colors:
it_colors = iter(colors)
fig.for_each_trace(lambda x: x.update(marker_color=next(it_colors)))
I think I may have done something wrong. Here is my callback function:
colors = ['azure', 'cornflowerblue', 'darkcyan', 'darkgreen', 'darkorange', 'darkslategrey', 'gainsboro']
names = df_table['model'].unique()
fig = go.Figure()
fig = make_subplots(rows=2, cols=1)
for name in names:
fig.add_bar(x=df_table[df_table['model']==name]['snapshot'],
y = df_table[df_table['model']==name]['MAPE'],
name=name,
row=1, col=1)
fig.add_bar(x=df_table[df_table['model']==name]['snapshot'],
y = df_table[df_table['model']==name]['BIAS'],
name=name,
row=2, col=1)
it_colors = iter(colors)
fig.for_each_trace(lambda x: x.update(marker_color=next(it_colors)))
But now I’m getting this:
Traceback (most recent call last):
File "/workspace/test.py", line 311, in time_series_show_snapshot
fig.for_each_trace(lambda x: x.update(marker_color=next(it_colors)))
File "/app/.heroku/python/lib/python3.7/site-packages/plotly/graph_objs/_figure.py", line 823, in for_each_trace
return super(Figure, self).for_each_trace(fn, selector, row, col, secondary_y)
File "/app/.heroku/python/lib/python3.7/site-packages/plotly/basedatatypes.py", line 1298, in for_each_trace
fn(trace)
File "/workspace/test.py", line 311, in <lambda>
fig.for_each_trace(lambda x: x.update(marker_color=next(it_colors)))
StopIteration
AIMPED
April 17, 2023, 7:23pm
6
Hi @jbh1128d1 you get this error because the iterator colors
is exhausted.
You add len(names)
x 2 traces, but len(colors)
is only the half of it.
Looking at your callback:
Why don’t you specify the color in the first place when adding the tarces? Like this:
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import numpy as np
colors = ['red', 'green', 'blue']
names_1 = list('ABC')
names_2 = list('DEF')
def data():
return np.random.randint(2, 10, 10)
fig = make_subplots(rows=2, cols=1)
for n_1, n_2, color in zip(names_1, names_2, colors):
fig.add_traces(go.Bar(x=np.arange(10), y=data(), name=n_1, marker_color=color), rows=1, cols=1)
fig.add_traces(go.Bar(x=np.arange(10), y=data(), name=n_2, marker_color=color), rows=2, cols=1)
fig.show()
1 Like
Thank you. I got it to show up but have double the legend values because both MAPE and BIAS have the same model values. See below:
How can I get only one legend value per model to show that will control both graphs?
I FIGURED IT OUT!!!
I used legendgroups=name
.
fig = go.Figure()
fig = make_subplots(rows=2, cols=1)
for name, color in zip(names, colors):
fig.add_traces(go.Bar(x=df_table[df_table['model']==name]['snapshot'],
y = df_table[df_table['model']==name]['MAPE'],
name=name, marker_color=color,
showlegend=True,
legendgroup=name),
rows=1, cols=1)
fig.add_traces(go.Bar(x=df_table[df_table['model']==name]['snapshot'],
y = df_table[df_table['model']==name]['BIAS'],
name=name, marker_color=color,
showlegend=False,
legendgroup=name),
rows=2, cols=1,
)
Thank you for all the help!
1 Like