As mentioned in the instructions, all materials can be open in Colab as Jupyter notebooks. In this way users can run the code in the cloud. It is highly recommanded to follow the tutorials in the right order.


This notebook aims to introduce users some practical skills on generating a circle packing chart.


Presumptions:

Not applicable.


! pip install circlify
Collecting circlify
  Downloading circlify-0.14.0-py2.py3-none-any.whl (11 kB)
Installing collected packages: circlify
Successfully installed circlify-0.14.0
from pprint import pprint as pp
import circlify as circ
surname = """
	王	李	張	趙	劉	陳	楊	吳	黃	朱	孫	郭	胡	呂	高	宋	徐	程	林	鄭	范	何	韓	曹	馬	許	田	馮	杜	周	曾	汪	蘇	董	方	蔡	梁	石	謝	賈	薛	彭	崔	唐	潘	鄧	任	史	錢	侯	魏	羅	葉	沈	孟	姚	傅	丁	章	蕭	蔣	盧	陸	袁	江	晁	譚	邵	歐陽	孔	俞	尹	廖	閻	洪	夏	雷	葛	文	柳	陶	毛	丘	龔	康	蒲	邢	郝	龐	安	裴	折	施	游	金	鄒	湯	虞	嚴	鍾
"""

import re
surname = list(re.sub("\s+", "", surname.strip()))
surname[:5]
['王', '李', '張', '趙', '劉']
surname.reverse()
len(surname)
101
import pandas as pd
import numpy as np
df = pd.DataFrame({
    'surname': surname,
    'weight': 5*np.arange(1,102)
})
import circlify

# compute circle positions:
circles = circlify.circlify(
    df['weight'].tolist(),  
    target_enclosure=circlify.Circle(x=0, y=0, r=1),
    show_enclosure=False
)
len(df.weight)
101
import math
import numpy as np

x = np.array([cir.x for cir in circles])
y = np.array([cir.y for cir in circles])
r = np.array([cir.r for cir in circles])

bubble_df = pd.DataFrame({
    'x': x,
    'y': y,
    'r': r,
    'l': df.sort_values('weight').surname.values,
    's': (math.pi)*(r**2)
})
!wget -O TaipeiSansTCBeta-Regular.ttf https://drive.google.com/uc?id=1eGAsTN1HBpJAkeVM57_C7ccp7hbgSz3_&export=download

import matplotlib as mpl
import matplotlib.pyplot as plt 
from matplotlib.font_manager import fontManager

fontManager.addfont('TaipeiSansTCBeta-Regular.ttf')
mpl.rc('font', family='Taipei Sans TC Beta')
import circlify
import numpy as np
import random
import matplotlib.pyplot as plt

import seaborn as sns
from matplotlib.colors import ListedColormap

palette = ["#CD5C5C","#F08080","#E9967A","#FFA07A","#C04000","#FF5F1F","#B22222","#660000","#C21E56"]

# Create just a figure and only one subplot
fig, ax = plt.subplots(figsize=(10,10))

# Title
ax.set_title('宋朝人口姓氏期望分佈', fontsize=26)

# Remove axes
ax.axis('off')

# Find axis boundaries
lim = max(
    max(
        abs(circle.x) + circle.r,
        abs(circle.y) + circle.r,
    )
    for circle in circles
)
plt.xlim(-lim, lim)
plt.ylim(-lim, lim)

# list of labels
labels = df.sort_values('weight').surname.values

# print circles
for circle, label in zip(circles, labels):
    x, y, r = circle
    ax.add_patch(plt.Circle((x, y), r, alpha=0.6, linewidth=1, facecolor=random.choice(palette), edgecolor="white"))
    plt.annotate(
          label, 
          (x,y) ,
          va='center',
          ha='center',
          fontsize=300*r,
          color="black"
     )
bubble_df["rank"] = bubble_df.sort_values(by="r", ascending=False).index
bubble_df.head()
x y r l s rank
0 -0.157353 0.011841 0.011880 0.000443 101
1 -0.199757 0.034318 0.016801 0.000887 100
2 -0.129251 -0.004397 0.020577 0.001330 99
3 -0.225690 0.181468 0.023760 0.001774 98
4 -0.309487 0.366656 0.026564 0.002217 97
font_size = 250*bubble_df.r.values
import plotly.express as px

fig = px.scatter(bubble_df, x="x", y="y", custom_data=["l","rank"], color="x", width=800, height=700,
                 size="s", hover_name="l", size_max=45, text="l")

fig.update(layout_coloraxis_showscale=False)
fig.update_traces(
    hovertemplate="<br>".join([
        "Surname: %{customdata[0]}",
        "Ranking: %{customdata[1]}"
    ])
)

fig.update_layout(showlegend=False)
fig.update_xaxes(visible=False)
fig.update_yaxes(visible=False)
fig.update_yaxes(
    scaleanchor = "x",
    scaleratio = 0.95,
  )

fig.update_layout({
'plot_bgcolor': 'rgba(0, 0, 0, 0)',
'paper_bgcolor': 'rgba(0, 0, 0, 0)',
})

fig.update_layout(
    title={
        'text': "<b>宋朝人口姓氏期望分佈</b>",
        'y':0.97,
        'x':0.5,
        'xanchor': 'center',
        'yanchor': 'top'},
    font=dict(
        family="Courier New, monospace",
        size=18,
        color="black"
    )
)

fig.update_traces(textfont_size=font_size)

fig.show()




Additional information

This notebook is provided for educational purpose and feel free to report any issue on GitHub.


Author: Ka Hei, Chow

License: The code in this notebook is licensed under the Creative Commons by Attribution 4.0 license.

Last modified: December 2021




References:

https://github.com/elmotec/circlify