3

I am wondering what is best practice to create subplots using Python Plotly. Is it to use plotly.express or the standard plotly.graph_objects?

I'm trying to create a figure with two subplots, which are stacked bar charts. The following code doesn't work. I didn't find anything useful in the official documentation. The classic Titanic dataset was imported as train_df here.

import plotly.express as px

train_df['Survived'] = train_df['Survived'].astype('category')
fig1 = px.bar(train_df, x="Pclass", y="Age", color='Survived')
fig2 = px.bar(train_df, x="Sex", y="Age", color='Survived')

trace1 = fig1['data'][0]
trace2 = fig2['data'][0]

fig = make_subplots(rows=1, cols=2, shared_xaxes=False)
fig.add_trace(trace1, row=1, col=1)
fig.add_trace(trace2, row=1, col=2)

fig.show()

I got the following figure:

enter image description here

What I expect is as follows:

enter image description here

3
  • Hi! and welcome to the forum! There are surprisingly many aspects of your short snippet that leaves me a bit puzzled. First of all, what are you aiming to show in fig1? It seems to me that what you would get here is the sum of the age for each class, split by whether or not they survived. Or am I missing something here? Maybe that's not really important, and you would just like to know how to do these things? Commented Jan 27, 2020 at 11:10
  • @WangShengdao How did my suggestion work out for you? Commented Jan 28, 2020 at 11:21
  • 1
    Hi @vestland! Thanks for your reply. I'm currently exploring plotly to replace the seaborn I've been using. To be more clear, I'd like to know how to create subplots with stacked bar charts, as well as when to use plotly.express and plotly.graph_objects. Your solution does help! Commented Jan 28, 2020 at 12:27

3 Answers 3

1

I'm hoping that the existing answer suits your needs, but I'd just like to note that the statement

it's not possible to subplot stakedbar (because stacked bar are in facted figures and not traces

is not entirely correct. It's possible to build a plotly subplot figure using stacked bar charts as long as you put it together correctly using add_trace() and go.Bar(). And this also answers your question regarding:

I am wondering what is best practice to create subplots using Python Plotly. Is it to use plotly.express or the standard plotly.graph_objects?

Use plotly.express ff you find a px approach that suits your needs. And like in your case where you do not find it; build your own subplots using plotly.graphobjects.

Below is an example that will show you one such possible approach using the titanic dataset. Note that the column names are noe the same as yours since there are no capital letters. The essence of this approav is that you use go.Bar() for each trace, and specify where to put those traces using the row and col arguments in go.Bar(). If you assign multiple traces to the same row and col, you will get stacked bar chart subplots if you specify barmode='stack' in fig.update_layout(). Usingpx.colors.qualitative.Plotly[i]` will let you assign colors from the standard plotly color cycle sequentially.

Plot:

enter image description here

Code:

from plotly.subplots import make_subplots
import plotly.graph_objects as go
import plotly.express as px
import pandas as pd

url = "https://raw.github.com/mattdelhey/kaggle-titanic/master/Data/train.csv"
titanic = pd.read_csv(url)
#titanic.info()
train_df=titanic
train_df

# data for fig 1
df1=titanic.groupby(['sex', 'pclass'])['survived'].aggregate('mean').unstack()

# plotly setup for fig
fig = make_subplots(2,1)
fig.add_trace(go.Bar(x=df1.columns.astype('category'), y=df1.loc['female'],
                     name='female',
                     marker_color = px.colors.qualitative.Plotly[0]),
    row=1, col=1)


fig.add_trace(go.Bar(x=df1.columns.astype('category'), y=df1.loc['male'],
                     name='male',
                     marker_color = px.colors.qualitative.Plotly[1]),
    row=1, col=1)


# data for plot 2
age = pd.cut(titanic['age'], [0, 18, 80])
df2 = titanic.pivot_table('survived', [age], 'pclass')
groups=['(0, 18]', '(18, 80]']

fig.add_trace(go.Bar(x=df2.columns, y=df2.iloc[0],
                     name=groups[0],
                     marker_color = px.colors.qualitative.Plotly[3]),
    row=2, col=1)

fig.add_trace(go.Bar(x=df2.columns, y=df2.iloc[1],
                     name=groups[1],
                     marker_color = px.colors.qualitative.Plotly[4]),
    row=2, col=1)

fig.update_layout(title=dict(text='Titanic survivors by sex and age group'), barmode='stack', xaxis = dict(tickvals= df1.columns))
fig.show()

fig.show()
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks man! I didn't know a single subplot can take multiple traces. This is helpful. I provided an alternative solution as below.
@WangShenghao Happy to help! Thank you for accepting my answer although you came up with a solution yourself (+1)
1

From what I know, it's not possible to subplot stakedbar (because stacked bar are in facted figures and not traces)...

On behalf of fig.show(), you can put to check if the html file is okay for you (The plots are unfortunately one under the other...) :

with open('p_graph.html', 'a') as f:
    f.write(fig1.to_html(full_html=False, include_plotlyjs='cdn',default_height=500))
    f.write(fig2.to_html(full_html=False, include_plotlyjs='cdn',default_height=500))

try the code below to check if the html file generate can be okay for you:

import pandas as pd
import plotly.graph_objects as go

#Remove the .astype('category') to easily 
#train_df['Survived'] = train_df['Survived'].astype('category')
Pclass_pivot=pd.pivot_table(train_df,values='Age',index='Pclass',
                   columns='Survived',aggfunc=lambda x: len(x))
Sex_pivot=pd.pivot_table(train_df,values='Age',index='Sex',
                   columns='Survived',aggfunc=lambda x: len(x))

fig1 = go.Figure(data=[
    go.Bar(name='Survived', x=Pclass_pivot.index.values, y=Pclass_pivot[1]),
    go.Bar(name='NotSurvived', x=Pclass_pivot.index.values, y=Pclass_pivot[0])])

# Change the bar mode
fig1.update_layout(barmode='stack')


fig2 = go.Figure(data=[
    go.Bar(name='Survived', x=Sex_pivot.index.values, y=Sex_pivot[1]),
    go.Bar(name='NotSurvived', x=Sex_pivot.index.values, y=Sex_pivot[0])])
# Change the bar mode
fig2.update_layout(barmode='stack')

with open('p_graph.html', 'a') as f:
    f.write(fig1.to_html(full_html=False, include_plotlyjs='cdn',default_height=500))
    f.write(fig2.to_html(full_html=False, include_plotlyjs='cdn',default_height=500))

1 Comment

Hi I hope to generate the plot in a notebook environment, but it's good to know how to generate plots in html. Thanks for your advice anyway!
1

I managed to generate the subplots using the add_bar function.

Code:

from plotly.subplots import make_subplots

# plotly can only support one legend per graph at the moment.
fig = make_subplots(
    rows=1, cols=2,
    subplot_titles=("Pclass vs. Survived", "Sex vs. Survived")
)
fig.add_bar(
    x=train_df[train_df.Survived == 0].Pclass.value_counts().index,
    y=train_df[train_df.Survived == 0].Pclass.value_counts().values,
    text=train_df[train_df.Survived == 0].Pclass.value_counts().values,
    textposition='auto',
    name='Survived = 0',
    row=1, col=1
)
fig.add_bar(
    x=train_df[train_df.Survived == 1].Pclass.value_counts().index,
    y=train_df[train_df.Survived == 1].Pclass.value_counts().values,
    text=train_df[train_df.Survived == 1].Pclass.value_counts().values,
    textposition='auto',
    name='Survived = 1',
    row=1, col=1
)
fig.add_bar(
    x=train_df[train_df.Survived == 0].Sex.value_counts().index,
    y=train_df[train_df.Survived == 0].Sex.value_counts().values,
    text=train_df[train_df.Survived == 0].Sex.value_counts().values,
    textposition='auto',
    marker_color='#636EFA',
    showlegend=False,
    row=1, col=2
)
fig.add_bar(
    x=train_df[train_df.Survived == 1].Sex.value_counts().index,
    y=train_df[train_df.Survived == 1].Sex.value_counts().values,
    text=train_df[train_df.Survived == 1].Sex.value_counts().values,
    textposition='auto',
    marker_color='#EF553B',
    showlegend=False,
    row=1, col=2
)

fig.update_layout(
    barmode='stack',
    height=400, width=1200,
)
fig.update_xaxes(ticks="inside")
fig.update_yaxes(ticks="inside", col=1)
fig.show()

Resulting plot: Expected stacked bar charts generated using plotly

Hope this is helpful to the newbies of plotly like me.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.