【问题标题】:Circular Visualization in Python with Piled RangesPython中的循环可视化与堆积范围
【发布时间】:2020-07-02 23:41:07
【问题描述】:

如何在 matplotlib(或其他包)中创建循环可视化(基因组表示)并堆积具有百分比范围的片段。例如,如果我有三个基因,我想将这三个基因堆积到一个长度为 0-1 的圆形图上。需要一些偏移量来区分各个范围。

基因 1:.1 - .25
基因 2:.15 - .3
基因 3:.6 - .68

期望的输出如下:

【问题讨论】:

    标签: python matplotlib range visualization circular-reference


    【解决方案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()
    

    产量:

    【讨论】:

    • 哇!我也喜欢设置偏移量的能力!非常感谢@Asmus
    • 干得好@Asmus,我喜欢你只使用 Matplotlib 的解决方案,它实际上看起来并不复杂!
    【解决方案2】:

    我会说使用 Matplotlib 绘制它并不容易,但我假设您会对其他库感到满意,因为您在问题中声称“或其他包”。

    我将展示我使用 Plotly 绘制它的方法。你可以简单地运行pip install plotly 来拥有这个库。

    我会使用极轴来绘制圆形图表,这样可以让一切变得更容易。

    首先,让我们定义一个函数,用于获取半径rtheta 值在特定时间重复。请注意,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 并替换它)。

    【讨论】:

    • 嗨@Christopher,这太棒了,正是我想要的!干得好,你是救生员,我一直在尝试使用 matplotlib,但失败了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-16
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多