PythonでRose Diagramを作るとき、Windroseを使う例が多いですが、インストールがめんどくさいので、標準ライブラリだけで作ることにしました。
やっていることは単純で、
1.円を描く 2.度数を求める 3.棒グラフを描く の3stepです。
今回は、大阪府における新型コロナウイルス感染症患者の発生状況(令和2年3月29日20時30分現在)のデータを取り上げ、
入院中、または入院調整中の方のなかで、軽症・無症状・重症がどれほどいるのかを年代ごとにRose Diagramで表現しました。
大阪府のデータを使っていますが、あくまでもrose diagramを作る練習なので、この図から得られる結果についてすべての責任を持つことはできません。予めご了承ください。正しい情報を得たい方は、上にリンクを張ってある大阪府のサイトからご確認ください。

スポンサーリンク
Pythonコード
#!/usr/bin/env python3
#必要なものを宣言
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from matplotlib.lines import Line2D
#保存する場所
DIR1 = '/home/User/rose_diagram/figs/'
#解像度の指定
set_dpi = 100
#指す内容は同じだが、
#age_rangeは円のグリットのラベル
#age_listはexcelファイルからの抽出に使う
age_range = np.linspace(10, 80, 8, dtype=int)
age_list = np.arange(0, 90, 10)
#軽症・無症状・重症のリスト
symptom_list = [ 'mild','asymptomatic','severe']
symptom_color = ['y', 'g', 'r']
nage, nsym = len(age_range), len(symptom_list)
#ezcelファイルの読み込み
df1 = pd.read_excel("rose-diagram_data_rev.xlsx")
#ここから作図
fig = plt.figure(figsize=(8,8))
ax = fig.add_subplot(projection='polar')
#円の設定
ax.set_theta_zero_location('N')
ax.set_theta_direction(-1)
ax.set_thetagrids(np.arange(0, 360, 45), labels=age_list, fontsize=12)
ax.set_rgrids(np.arange(0, 30, 5), angle=0, weight= 'black')
#dataframeをnp.arrayで使いやすいように調節
age = df1.iloc[:, 0]
sym = df1.iloc[:, 1]
data = np.array([age,sym]).T
#legendとangle位置調整につかう
bar_angle = np.arange(23, 383, 45)
legend_angle = np.deg2rad(270)
#必要なデータをリストで受け渡すための準備
ndata = []
for isym in range(nsym):
lsym = symptom_list[isym]
for iage in range(nage):
lage = age_range[iage]
#年齢と症状が一致するものに並び替える
var0 = np.where((data[:,0] == lage) & (data[:,1] == lsym))
vshape = data[var0].shape[0]
ndata.append(vshape)
#if~をする理由は、最後のループ結果をndataとしたいため
if iage == nage-1 and isym == nsym-1:
ndata = np.array(ndata)
#このaの要素が棒グラフをかくための度数
a = np.reshape(ndata, (nsym, -1))
ybar = a.tolist()
#棒グラフを作成
for iybar in range(nsym):
ax.bar(np.deg2rad(bar_angle), ybar[iybar],
width=np.deg2rad(45), bottom=0.0, color=symptom_color[iybar],
edgecolor='k', alpha=0.5, zorder=iybar)
#ax.barにlabelを指定しても、legendが出力されなかったので、自力でつくる
custom_lines = [Line2D([0], [0], color=symptom_color[0], lw=4),
Line2D([0], [0], color=symptom_color[1], lw=4),
Line2D([0], [0], color=symptom_color[2], lw=4),]
ax.legend(custom_lines, symptom_list, loc="lower center",
ncol=nsym, columnspacing=1, fontsize=18, frameon=False,
bbox_to_anchor=(.5 + np.cos(legend_angle)/2, .35 + np.sin(legend_angle)/2))
#pngで保存
fileo1 = DIR1 +'test'+'.png'
plt.savefig(fileo1,dpi=set_dpi, transparent=False)
使用したexcelの中身
Pythonコードでいう、df1の中身を一応載せておきます。ageとsymtomを列とした133×2のdataframeを使っています。
age symptom
0 40 mild
1 60 mild
2 70 asymptomatic
3 60 asymptomatic
4 60 mild
5 50 mild
6 20 mild
7 60 mild
8 30 asymptomatic
9 40 severe
10 30 mild
11 20 mild
12 70 mild
13 50 asymptomatic
14 30 asymptomatic
15 30 mild
16 50 mild
17 70 mild
18 70 mild
19 30 mild
20 20 mild
21 70 mild
22 60 severe
23 50 mild
24 80 severe
25 50 mild
26 50 mild
27 20 mild
28 60 severe
29 40 mild
.. ... ...
103 40 mild
104 70 mild
105 20 mild
106 20 mild
107 30 mild
108 20 mild
109 50 mild
110 30 mild
111 40 mild
112 30 asymptomatic
113 20 mild
114 20 mild
115 40 mild
116 40 mild
117 10 asymptomatic
118 70 mild
119 60 mild
120 30 mild
121 60 mild
122 50 mild
123 30 mild
124 40 mild
125 20 mild
126 30 mild
127 60 mild
128 60 mild
129 20 mild
130 20 mild
131 50 mild
132 70 mild
[133 rows x 2 columns]
スポンサーリンク
参考にしたサイト様
Rose Diagramを作る作業の流れ (こちらのサイト様は度数を求めるためにヒストグラムを利用しています)
http://geologyandpython.com/structural_geology.html
matplotlib公式 (legendの配置の仕方を参考にしました)
https://matplotlib.org/3.2.1/gallery/pie_and_polar_charts/polar_legend.html