代码之家  ›  专栏  ›  技术社区  ›  O.rka

如何使用极坐标绘制scipy.hierarchy.dendrogram?

  •  6
  • O.rka  · 技术社区  · 6 年前

    我正在尝试使以下资源适应这个问题:

    python conversion between coordinates

    https://matplotlib.org/gallery/pie_and_polar_charts/polar_scatter.html

    我似乎无法获得坐标,无法将树形图形状转换为极坐标。

    有人知道怎么做吗?我知道networkx中有一个实现,但这需要构建一个图,然后使用pygraphviz后端获取位置。

    是否有方法用 matplotlib numpy将树形图笛卡尔坐标转换为极坐标?

    导入请求 从ast导入文本评估 将matplotlib.pyplot导入为plt 将numpy导入为np 定义读取URL(URL): r=请求.get(url) 返回文本 定义笛卡尔坐标到极坐标(x,y): rho=np.sqrt(x**2+y**2) phi=np.arctan2(y,x) 返回(rho,phi) 定义图树形图(icoord,dcord,figsize,polar=false): 如果极性: icoord,dcord=笛卡尔_to_polar(icoord,dcord) 带有plt.style.context(“Seaborn White”): 图=PLT.图(图尺寸=图尺寸) ax=图添加子地块(111,极性=极性) 对于zip中的xs、ys(icoord、dcord): ax.绘图(xs,ys,color=“black”) ax.set_title(f“polar=polar”,fontsize=15) #加载树形图数据 string_data=read_url(“https://pastebin.com/raw/f953qgdr”).replace(“\r”,“).replace(“\n”,“).replace(“\u200b\u200b”,“) #将其转换为字典(scipy.hierarchy.dendrogram输出的子集) 树形图数据=文字评估(字符串数据) icoord=np.asarray(树形图数据[“icoord”],dtype=float) dcord=np.asarray(树形图数据[“dcord”],dtype=float) #绘制笛卡尔版本 绘图树图(icoord,dcord,figsize=(8,3),polar=false) #绘制极坐标 绘图树图(icoord,dcord,figsize=(5,5),polar=true) < /代码>

    我刚试过这个,但还是不正确:

    导入matplotlib.transforms作为mtransforms 带有plt.style.context(“Seaborn White”): Fig,ax=plt.子批次(FigSize=(5,5))。 对于zip中的xs、ys(icoord、dcord): ax.plot(xs,ys,color=“black”,transform=trans_offset) ax_polar=plt.子地块(111,投影='polar') trans_offset=mtransforms.offset_copy(ax_polar.transdata,fig=fig) 对于zip中的xs、ys(icoord、dcord): ax_polar.plot(xs,ys,color=“black”,transform=trans_offset) < /代码>

    .

    https://matplotlib.org/gallery/pie_and_polar_charts/polar_scatter.html

    我似乎无法得到坐标来把树木图的形状转换成极坐标。

    有人知道怎么做吗?我知道networkx中有一个实现,但这需要构建一个图,然后使用pygraphviz后端获取位置。

    有没有一种方法可以将树木图的笛卡尔坐标转换成极坐标 matplotlib numpy ?

    import requests
    from ast import literal_eval
    import matplotlib.pyplot as plt
    import numpy as np 
    
    def read_url(url):
        r = requests.get(url)
        return r.text
    
    def cartesian_to_polar(x, y):
        rho = np.sqrt(x**2 + y**2)
        phi = np.arctan2(y, x)
        return(rho, phi)
    
    def plot_dendrogram(icoord,dcoord,figsize, polar=False):
        if polar:
            icoord, dcoord = cartesian_to_polar(icoord, dcoord)
        with plt.style.context("seaborn-white"):
            fig = plt.figure(figsize=figsize)
            ax = fig.add_subplot(111, polar=polar)
            for xs, ys in zip(icoord, dcoord):
                ax.plot(xs,ys, color="black")
            ax.set_title(f"Polar= {polar}", fontsize=15)
    
    # Load the dendrogram data
    string_data = read_url("https://pastebin.com/raw/f953qgdr").replace("\r","").replace("\n","").replace("\u200b\u200b","")
    
    # Convert it to a dictionary (a subset of the output from scipy.hierarchy.dendrogram)
    dendrogram_data = literal_eval(string_data)
    icoord = np.asarray(dendrogram_data["icoord"], dtype=float)
    dcoord = np.asarray(dendrogram_data["dcoord"], dtype=float)
    
    # Plot the cartesian version
    plot_dendrogram(icoord,dcoord, figsize=(8,3), polar=False)
    
    # Plot the polar version
    plot_dendrogram(icoord,dcoord, figsize=(5,5), polar=True)
    

    enter image description here

    我刚试过这个,但还是不正确:

    import matplotlib.transforms as mtransforms
    with plt.style.context("seaborn-white"):
        fig, ax = plt.subplots(figsize=(5,5))
        for xs, ys in zip(icoord, dcoord):
            ax.plot(xs,ys, color="black",transform=trans_offset)
    
        ax_polar = plt.subplot(111, projection='polar')
        trans_offset = mtransforms.offset_copy(ax_polar.transData, fig=fig)
        for xs, ys in zip(icoord, dcoord):
            ax_polar.plot(xs,ys, color="black",transform=trans_offset)
    

    2 回复  |  直到 6 年前
        1
  •  5
  •   chthonicdaemon    6 年前

    你可以让树的“根”从中间开始,把叶子放在外面。您还必须在“条形”部分添加更多点,使其看起来更漂亮和圆润。

    我们注意到ICORD和DCOORD的每个元素(我将称其为 seg )都有四个点:

    seg[1]seg[2]
    +----------+
    γ
    +段[0]+段[3]
    < /代码> 
    
    

    垂直线在两个点之间是很好的直线,但是我们需要更多的点在seg[1]seg[2](水平线,这将需要成为一个弧)。

    此函数将在这些位置添加更多的点,并且可以在绘图函数中对xs和ys调用:

    def smoothSegment(seg,nsmooth=100):
    返回np.concatenate([[seg[0]],np.linspace(seg[1],seg[2],nsmouth),[seg[3]]])
    < /代码> 
    
    

    现在我们必须修改绘图函数来计算径向坐标。一些实验导致了我使用的对数公式,基于另一个同样使用对数刻度的答案。我在右边为径向标签留了一个空白,对“icoord”坐标和径向坐标做了一个非常基本的映射,以便标签与矩形图中的对应。我不知道怎么处理径向尺寸。这些数字对于日志是正确的,但我们可能也希望映射它们。

    def plot树状图(icoord,dcord,figsize,polar=false):
    如果极性:
    dcord=-np.log(dcord+1)
    #避免在径向标签上使用楔子。
    GAP=0.1
    imax=icoord.max()。
    imin=icoord.min()。
    icoord=(icoord-imin)/(imax-imin)*(1-间隙)+间隙/2)*2*numpy.pi
    带有plt.style.context(“Seaborn White”):
    图=PLT.图(图尺寸=图尺寸)
    ax=图添加子地块(111,极性=极性)
    对于zip中的xs、ys(icoord、dcord):
    如果极性:
    xs=平滑段(xs)
    ys=平滑段(ys)
    ax.绘图(xs,ys,color=“black”)
    ax.set_title(f“polar=polar”,fontsize=15)
    如果极性:
    ax.spines['polar']设置\u可见(false)
    ax.设置标签位置(0)
    NxTiKS=10
    xticks=np.linspace(间隙/2,1-间隙/2,nxticks)
    ax.设置_xTicks(xTicks*np.pi*2)
    ax.set_xtickLabels(np.round(np.linspace(imin,imax,nxticks)).astype(int))。
    < /代码> 
    
    

    结果如下图:

    看起来又漂亮又圆。

    我们注意到icoord和dcord的每个元素(我将称之为seg)有四点:

    seg[1]        seg[2]
    +-------------+
    |             |
    + seg[0]      + seg[3]
    

    竖线和两点之间的直线一样细,但我们需要两点之间的更多点seg[1]seg[2](水平条,需要变成弧形)。

    此函数将在这些位置中添加更多点,并且可以在绘图函数中对xs和ys调用:

    def smoothsegment(seg, Nsmooth=100):
        return np.concatenate([[seg[0]], np.linspace(seg[1], seg[2], Nsmooth), [seg[3]]])
    

    现在我们必须修改绘图函数来计算径向坐标。一些实验导致了我使用的对数公式,基于另一个同样使用对数刻度的答案。我在右边为径向标签留了一个空白,对“icoord”坐标和径向坐标做了一个非常基本的映射,以便标签与矩形图中的对应。我不知道怎么处理径向尺寸。这些数字对于日志是正确的,但我们可能也希望映射它们。

    def plot_dendrogram(icoord,dcoord,figsize, polar=False):
        if polar:
            dcoord = -np.log(dcoord+1)
            # avoid a wedge over the radial labels
            gap = 0.1
            imax = icoord.max()
            imin = icoord.min()
            icoord = ((icoord - imin)/(imax - imin)*(1-gap) + gap/2)*2*numpy.pi
        with plt.style.context("seaborn-white"):
            fig = plt.figure(figsize=figsize)
            ax = fig.add_subplot(111, polar=polar)
            for xs, ys in zip(icoord, dcoord):
                if polar:
                    xs = smoothsegment(xs)
                    ys = smoothsegment(ys)
                ax.plot(xs,ys, color="black")
            ax.set_title(f"Polar= {polar}", fontsize=15)
            if polar:
                ax.spines['polar'].set_visible(False)
                ax.set_rlabel_position(0)
                Nxticks = 10
                xticks = np.linspace(gap/2, 1-gap/2, Nxticks)
                ax.set_xticks(xticks*np.pi*2)
                ax.set_xticklabels(np.round(np.linspace(imin, imax, Nxticks)).astype(int))
    

    结果如下图:

    Radial dendrogram

        2
  •  3
  •   The Data Scientician    6 年前

    首先,我认为您可能会受益于

    那么,让我们来分解目标:我不太清楚你想做什么,但我假设你想得到这样的东西

    ( source,page 14 ))

    要渲染类似的东西,您需要能够渲染在极坐标中显示为半圆形的水平线。然后,将水平线映射到极坐标图就成了问题。

    首先,请注意,您的半径在这一行中没有规格化:

    如果极坐标: icoord,dcord=笛卡尔_to_polar(icoord,dcord) < /代码>

    您可以通过简单地重新映射 icoord to[0;2pi]来规范化它们。

    现在,让我们试着画一些更简单的图,而不是复杂的图:

    icoord,dcord=np.meshgrid(np.r_[1:10],np.r_[1:4])
    
    #绘制笛卡尔版本
    绘图树图(icoord,dcord,figsize=(8,3),polar=false)
    
    #绘制极坐标
    绘图树图(icoord,dcord,figsize=(5,5),polar=true)
    < /代码> 
    
    

    结果如下:

    正如你所看到的,极坐标代码并没有将水平线映射到半圆形,因此这是行不通的。让我们试试plt.polarinstead:。

    plt.polar(icoord.t,dcord.t)
    < /代码> 
    
    

    产生

    这更像是我们需要的。我们需要先确定角度,然后考虑Y坐标向内(你可能希望它从中心到边界)。归根结底就是这个

    nic=(icoord.t-icoord.min())/(icoord.max()-icoord.min())
    极性PLT(2*np.pi*nic,-dcord.t)
    < /代码> 
    
    

    它产生了以下

    这和你需要的相似。请注意,直线保持笔直,不会被弧替换,因此您可能需要在for循环中对其重新采样。

    此外,您还可以从单色和对数刻度中获益,使阅读更容易。

    plt.subflots(figsize=(10,10))。
    ico=(icoord.t-icoord.min())/(icoord.max()-icoord.min())
    plt.polar(2*np.pi*ico,-np.log(dcord.t),'b')
    < /代码> 
    .

    那么,让我们把目标分解一下:我不太清楚你想做什么,但我假设你想得到这样的东西polar dendogram

    (source, page 14)

    要渲染类似的东西,您需要能够渲染在极坐标中显示为半圆形的水平线。然后,将水平线映射到极坐标图。

    首先,请注意,您的半径在这一行中没有标准化:

    if polar:
        icoord, dcoord = cartesian_to_polar(icoord, dcoord)
    

    您可以通过简单地重新映射来规范化它们icoord至(0;2PI)。

    现在,让我们尝试绘制更简单的图,而不是复杂的图:

    icoord, dcoord = np.meshgrid(np.r_[1:10], np.r_[1:4])
    
    # Plot the cartesian version
    plot_dendrogram(icoord, dcoord, figsize=(8, 3), polar=False)
    
    # Plot the polar version
    plot_dendrogram(icoord, dcoord, figsize=(5, 5), polar=True)
    

    结果如下:

    regular plot polar plot

    正如你所看到的,极坐标代码并没有将水平线映射到半圆形,因此这是行不通的。让我们一起尝试plt.polar而是:

    plt.polar(icoord.T, dcoord.T)
    

    生产

    plt.polar

    这更像是我们需要的。我们需要先确定角度,然后考虑Y坐标向内(你可能希望它从中心到边界)。归根结底就是这个

    nic = (icoord.T - icoord.min()) / (icoord.max() - icoord.min())
    plt.polar(2 * np.pi * nic, -dcoord.T)
    

    它产生了以下

    polar dendogram

    这和你需要的相似。请注意,直线保持直线,不会被圆弧替换,因此您可能需要在for循环中对其重新采样。

    此外,您还可以从单色和对数刻度中获益,使阅读更容易。

    A better polar dendogram

    plt.subplots(figsize=(10, 10))
    ico = (icoord.T - icoord.min()) / (icoord.max() - icoord.min())
    plt.polar(2 * np.pi * ico, -np.log(dcoord.T), 'b')