How is it possible to manipulate the spacing between rows(e.g. increasing the space between fist two rows and final two rows) and the size of charts inside the figure (e.g. making pie chart bigger)?
In my example, I'm trying to visualize multiple data columns from Telco Customer Churn dataset (download 176kB) using plotly's FigureWidget
and make_subplots
.
This code loops through 8 columns, adds 1 pie chart and one bar chart for each column.
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# Read data
df = pd.read_csv("./WA_Fn-UseC_-Telco-Customer-Churn.csv")
df['SeniorCitizen'] = df['SeniorCitizen'].map({0: 'No', 1: 'Yes'})
# Define subplot titles and data columns
data_cols = ['PhoneService' ,'MultipleLines' ,'InternetService' ,'OnlineBackup' ,'DeviceProtection' ,'TechSupport' ,'StreamingTV' ,'StreamingMovies']
titles = ['Phone Service' ,'Multiple Lines' ,'Internet Service' ,'Online Backup' ,'Device Protection' ,'Tech Support' ,'Streaming TV' ,'Streaming Movies']
fig = go.FigureWidget(make_subplots(rows=4, cols=4, specs=[
[{'type':'domain'}, {'type':'domain'}, {'type':'domain'}, {'type':'domain'}],
[{'type':'xy'}, {'type':'xy'}, {'type':'xy'}, {'type':'xy'}],
[{'type':'domain'}, {'type':'domain'}, {'type':'domain'}, {'type':'domain'}],
[{'type':'xy'}, {'type':'xy'}, {'type':'xy'}, {'type':'xy'}]]))
row, col = 1, 0
for i, (title, data_col) in enumerate(zip(titles, data_cols)):
row, col = divmod(i, 4)
row = row * 2
# Get value counts for pie chart
value_counts = df[data_col].value_counts()
# Create pie chart trace and add to subplot
pie_chart = go.Pie(labels=value_counts.index, values=value_counts.to_numpy(), name=title, title=title)
fig.add_trace(pie_chart, row=row+1, col=col+1)
# get churn rates
churn_counts = df.groupby([data_col, 'Churn'])['Churn'].count().unstack()
# Create stacked bar charts
t1 = go.Bar(name='Churn (yes)', x=churn_counts['Yes'].index, y=churn_counts['Yes'])
t2 = go.Bar(name='Churn (no)', x=churn_counts['No'].index, y=churn_counts['No'], marker_color='indianred')
fig.add_trace(t1, row=row+2, col=col+1)
fig.add_trace(t2, row=row+2, col=col+1)
fig.update_layout(title="Distribution of Customer Services", barmode='stack', showlegend=False)
fig.show()
Edit: this issue is not fixed with decreasing the number of columns to two either. this is the chart on a large wide screen:
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# Read data
df = pd.read_csv("./WA_Fn-UseC_-Telco-Customer-Churn.csv")
df['SeniorCitizen'] = df['SeniorCitizen'].map({0: 'No', 1: 'Yes'})
# Define subplot titles and data columns
data_cols = ['PhoneService' ,'MultipleLines' ,'InternetService' ,'OnlineBackup' ,'DeviceProtection' ,'TechSupport' ,'StreamingTV' ,'StreamingMovies']
titles = ['Phone Service' ,'Multiple Lines' ,'Internet Service' ,'Online Backup' ,'Device Protection' ,'Tech Support' ,'Streaming TV' ,'Streaming Movies']
fig = go.FigureWidget(make_subplots(rows=8, cols=2, specs=[
[{'type':'domain'}, {'type':'domain'}],
[{'type':'xy'}, {'type':'xy'}],
[{'type':'domain'}, {'type':'domain'}],
[{'type':'xy'}, {'type':'xy'}],
[{'type':'domain'}, {'type':'domain'}],
[{'type':'xy'}, {'type':'xy'}],
[{'type':'domain'}, {'type':'domain'}],
[{'type':'xy'}, {'type':'xy'}]]))
row, col = 1, 0
for i, (title, data_col) in enumerate(zip(titles, data_cols)):
row, col = divmod(i, 2)
row = row * 2
# Get value counts for pie chart
value_counts = df[data_col].value_counts()
# Create pie chart trace and add to subplot
pie_chart = go.Pie(labels=value_counts.index, values=value_counts.to_numpy(), name=title, title=title)
fig.add_trace(pie_chart, row=row+1, col=col+1)
# get churn rates
churn_counts = df.groupby([data_col, 'Churn'])['Churn'].count().unstack()
# Create stacked bar charts
t1 = go.Bar(name='Churn (yes)', x=churn_counts['Yes'].index, y=churn_counts['Yes'])
t2 = go.Bar(name='Churn (no)', x=churn_counts['No'].index, y=churn_counts['No'], marker_color='indianred')
fig.add_trace(t1, row=row+2, col=col+1)
fig.add_trace(t2, row=row+2, col=col+1)
fig.update_layout(title="Distribution of Customer Services", barmode='stack', showlegend=False)
fig.show()
The spacing between rows and columns can be adjusted with vertical_spacing
and horizontal_spacing
arguments respectively. Both can have a float value between 0 and 1/(size -1)
. It takes some tinkering to find the right value that suits you. To maximize the size of the charts within the figure you can update the margin
argument within the fig.update_layout
call. All four sides are referred to in a dictionary with the keys: t
, b
, l
and r
.
The code below is an alteration of yours that using all these arguments.
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
# Read data
df = pd.read_csv(".../WA_Fn-UseC_-Telco-Customer-Churn.csv")
df['SeniorCitizen'] = df['SeniorCitizen'].map({0: 'No', 1: 'Yes'})
# Define subplot titles and data columns
data_cols = ['PhoneService' ,'MultipleLines' ,'InternetService' ,'OnlineBackup' ,'DeviceProtection' ,'TechSupport' ,'StreamingTV' ,'StreamingMovies']
titles = ['Phone Service' ,'Multiple Lines' ,'Internet Service' ,'Online Backup' ,'Device Protection' ,'Tech Support' ,'Streaming TV' ,'Streaming Movies']
hor_space = 0.02
ver_space = 0.02
fig = go.FigureWidget(make_subplots(rows=4,
cols=4,
specs=[[{'type':'domain'}, {'type':'domain'}, {'type':'domain'}, {'type':'domain'}],
[{'type':'xy'}, {'type':'xy'}, {'type':'xy'}, {'type':'xy'}],
[{'type':'domain'}, {'type':'domain'}, {'type':'domain'}, {'type':'domain'}],
[{'type':'xy'}, {'type':'xy'}, {'type':'xy'}, {'type':'xy'}]
],
horizontal_spacing=hor_space, # in range 0 to 1/(cols-1)
vertical_spacing=ver_space # in range 0 to 1/(rows-1)
)
)
row, col = 1, 0
for i, (title, data_col) in enumerate(zip(titles, data_cols)):
row, col = divmod(i, 4)
row = row * 2
# Get value counts for pie chart
value_counts = df[data_col].value_counts()
# Create pie chart trace and add to subplot
pie_chart = go.Pie(labels=value_counts.index, values=value_counts.to_numpy(), name=title, title=title)
fig.add_trace(pie_chart, row=row+1, col=col+1)
# get churn rates
churn_counts = df.groupby([data_col, 'Churn'])['Churn'].count().unstack()
# Create stacked bar charts
t1 = go.Bar(name='Churn (yes)', x=churn_counts['Yes'].index, y=churn_counts['Yes'])
t2 = go.Bar(name='Churn (no)', x=churn_counts['No'].index, y=churn_counts['No'], marker_color='indianred')
fig.add_trace(t1, row=row+2, col=col+1)
fig.add_trace(t2, row=row+2, col=col+1)
fig.update_layout(title="Distribution of Customer Services",
barmode='stack',
showlegend=False,
margin={"l":25,
"r":25,
"t":25,
"b":25}
)
fig.show()
Some background provided by the plotly documentation: