Python 中具有堆积范围的圆形可视化
Circular Visualization in Python with Piled Ranges
如何在 matplotlib(或其他包)中创建循环可视化(基因组表示)并堆积具有百分比范围的片段。比如我有3个基因,我想把这3个基因堆到一个长度为0-1的圆形图上。需要一些偏移量来区分各个范围。
基因 1:.1 - .25
基因 2:.15 - .3
基因 3:.6 - .68
下面的期望输出:
我会说使用 Matplotlib 绘制它并不容易,但我认为您会对您在问题中声称的“或其他包”的其他库感到满意。
我将展示我使用 Plotly 绘制它的方法。您可以简单地 运行 pip install plotly
来拥有这个库。
我会用极轴来画圆图,这样就方便多了。
首先,让我们定义一个函数,用于获取在特定时间重复的半径 r
以及 theta
值。请注意 num_points
是一个常量值,如果您将其设置得更高,它会使您的图表更“平滑”。
import plotly.graph_objects as go
import numpy as np
def get_theta(pct, num_points=360):
start = pct[0] * 360
length = (pct[1] - pct[0]) * 360
step = 360 / num_points
return np.arange(start, start + length + step, step)
我会硬编码你的基因列表。在你的情况下,我假设你不必这样做:)
# Hard-code your gene list
gene_list = [
[0.1, 0.25],
[0.15, 0.3],
[0.6, 0.68]
]
然后是绘制圆形图表的代码。
# Get radial scale
max_r = 1 + (len(gene_list) + 1) * 0.1
# Create a figure
fig = go.Figure()
# Create the main circle
fig.add_trace(go.Scatterpolar(
r=[1]*360,
theta=get_theta([0, 1]),
mode='lines',
line_color='black',
line_width=3
))
# Create the zero indicator
fig.add_trace(go.Scatterpolar(
r=[1, max_r - 0.1],
theta=[0, 0],
mode='lines',
line_color='black',
line_width=3
))
# Loop the gene list to add all the gene cirles
for index, circle in enumerate(gene_list):
fig.add_trace(go.Scatterpolar(
r = [1 + (index + 1) * 0.1] * 360,
theta = get_theta(circle),
mode='lines',
line_width=3
))
# Configure the layout based on the requirements.
fig.update_layout(
polar=dict(
angularaxis=dict(
rotation=90,
direction="clockwise",
showticklabels=True,
showgrid=False
),
radialaxis=dict(
range=[0, 1 + (len(gene_list) + 1) * 0.1],
showticklabels=False,
visible=False
)
),
paper_bgcolor='white'
)
# Show the figure
fig.show()
这是代码生成的图表。
当然我可以看到仍然存在问题。每个“基因”段不会在相同的半径上呈现。完全复制您的示例并非不可能,但显然并不容易。希望这对你来说足够了。如果它对你来说真的很重要。可能值得尝试使用小于 0.1
的步骤(在我的代码中找到 0.1
并替换它)。
仅供参考,这是使用“仅”matplotlib
:
的方法
import numpy as np
import matplotlib.pyplot as plt
data={
0:{'name':'Gene 1', 'start': .10, 'end': .25, 'offset': 0.1, 'color': 'blue'},
1:{'name':'Gene 2', 'start': .15, 'end': .30, 'offset': 0.2, 'color': 'orange'},
2:{'name':'Gene 3', 'start': .60, 'end': .68, 'offset': 0.1, 'color': 'green'}
}
## setup the figure:
fig = plt.figure()
ax = plt.subplot(111, projection='polar')
ax.set_theta_direction(-1) # make it go clockwise
ax.set_theta_zero_location('N') # put "0" at top
# remove the labels
ax.set_xticks([])
ax.set_yticks([])
ax.spines['polar'].set_visible(False)
LW = 3.0 ## setting the linewidth globally for fine-tuning
def add_bg_circle(ax):
""" adds the central circle with top notch """
# the circle
circle_x = np.linspace(0,2*np.pi,200)
circle_y = np.array([1.0 for x in circle_x])
ax.plot(circle_x,circle_y,c="k",linewidth=LW)
# the top notch
line_y = np.linspace(1.0,1.1) ## change length of the top line here
line_x = np.array([0 for y in line_y])
ax.plot(line_x,line_y,c="k",linewidth=LW)
# the text
ax.text(0.0,1.15,"0",ha="center",va="center")
add_bg_circle(ax)
## plot the line segments:
for (k,v) in data.items():
xs = np.linspace(v['start']*2*np.pi , v['end']*2*np.pi, 200)
ys = np.array([(1.0 + v['offset']) for x in xs])
ax.plot(xs, ys, linewidth=LW, label=v['name'])
_inner_lim = 0.5 # keep this below the value for the main circle at 1.0
_outer_lim = 1.3 # adjust to include all plotted segments
ax.set_ylim(_inner_lim,_outer_lim)
# plt.legend() # optional
# plt.savefig("dna_circle.png")
plt.show()
产量:
如何在 matplotlib(或其他包)中创建循环可视化(基因组表示)并堆积具有百分比范围的片段。比如我有3个基因,我想把这3个基因堆到一个长度为0-1的圆形图上。需要一些偏移量来区分各个范围。
基因 1:.1 - .25
基因 2:.15 - .3
基因 3:.6 - .68
下面的期望输出:
我会说使用 Matplotlib 绘制它并不容易,但我认为您会对您在问题中声称的“或其他包”的其他库感到满意。
我将展示我使用 Plotly 绘制它的方法。您可以简单地 运行 pip install plotly
来拥有这个库。
我会用极轴来画圆图,这样就方便多了。
首先,让我们定义一个函数,用于获取在特定时间重复的半径 r
以及 theta
值。请注意 num_points
是一个常量值,如果您将其设置得更高,它会使您的图表更“平滑”。
import plotly.graph_objects as go
import numpy as np
def get_theta(pct, num_points=360):
start = pct[0] * 360
length = (pct[1] - pct[0]) * 360
step = 360 / num_points
return np.arange(start, start + length + step, step)
我会硬编码你的基因列表。在你的情况下,我假设你不必这样做:)
# Hard-code your gene list
gene_list = [
[0.1, 0.25],
[0.15, 0.3],
[0.6, 0.68]
]
然后是绘制圆形图表的代码。
# Get radial scale
max_r = 1 + (len(gene_list) + 1) * 0.1
# Create a figure
fig = go.Figure()
# Create the main circle
fig.add_trace(go.Scatterpolar(
r=[1]*360,
theta=get_theta([0, 1]),
mode='lines',
line_color='black',
line_width=3
))
# Create the zero indicator
fig.add_trace(go.Scatterpolar(
r=[1, max_r - 0.1],
theta=[0, 0],
mode='lines',
line_color='black',
line_width=3
))
# Loop the gene list to add all the gene cirles
for index, circle in enumerate(gene_list):
fig.add_trace(go.Scatterpolar(
r = [1 + (index + 1) * 0.1] * 360,
theta = get_theta(circle),
mode='lines',
line_width=3
))
# Configure the layout based on the requirements.
fig.update_layout(
polar=dict(
angularaxis=dict(
rotation=90,
direction="clockwise",
showticklabels=True,
showgrid=False
),
radialaxis=dict(
range=[0, 1 + (len(gene_list) + 1) * 0.1],
showticklabels=False,
visible=False
)
),
paper_bgcolor='white'
)
# Show the figure
fig.show()
这是代码生成的图表。
当然我可以看到仍然存在问题。每个“基因”段不会在相同的半径上呈现。完全复制您的示例并非不可能,但显然并不容易。希望这对你来说足够了。如果它对你来说真的很重要。可能值得尝试使用小于 0.1
的步骤(在我的代码中找到 0.1
并替换它)。
仅供参考,这是使用“仅”matplotlib
:
import numpy as np
import matplotlib.pyplot as plt
data={
0:{'name':'Gene 1', 'start': .10, 'end': .25, 'offset': 0.1, 'color': 'blue'},
1:{'name':'Gene 2', 'start': .15, 'end': .30, 'offset': 0.2, 'color': 'orange'},
2:{'name':'Gene 3', 'start': .60, 'end': .68, 'offset': 0.1, 'color': 'green'}
}
## setup the figure:
fig = plt.figure()
ax = plt.subplot(111, projection='polar')
ax.set_theta_direction(-1) # make it go clockwise
ax.set_theta_zero_location('N') # put "0" at top
# remove the labels
ax.set_xticks([])
ax.set_yticks([])
ax.spines['polar'].set_visible(False)
LW = 3.0 ## setting the linewidth globally for fine-tuning
def add_bg_circle(ax):
""" adds the central circle with top notch """
# the circle
circle_x = np.linspace(0,2*np.pi,200)
circle_y = np.array([1.0 for x in circle_x])
ax.plot(circle_x,circle_y,c="k",linewidth=LW)
# the top notch
line_y = np.linspace(1.0,1.1) ## change length of the top line here
line_x = np.array([0 for y in line_y])
ax.plot(line_x,line_y,c="k",linewidth=LW)
# the text
ax.text(0.0,1.15,"0",ha="center",va="center")
add_bg_circle(ax)
## plot the line segments:
for (k,v) in data.items():
xs = np.linspace(v['start']*2*np.pi , v['end']*2*np.pi, 200)
ys = np.array([(1.0 + v['offset']) for x in xs])
ax.plot(xs, ys, linewidth=LW, label=v['name'])
_inner_lim = 0.5 # keep this below the value for the main circle at 1.0
_outer_lim = 1.3 # adjust to include all plotted segments
ax.set_ylim(_inner_lim,_outer_lim)
# plt.legend() # optional
# plt.savefig("dna_circle.png")
plt.show()
产量: