Plot Tips
# %pip install pycirclizely
import plotly.io as pio
from IPython.display import HTML
Grouping Sectors¶
In pyCirclizely, the space size between sectors can be set arbitrarily.
By using the calc_group_spaces
function, users can easily get the sector space size setting
within/between groups based on the number of groups.
Groups can be explicitly visualized as shown in the code example below.
from pycirclizely import Circos
from pycirclizely.utils import ColorCycler, calc_group_spaces
sectors = {name: 10 for name in "ABCDEFGHIJ"}
group1, group2, group3 = list("ABCD"), list("EFG"), list("HIJ")
# Calculate appropriate group between/within spaces
# In this example, 10 sectors are displayed as groups dividied into [4, 3, 3]
spaces = calc_group_spaces([4, 3, 3], space_bw_group=15, space_in_group=2)
circos = Circos(sectors, space=spaces)
# Plot sector track
color_cycler = ColorCycler("Set3")
for sector in circos.sectors:
track = sector.add_track(r_lim=(85, 90))
track.axis(fillcolor=color_cycler.get_color())
track.text(sector.name)
# Plot group sectors range
color_cycler = ColorCycler("T10")
for idx, group in enumerate((group1, group2, group3), 1):
group_deg_lim = circos.get_group_sectors_deg_lim(group)
circos.rect(
r_lim=(97, 100),
deg_lim=group_deg_lim,
fillcolor=color_cycler.get_color(),
line=dict(color="black", width=0.5),
)
group_center_deg = sum(group_deg_lim) / 2
circos.text(f"Group{idx}", r=105, deg=group_center_deg, adjust_rotation=True)
fig = circos.plotfig()
HTML(pio.to_html(fig, include_plotlyjs="cdn"))
Anti-clockwise¶
pyCirclize sets the coordinate direction of each sector as clockwise by default.
Users can set the coordinate direction of any sector to anti-clockwise with
sector2clockwise
option when initializing Circos instance.
from pycirclizely import Circos
sectors = dict(A1=18000, A2=13000, A3=6000, A4=5000, B3=12000, B2=13000, B1=15000)
circos = Circos(
sectors,
space=3,
# Set (B1, B2, B3) sector coordinate direction as anti-clockwise
sector2clockwise=dict(B1=False, B2=False, B3=False),
)
for sector in circos.sectors:
# Plot track
color = "orange" if sector.name.startswith("A") else "skyblue"
track = sector.add_track((94, 100), r_pad_ratio=0.1)
track.axis(fillcolor=color)
track.text(sector.name)
# Plot xticks
major_interval, minor_interval = 5000, 1000
track.xticks_by_interval(
major_interval,
label_orientation="vertical",
label_formatter=lambda v: f"{v / 1000:.0f} Kb",
)
track.xticks_by_interval(minor_interval, tick_length=1, show_label=False)
# Plot links
circos.link(("A1", 0, 10000), ("B1", 0, 10000))
circos.link(("A1", 18000, 13000), ("B1", 10000, 15000), fillcolor="tomato")
circos.link(("A2", 0, 13000), ("B2", 0, 13000))
circos.link(("A3", 0, 6000), ("B3", 6000, 12000))
circos.link(("A4", 0, 5000), ("B3", 0, 5000))
fig = circos.plotfig()
HTML(pio.to_html(fig, include_plotlyjs="cdn"))
Colorbar¶
Users can easily plot colorbars with circos.colorbar()
method.
import numpy as np
from pycirclizely import Circos
np.random.seed(0)
# Initialize Circos instance
circos = Circos(sectors=dict(data=100), start=90)
sector = circos.sectors[0]
# Plot heatmap track1 (cmap="RdBu_r")
track1 = sector.add_track((85, 100))
track1.axis()
vmin1, vmax1, cmap1 = 0, 100, "RdBu_r"
matrix1 = np.random.randint(vmin1, vmax1, (5, 100))
# Create first colorbar (vertical on the right)
coloraxis1 = circos.colorbar(
vmin=vmin1,
vmax=vmax1,
cmap=cmap1,
thicknessmode="pixels",
thickness=15,
lenmode="pixels",
len=300,
yanchor="middle",
y=0.5,
xanchor="left",
x=1.0,
ticks="outside",
)
# Apply coloraxis to heatmap
track1.heatmap(matrix1, cmap=cmap1, vmin=vmin1, vmax=vmax1, coloraxis=coloraxis1)
# Plot heatmap track2 (cmap="Viridis")
track2 = sector.add_track((65, 80))
track2.axis()
vmin2, vmax2, cmap2 = -200, 200, "Viridis"
matrix2 = np.random.randint(vmin2, vmax2, (3, 100))
# Create second colorbar (horizontal at bottom)
coloraxis2 = circos.colorbar(
vmin=vmin2,
vmax=vmax2,
cmap=cmap2,
title=dict(
text="Colorbar in center", font=dict(size=16, color="blue"), side="bottom"
),
thicknessmode="pixels",
thickness=15,
lenmode="pixels",
len=250,
yanchor="bottom",
y=0.4,
xanchor="center",
x=0.5,
orientation="h",
tickfont=dict(size=12, color="red"),
)
# Apply coloraxis to second heatmap
track2.heatmap(matrix2, cmap=cmap2, vmin=vmin2, vmax=vmax2, coloraxis=coloraxis2)
fig = circos.plotfig()
HTML(pio.to_html(fig, include_plotlyjs="cdn"))
Stacked Bar¶
Users can easily plot stacked bar chart from matrix dataframe with row and column names.
Vertical and horizontal stacked bar chart can be plotted using track.stacked_bar()
and track.stacked_barh()
methods, respectively.
import numpy as np
import pandas as pd
from pycirclizely import Circos
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)
print(table_df)
# 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
sb_table = track.stacked_bar(table_df, width=0.6, cmap="Set3")
x_list = sb_table.calc_bar_label_x_list(track.size)
track.xticks(
x=x_list,
labels=sb_table.row_names,
outer=False,
tick_length=0,
label_margin=2,
label_orientation="horizontal",
text_kws=dict(font=dict(size=12)),
)
fig = circos.plotfig()
HTML(pio.to_html(fig, include_plotlyjs="cdn"))
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
import numpy as np
import pandas as pd
from pycirclizely import Circos
from pycirclizely.parser import StackedBarTable
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)
sb_table = StackedBarTable(table_df)
print(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(fillcolor="lightgrey", line=dict(color="black"), opacity=0.5)
# Plot horizontal stacked bar & label & xticks
track.stacked_barh(sb_table.dataframe, cmap="T10", 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, xanchor="right")
track.xticks_by_interval(interval=5)
track.xticks_by_interval(interval=1, tick_length=1, show_label=False)
fig = circos.plotfig()
HTML(pio.to_html(fig, include_plotlyjs="cdn"))
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
Appendix¶
1. Clock¶
import numpy as np
from pycirclizely import Circos
circos = Circos(sectors={"clock": 12})
sector = circos.sectors[0]
# Plot outer line & xticks
track = sector.add_track(r_lim=(100, 100))
major_xticks = np.arange(0, 12, 1) + 1
track.xticks(major_xticks, outer=False, show_bottom_line=True)
minor_xticks = np.arange(0, 12, 0.2)
track.xticks(minor_xticks, outer=False, tick_length=1)
# Plot 1-12 hour characters
for x in major_xticks:
track.text(str(x), x=x, r=93, font=dict(size=15), adjust_rotation=False)
# Plot clock hands (hour, minute, second)
sector.line(r=(0, 40), start=8, end=8, line=dict(width=3))
sector.line(r=(0, 70), start=0, end=0, line=dict(width=1.5))
sector.line(r=(0, 80), start=5, end=5, line=dict(width=0.5, color="red"))
fig = circos.plotfig()
HTML(pio.to_html(fig, include_plotlyjs="cdn"))
2. Dartboard¶
from pycirclizely import Circos
points = [20, 1, 18, 4, 13, 6, 10, 15, 2, 17, 3, 19, 7, 16, 8, 11, 14, 9, 12, 5]
sectors = {str(p): 1 for p in points}
circos = Circos(sectors, space=0, start=-9, end=351)
red_or_green = ("red", "green")
black_or_white = ("black", "white")
circos.rect(r_lim=(85, 100), fillcolor="black")
for idx, sector in enumerate(circos.sectors):
sector.text(
sector.name, r=92.5, font=dict(color="white", size=12), adjust_rotation=False
)
color_idx = idx % 2
sector.rect(
r_lim=(80, 85),
fillcolor=red_or_green[color_idx],
line=dict(color="lightgrey", width=1),
)
sector.rect(
r_lim=(52.5, 80),
fillcolor=black_or_white[color_idx],
line=dict(color="lightgrey", width=1),
)
sector.rect(
r_lim=(47.5, 52.5),
fillcolor=red_or_green[color_idx],
line=dict(color="lightgrey", width=1),
)
sector.rect(
r_lim=(10, 47.5),
fillcolor=black_or_white[color_idx],
line=dict(color="lightgrey", width=1),
)
circos.rect(r_lim=(5, 10), fillcolor="green", line=dict(width=0))
circos.rect(r_lim=(0, 5), fillcolor="red", line=dict(width=0))
circos.line(r=5, line=dict(color="lightgrey", width=1))
fig = circos.plotfig()
HTML(pio.to_html(fig, include_plotlyjs="cdn"))