问题
I need to create a combination of "relative" and "grouped" chart in plotly.
I figured out how to create stacked and grouped by using this code:
from plotly import graph_objects as go
import plotly
pyplt = plotly.offline.plot
data = {
"Sports_19": [15, 23, 32, 10, 23, 22, 32, 24],
"Casual_19": [4, 12, 11, 14, 15, 12, 22, 14],
"Yoga_19": [4, 8, 18, 6, 12, 11, 10, 4],
"Sports_20": [11, 18, 18, 0, 20, 12, 12, 11],
"Casual_20": [20, 10, 9, 6, 10, 11, 17, 22],
"Yoga_20": [11, 18, 18, 0, 20, 12, 12, 11],
"labels": ["January", "February", "March", "April", "May", 'June', 'July', "August"]
}
fig = go.Figure()
fig.add_trace(go.Bar(name="Sports",x=data["labels"],y=data["Sports_19"],offsetgroup=19,marker_color='lightsalmon',text=data["Sports_19"],textposition='auto'))
fig.add_trace(go.Bar(name="Casual",x=data['labels'],y=data['Casual_19'],offsetgroup=19,base=data['Sports_19'],marker_color='crimson',text=data["Casual_19"],textposition='auto'))
fig.add_trace(go.Bar(name="Yoga",x=data['labels'],y=data['Yoga_19'],marker_color='indianred',text=data["Yoga_19"],textposition='auto',offsetgroup=19,base=[val1 + val2 for val1, val2 in zip(data["Sports_19"], data["Casual_19"])]))
fig.add_trace(go.Bar(name="Sports_20",x=data["labels"],y=data["Sports_20"],offsetgroup=20,marker_color='lightsalmon',showlegend=False,text=data["Sports_20"],textposition='auto'))
fig.add_trace(go.Bar(name="Casual_20",x=data['labels'],y=data['Casual_20'],offsetgroup=20,base=data['Sports_20'],marker_color='crimson',showlegend=False,text=data["Casual_20"],textposition='auto'))
fig.add_trace(go.Bar(name="Yoga_20", x=data['labels'], y=data['Yoga_20'], marker_color='indianred', text=data["Yoga_20"], showlegend=False, textposition='auto', offsetgroup=20, base=[val1 + val2 for val1, val2 in zip(data["Sports_20"], data["Casual_20"])]))
fig.update_layout(title="2019 vs 2020 Sales by Category",yaxis_title="Sales amount in US$")
fig.show()
pyplt(fig, auto_open=True)
Output is this:
Is there is any way i can convert this graph to combination of "relative" and "grouped"? May be not with plotly, but with matplotlib or another tools?
p.s. Here is the example of "relative graph"(but its not grouped):
回答1:
Probably the most straightforward way is to create two new dataframes df_perc_19
and df_perc_20
to store your data, normalized to relative percentages for each month in each year, rounding off to two digits using .round(2)
since a long decimal will cause the default direction of the text to change - feel free to adjust this however you like.
Then access the values in these new dataframes for your traces, and although it's ugly, you can get percentages to display for the text
parameter using something like: text=[str(x)+"%" for x in df_perc_19["Casual_19"]]
import pandas as pd
import plotly
from plotly import graph_objects as go
# pyplt = plotly.offline.plot
data = {
"Sports_19": [15, 23, 32, 10, 23, 22, 32, 24],
"Casual_19": [4, 12, 11, 14, 15, 12, 22, 14],
"Yoga_19": [4, 8, 18, 6, 12, 11, 10, 4],
"Sports_20": [11, 18, 18, 0, 20, 12, 12, 11],
"Casual_20": [20, 10, 9, 6, 10, 11, 17, 22],
"Yoga_20": [11, 18, 18, 0, 20, 12, 12, 11],
# "labels": ["January", "February", "March", "April", "May", 'June', 'July', "August"]
}
labels = ["January", "February", "March", "April", "May", 'June', 'July', "August"]
df = pd.DataFrame(data=data,index=labels)
## normalize data for the months of 2019, and the months of 2020
df_perc_19 = df.apply(lambda x: 100*x[["Sports_19","Casual_19","Yoga_19"]] / x[["Sports_19","Casual_19","Yoga_19"]].sum(),axis=1).round(2)
df_perc_20 = df.apply(lambda x: 100*x[["Sports_20","Casual_20","Yoga_20"]] / x[["Sports_20","Casual_20","Yoga_20"]].sum(),axis=1).round(2)
fig = go.Figure()
## traces for 2019
fig.add_trace(go.Bar(name="Sports",x=labels,y=df_perc_19["Sports_19"],offsetgroup=19,marker_color='lightsalmon',text=[str(x)+"%" for x in df_perc_19["Sports_19"]],textposition='auto'))
fig.add_trace(go.Bar(name="Casual",x=labels,y=df_perc_19['Casual_19'],offsetgroup=19,base=df_perc_19['Sports_19'],marker_color='crimson',text=[str(x)+"%" for x in df_perc_19["Casual_19"]],textposition='auto'))
fig.add_trace(go.Bar(name="Yoga",x=labels,y=df_perc_19['Yoga_19'],marker_color='indianred',text=[str(x)+"%" for x in df_perc_19["Yoga_19"]],textposition='auto',offsetgroup=19,base=[val1 + val2 for val1, val2 in zip(df_perc_19["Sports_19"], df_perc_19["Casual_19"])]))
## traces for 2020
fig.add_trace(go.Bar(name="Sports_20",x=labels,y=df_perc_20["Sports_20"],offsetgroup=20,marker_color='lightsalmon',showlegend=False,text=[str(x)+"%" for x in df_perc_20["Sports_20"]] ,textposition='auto'))
fig.add_trace(go.Bar(name="Casual_20",x=labels,y=df_perc_20['Casual_20'],offsetgroup=20,base=df_perc_20['Sports_20'],marker_color='crimson',showlegend=False,text=[str(x)+"%" for x in df_perc_20["Casual_20"]],textposition='auto'))
fig.add_trace(go.Bar(name="Yoga_20", x=labels, y=df_perc_20['Yoga_20'], marker_color='indianred', text=[str(x)+"%" for x in df_perc_20["Yoga_20"]], showlegend=False, textposition='auto', offsetgroup=20, base=[val1 + val2 for val1, val2 in zip(df_perc_20["Sports_20"], df_perc_20["Casual_20"])]))
fig.update_layout(title="2019 vs 2020 Sales by Category",yaxis_title="Sales amount in US$ (percentage)")
fig.show()
# pyplt(fig, auto_open=True)
来源:https://stackoverflow.com/questions/63772597/create-a-combination-of-relative-and-grouped-chart-in-python