Source: Data Viz Catalogue
$Circle\_Area = \pi + {Radius}^{2}$
$Circle\_Diameter = 2 \sqrt{\frac{Area}{\pi}}$
import math
import pandas as pd
from pandas.api.types import CategoricalDtype
from bokeh.io import output_notebook, show
from bokeh.plotting import figure
from bokeh.transform import transform
from bokeh.models import ColumnDataSource
from bokeh.models.mappers import CategoricalColorMapper
output_notebook()
Dataset comes from Kaggle: Titanic - Suited for binary logistic regression
import kaggle
kaggle.api.authenticate()
kaggle.api.dataset_download_files('heptapod/titanic', path='.', unzip=True)
df = pd.read_csv('train_and_test2.csv', sep=',')
df.rename(columns={'2urvived': 'survived'}, inplace=True)
df['Sex'] = df['Sex'].replace({0: 'Male', 1: 'Female'}).astype('category')
df['Pclass'] = df['Pclass'].replace({1: '1st', 2: '2nd', 3: '3th'}).astype('category')
df['Age'] = pd.cut(df['Age'].round(), 5)
df[['Age', 'Pclass', 'sibsp', 'survived']].sample(10)
| Age | Pclass | sibsp | survived | |
|---|---|---|---|---|
| 516 | (32.0, 48.0] | 2nd | 0 | 1 |
| 29 | (16.0, 32.0] | 3th | 0 | 0 |
| 523 | (32.0, 48.0] | 1st | 0 | 1 |
| 1250 | (16.0, 32.0] | 3th | 1 | 0 |
| 911 | (48.0, 64.0] | 1st | 1 | 0 |
| 161 | (32.0, 48.0] | 2nd | 0 | 1 |
| 723 | (48.0, 64.0] | 2nd | 0 | 0 |
| 972 | (64.0, 80.0] | 1st | 1 | 0 |
| 383 | (32.0, 48.0] | 1st | 1 | 1 |
| 1244 | (48.0, 64.0] | 2nd | 1 | 0 |
aux = df[['Age', 'Pclass', 'sibsp', 'survived']].groupby(by=['Age', 'Pclass']).agg(['sum', 'count']).copy()
aux.reset_index(inplace=True)
aux['Age'] = aux['Age'].astype(str)
aux['percent'] = aux['survived']['sum'] / aux['survived']['count'] * 100
aux['sibsp_area'] = 2 * ((aux['sibsp']['sum'] / aux['sibsp']['count']) / math.pi).pow(1./2)
aux = aux[aux['percent'] > 0]
aux
| Age | Pclass | sibsp | survived | percent | sibsp_area | |||
|---|---|---|---|---|---|---|---|---|
| sum | count | sum | count | |||||
| 0 | (-0.08, 16.0] | 1st | 6 | 11 | 8 | 11 | 72.727273 | 0.833363 |
| 1 | (-0.08, 16.0] | 2nd | 21 | 30 | 19 | 30 | 63.333333 | 0.944070 |
| 2 | (-0.08, 16.0] | 3th | 177 | 93 | 28 | 93 | 30.107527 | 1.556683 |
| 3 | (16.0, 32.0] | 1st | 51 | 127 | 57 | 127 | 44.881890 | 0.715053 |
| 4 | (16.0, 32.0] | 2nd | 61 | 157 | 41 | 157 | 26.114650 | 0.703348 |
| 5 | (16.0, 32.0] | 3th | 192 | 507 | 83 | 507 | 16.370809 | 0.694387 |
| 6 | (32.0, 48.0] | 1st | 43 | 106 | 47 | 106 | 44.339623 | 0.718681 |
| 7 | (32.0, 48.0] | 2nd | 20 | 64 | 21 | 64 | 32.812500 | 0.630783 |
| 8 | (32.0, 48.0] | 3th | 33 | 95 | 7 | 95 | 7.368421 | 0.665044 |
| 9 | (48.0, 64.0] | 1st | 38 | 71 | 23 | 71 | 32.394366 | 0.825501 |
| 10 | (48.0, 64.0] | 2nd | 7 | 24 | 6 | 24 | 25.000000 | 0.609394 |
| 11 | (48.0, 64.0] | 3th | 1 | 11 | 1 | 11 | 9.090909 | 0.340219 |
| 12 | (64.0, 80.0] | 1st | 3 | 8 | 1 | 8 | 12.500000 | 0.690988 |
aux['sibsp_area'] *= 10
source = ColumnDataSource(data=aux)
p = figure(
title='Survival chance on The Titanic',
plot_width=600,
plot_height=400,
x_range=aux['Age'].unique().tolist(),
)
color_mapper = CategoricalColorMapper(palette=["green", "blue", "red"], factors=["1st", "2nd", "3th"])
p.circle(
x='Age_',
y='percent_',
size='sibsp_area_',
fill_color=transform('Pclass_', color_mapper),
line_color=None,
fill_alpha=0.6,
legend_group='Pclass_',
source=source,
)
p.yaxis.axis_label = 'Survival percentage (%)'
p.xaxis.axis_label = 'Age ranges'
show(p)