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

O.r*_*rka 6 python plot dendrogram polar-coordinates cartesian-coordinates

我正在尝试将以下资源调整到这个问题:

Python之间的坐标转换

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

我似乎无法获得坐标将树状图形状转移到极坐标.

有谁知道如何做到这一点?我知道networkx中有一个实现,但是需要构建一个图形,然后使用pygraphviz后端来获取位置.

有没有办法将树状图笛卡尔坐标转换为极坐标matplotlibnumpy

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)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

我只是尝试了这个,它更接近但仍然不正确:

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)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

cht*_*mon 6

你可以让树的"根"从中间开始,然后在外面留下叶子.你还必须在"bar"部分添加更多的点,以使它看起来漂亮和圆润.

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

seg[1]        seg[2]
+-------------+
|             |
+ seg[0]      + seg[3]
Run Code Online (Sandbox Code Playgroud)

垂直条纹很好,就像两点之间的直线一样,但我们需要更多的点seg[1]seg[2](水平条,需要成为弧形).

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

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

现在我们必须修改绘图功能来计算径向坐标.一些实验已导致我使用的对数公式,基于另一个也使用对数比例的答案.我在右侧为径向标签留下了一个间隙,并对"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))
Run Code Online (Sandbox Code Playgroud)

结果如下图所示:

径向树状图