I've scowled the internet and tried various ways to create a subplot with three scatterpolar plots and three bar plots.
I've come down to this...
Let's say I have three dataframes that I filtered from another database to gives me data for students and how much they completed each category. We'll use the ones below as an example of all three:
import pandas as pd
pd.set_option('display.max_rows', None)
# Run this app with `python app.py`
from dash import Dash, dcc, html
#import plotly.express as px
from plotly.subplots import make_subplots
from plotly import graph_objects as go
import dash_bootstrap_components as dbc
import pandas as pd
Dash(assets_ignore='.*ignored.*')
app = Dash(__name__)
# neglect false warnings
pd.options.mode.chained_assignment = None # default='warn'
# color dictionary
class RangeDict(dict):
def __getitem__(self, item):
if not isinstance(item, range):
for key in self:
if item in key:
return self[key]
raise KeyError(item)
else:
return super().__getitem__(item)
grade_colors = RangeDict({
range(0,60): 'crimson',
range(60,70): '#E34363',
range(70,80): '#FFB733',
range(80,90): '#29CC92',
range(90,101): '#339933'})
colors = {
'background': '#111111',
'text': 'teal',
"0":"silver",
"1":"#FBEC5D",
"5":"#50C878",
"10":"#40E0D0",
"15":"#A23D60",
0:"silver",
1:"#FBEC5D",
5:"#50C878",
10:"#40E0D0",
15:"#A23D60",
'Linux':'#50C878',
'Windows':'#66D3F4',
'Primer':'#FFD700',
}
# pandas dataframe used for plots
students_category_earned = pd.DataFrame({
'Category': ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J','A','A','B','B','C','C'],
'completed' : [ 55 , 55 , 100 , 95 , 45 , 99 , 75 , 64 , 93 , 10 , 15 , 55 , 45 , 78 , 98 , 33 ],
'platform' : ['primer','primer','primer','primer','primer','primer','primer','primer', 'primer', 'primer','Linux','Windows','Linux','Windows','Linux','Windows']
})
print( students_category_earned )
print(" - "*9)
print(students_category_earned)
students_topics_earned = pd.DataFrame({
'topic': ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J','A','A','B','B','C','C'],
'completed' : [ 55 , 55 , 100 , 95 , 45 , 99 , 75 , 64 , 93 , 10 , 15 , 55 , 45 , 78 , 98 , 33 ],
'platform' : ['primer','primer','primer','primer','primer','primer','primer','primer', 'primer', 'primer','Linux','Windows','Linux','Windows','Linux','Windows']
})
print("students_topics_earned")
print("-"*9)
print(students_topics_earned)
# functions to creating the plots
def student_category_bar_grade(df,platform):
df_filtered = df[df['platform']==platform].sort_values(by='Category',ascending=True)
fig = go.Figure()
for completed,sdf in df_filtered.groupby('completed'):
color = grade_colors[completed]
fig.add_traces(
go.Bar(x=sdf['Category'],
y=sdf['completed'],
customdata=sdf['platform'],
name=str(completed)+" %",
marker={'color': color},
hovertemplate="<br>".join([
"Platform: %{customdata}",
"Category: %{x}",
]),
)
)
# Change the bar mode
fig.update_layout(title_text=platform)
fig.update_layout(barmode='group',
plot_bgcolor=colors['background'],
paper_bgcolor=colors['background'],
font_color=colors['text']
)
fig.update_layout(showlegend=False)
fig.update_layout(
title_x=0.5,
title_font_size=26,
title_font_family="Copperplate",
title_font_color="teal",
)
return fig
def student_topic_scatter_polar_graph(df,platform):
df_filtered = df[df['platform']==platform].sort_values(by='topic',ascending=True)
color = colors[platform]
fig = go.Scatterpolar(
r=df_filtered.completed,
theta=df_filtered.topic,
fill='toself',
name="%s - Focused Topics"%platform,
fillcolor=color,
opacity=0.6,
line=dict(color=color)
)
return fig
# calling the plot functinos
linux_category_bar_fig = student_category_bar_grade(students_category_earned,'Linux')
windows_category_bar_fig = student_category_bar_grade(students_category_earned,'Windows')
primer_category_bar_fig = student_category_bar_grade(students_category_earned,'Primer')
linux_topic_scatter_polar_fig = student_topic_scatter_polar_graph(students_topics_earned,'Linux')
windows_topic_scatter_polar_fig = student_topic_scatter_polar_graph(students_topics_earned,'Windows')
primer_topic_scatter_polar_fig = student_topic_scatter_polar_graph(students_topics_earned,'Primer')
#create subplot
student_subplot = make_subplots(rows=2, cols=3,
specs=[[{"type": "scatterpolar"}, {"type": "scatterpolar"}, {"type": "scatterpolar"}],
[{"type": "bar"}, {"type": "bar"}, {"type": "bar"}]] )
figure1_traces = []
figure2_traces = []
figure3_traces = []
# combine the figs to the subplot
for trace in range(len(linux_category_bar_fig["data"])):
figure1_traces.append(linux_category_bar_fig["data"][trace])
for trace in range(len(windows_category_bar_fig["data"])):
figure2_traces.append(windows_category_bar_fig["data"][trace])
for trace in range(len(primer_category_bar_fig["data"])):
figure3_traces.append(primer_category_bar_fig["data"][trace])
student_subplot.add_trace(linux_topic_scatter_polar_fig,row=1,col=1)
student_subplot.add_trace(windows_topic_scatter_polar_fig,row=1,col=2)
student_subplot.add_trace(primer_topic_scatter_polar_fig,row=1,col=3)
student_subplot.add_trace(figure1_traces,row=1,col=1)
student_subplot.add_trace(figure1_traces,row=1,col=2)
student_subplot.add_trace(figure1_traces,row=1,col=3)
# creating card that the subplots will be in
card = dbc.Card(
[
dbc.CardBody([
html.H4("Student Name", className="card-title"),
dcc.Graph(figure=student_subplot),
])
]
)
app.layout = html.Div([
card
],
)
if __name__ == '__main__':
app.run_server(host="0.0.0.0", port=8070, debug=True)
but I keep getting an error about the 'data' property of the trace...I cannot figure it out.. could someone help me understand how to combine the two different types of plots in a 'make_subplot' ?
ALSO…the end result is supposed to look something like this…
sorry for the terrible depiction.

