LoginSignup
1
2

Pythonで円形の積み上げ棒グラフ(Circular Stacked Bar)をプロットする

Last updated at Posted at 2023-07-21

個人開発している円形データプロットのためのPython製OSSライブラリ「pyCirclize」に積み上げ棒グラフのプロット機能を最近追加してみた。この記事では、新しく追加した円形の積み上げ棒プロット機能の使い方について簡単に紹介します。

stacked_bar_gallery.png
↑ 垂直・水平方向の円形積み上げ棒グラフのプロット例

pyCirclizeのインストール

pip または condaコマンドでインストール可能

PyPIからインストール
pip install pycirclize
conda-forgeからインストール
conda install -c conda-forge pycirclize

積み上げ棒グラフのプロット

pyCirclizeでは行名・列名付きの表データから円形の積み上げ棒グラフを垂直・水平方向にそれぞれプロットする機能を実装してます。

垂直方向プロット例①

from pycirclize import Circos
import pandas as pd
import numpy as np
np.random.seed(0)

# Generate matrix data for stacked bar plot
row_num, col_num = 12, 6
matrix = np.random.randint(5, 20, (row_num, col_num))
row_names = [f"R{i}" for i in range(row_num)]
col_names = [f"group{i}" for i in range(col_num)]
table_df = pd.DataFrame(matrix, index=row_names, columns=col_names)
table_df.to_csv("stacked_bar_table.tsv", sep="\t")

# Initialize Circos sector & track
circos = Circos(sectors=dict(bar=len(table_df.index)))
sector = circos.sectors[0]
track = sector.add_track((50, 100))
track.grid()

# Plot stacked bar 
colormap = "Set3"
sb_table = track.stacked_bar(
    table_df,
    width=0.6,
    cmap=colormap,
    bar_kws=dict(ec="black", lw=0.2),
    label_pos="bottom",
    label_kws=dict(size=10, orientation="horizontal"),
)

circos.savefig("stacked_bar01.png")

入力

行名・列名付き表データ(TSV形式)
	group0	group1	group2	group3	group4	group5
R0	17	10	5	8	16	8
R1	12	14	8	10	7	9
R2	12	11	13	13	17	15
R3	6	11	12	12	19	13
R4	6	10	14	18	13	14
R5	9	8	5	8	10	19
R6	5	7	8	13	6	8
R7	18	8	8	19	12	5
R8	6	14	14	5	15	9
R9	12	8	19	16	7	12
R10	17	7	5	5	9	10
R11	10	11	13	9	6	9

出力図

stacked_bar01.png

垂直方向プロット例②

最小限のプロットのみだった垂直方向プロット例①から凡例や最小・最大値ラベルを追加した例

from pycirclize import Circos
from matplotlib.patches import Patch
import pandas as pd
import numpy as np
np.random.seed(0)

# Generate matrix data for stacked bar plot
row_num, col_num = 12, 6
matrix = np.random.randint(5, 20, (row_num, col_num))
row_names = [f"R{i}" for i in range(row_num)]
col_names = [f"group{i}" for i in range(col_num)]
table_df = pd.DataFrame(matrix, index=row_names, columns=col_names)

# Initialize Circos sector & track (5 <= range <= 355)
circos = Circos(sectors=dict(bar=len(table_df.index)), start=5, end=355)
sector = circos.sectors[0]
track = sector.add_track((50, 100))
track.grid(x_grid_interval=track.size)

# Plot stacked bar & label
colormap = "tab10"
sb_table = track.stacked_bar(
    table_df,
    width=0.6,
    cmap=colormap,
    bar_kws=dict(ec="black", lw=0.2),
    label_pos="top",
    label_kws=dict(size=10, orientation="vertical"),
)
vmin, vmax = 0, sb_table.row_sum_vmax
circos.text(str(vmin), r=min(track.r_lim), color="grey")
circos.text(str(vmax), r=max(track.r_lim), color="grey")

fig = circos.plotfig()

# Plot legends
col_name2color = sb_table.get_col_name2color(colormap)
_ = circos.ax.legend(
    handles=[Patch(label=n, fc=c, ec="black", lw=0.5) for n, c in col_name2color.items()],
    bbox_to_anchor=(0.5, 0.5),
    loc="center",
    ncols=2,
)

fig.savefig("stacked_bar02.png")

出力図

stacked_bar02.png

水平方向プロット例

from pycirclize import Circos
from pycirclize.parser import StackedBarTable
from matplotlib.patches import Patch
import pandas as pd
import numpy as np
np.random.seed(0)

# Generate & load matrix data for horizontal stacked bar plot
row_names = list("ABCDEF")
col_names = ["group1", "group2", "group3", "group4", "group5", "group6"]
matrix = np.random.randint(5, 20, (len(row_names), len(col_names)))
table_df = pd.DataFrame(matrix, index=row_names, columns=col_names)
table_df.to_csv("stacked_barh_table.tsv", sep="\t")
sb_table = StackedBarTable(table_df)

# Initialize Circos sector & track (0 <= range <= 270)
circos = Circos(sectors=dict(bar=sb_table.row_sum_vmax), start=0, end=270)
sector = circos.sectors[0]
track = sector.add_track((30, 100))
track.axis(fc="lightgrey", ec="black", alpha=0.5)

# Plot horizontal stacked bar & label & xticks
colormap = "tab10"
track.stacked_barh(sb_table.dataframe, cmap=colormap, width=0.6)
label_r_list = sb_table.calc_barh_label_r_list(track.r_plot_lim)
for label_r, row_name in zip(label_r_list, sb_table.row_names):
    track.text(f"{row_name} ", x=0, r=label_r, ha="right")
track.xticks_by_interval(interval=5)
track.xticks_by_interval(interval=1, tick_length=1, show_label=False)

fig = circos.plotfig()

# Plot legends
col_name2color = sb_table.get_col_name2color(colormap)
_ = circos.ax.legend(
    handles=[Patch(label=n, fc=c, ec="black", lw=0.5) for n, c in col_name2color.items()],
    bbox_to_anchor=(0.2, 0.8),
    fontsize=12,
    loc="center",
    ncols=2,
)

fig.savefig("stacked_barh.png")

入力

行名・列名付き表データ(TSV形式)
	group1	group2	group3	group4	group5	group6
A	17	10	5	8	16	8
B	12	14	8	10	7	9
C	12	11	13	13	17	15
D	6	11	12	12	19	13
E	6	10	14	18	13	14
F	9	8	5	8	10	19

出力図

stacked_barh.png

おわりに

matplotlibで円形の積み上げ棒グラフをプロットするコードを一から実装しようとすると、そこそこ手間がかかります。pyCirclizeを利用することで、比較的簡単に積み上げ棒グラフを作成できるようになると思います。円形の積み上げ棒グラフを使うことはあまりないと思いますが、興味を持った人がいれば使ってみてください。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2