首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何用极坐标绘制scipy.hierarchy.dendrogram?

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

Stack Overflow用户
提问于 2018-08-20 18:26:23
回答 2查看 2.5K关注 0票数 7

我正在努力使以下资源适应这个问题:

坐标之间的Python转换

scatter.html

我似乎无法得到坐标来将树状图的形状转换为极坐标。

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

有一种方法可以用matplotlib numpy**?**和numpy**?**将树状笛卡尔坐标转换成极坐标。

代码语言:javascript
复制
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)

我刚试了一下,它更接近了,但还是不正确:

代码语言:javascript
复制
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)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-09-26 11:55:24

你可以把树的“根”从中间开始,把叶子放在外面。你还必须增加更多的积分到“酒吧”部分,以使它看起来漂亮和圆。

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

代码语言:javascript
复制
seg[1]        seg[2]
+-------------+
|             |
+ seg[0]      + seg[3]

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

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

代码语言:javascript
复制
def smoothsegment(seg, Nsmooth=100):
    return np.concatenate([[seg[0]], np.linspace(seg[1], seg[2], Nsmooth), [seg[3]]])

现在,我们必须修改绘图函数来计算径向坐标。一些实验已经导致了我正在使用的日志公式,基于另一个答案,它也使用日志标度。我在右边的径向标号上留下了一个空隙,对"icoord“坐标和径向坐标做了一个非常基本的映射,这样标签就对应于矩形图中的坐标。我不知道如何处理径向尺寸。这些数字对于日志是正确的,但是我们可能也想映射它们。

代码语言:javascript
复制
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))

其结果如下:

票数 10
EN

Stack Overflow用户

发布于 2018-09-26 12:20:23

首先,我认为您可能从这个问题中受益。

那么,让我们细分一下目标:我不太清楚你想做什么,但我想你想要得到这样的东西

(资料来源,第14页)

要渲染这样的东西,你需要能够渲染出在极坐标中以半圆的形式出现的水平线。然后,这是一个把你的水平线映射到极地的问题。

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

代码语言:javascript
复制
if polar:
    icoord, dcoord = cartesian_to_polar(icoord, dcoord)

您可以通过简单地将icoord映射为[0;2pi)来使它们正常化。

现在,让我们尝试绘制一些更简单的东西,而不是复杂的情节:

代码语言:javascript
复制
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)

结果如下:

正如您所看到的,极坐标代码不会将水平线映射到半圆,因此这是行不通的。让我们来尝试一下plt.polar

代码语言:javascript
复制
plt.polar(icoord.T, dcoord.T)

产生

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

代码语言:javascript
复制
nic = (icoord.T - icoord.min()) / (icoord.max() - icoord.min())
plt.polar(2 * np.pi * nic, -dcoord.T)

产生以下内容:

这和你所需要的很相似。请注意,直线保持为直线,并且没有被圆弧所取代,因此您可能需要在for循环中对它们进行重采样。

此外,您还可以从单色和日志比例尺中获益,从而使阅读更容易。

代码语言:javascript
复制
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')
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51936574

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档