![](/img/trans.png)
[英]How can I plot a line with a confidence interval in python using plotly?
[英]How can i plot a truncated dendrogram plot using plotly?
I want to plot a dendrogram plot for hierarchical clustering using plotly and show a small subset of the plot as with the large number of samples the plot can be very dense at the bottom.
我使用 plotly 包裝器 function create_dendrogram 繪制了 plot 和以下代碼:
from scipy.cluster.hierarchy import linkage
import plotly.figure_factory as ff
fig = ff.create_dendrogram(test_df, linkagefun=lambda x: linkage(test_df, 'average', metric='euclidean'))
fig.update_layout(autosize=True, hovermode='closest')
fig.update_xaxes(mirror=False, showgrid=True, showline=False, showticklabels=False)
fig.update_yaxes(mirror=False, showgrid=True, showline=True)
fig.show()
下面是使用 matplotlib 的 plot,scipy 庫默認使用 plot,以便於解釋:
from scipy.cluster.hierarchy import dendrogram,linkage
x = linkage(test_df,method='average')
dendrogram(x,truncate_mode='level',p=4)
plt.show()
如您所見,截斷對於解釋大量樣本非常有用,我如何在 plotly 中實現這一點?
使用ff.create_dendrogram()
似乎沒有直接的方法來做到這一點。 但這並不意味着它是不可能的。 但我至少會考慮Dash Clustergram提供的出色功能。 如果你堅持堅持使用ff.create_dendrogram()
,這將比 Plotly 用戶已經習慣的更混亂。 您還沒有提供數據樣本,所以讓我們改用 Plotly Basic Dendrogram
示例:
import plotly.figure_factory as ff
import numpy as np
np.random.seed(1)
X = np.random.rand(15, 12) # 15 samples, with 12 dimensions each
fig = ff.create_dendrogram(X)
fig.update_layout(width=800, height=500)
f = fig.full_figure_for_development(warn=False)
fig.show()
好消息是,在我們采取了一些我將在下面詳細解釋的步驟之后,完全相同的代碼段將生成以下截斷的 plot。
如果在我的回答中得到這么多的人知道執行以下操作的更好方法,請分享。
ff.create_dendrogram()
是scipy.cluster.hierarchy.dendrogram
的包裝器您可以致電help(ff.create_dendrogram)
並了解:
[...]這是圍繞 scipy.cluster.hierarchy.dendrogram 的薄包裝。
從可用的 arguments 中,您還可以看到似乎沒有人處理與截斷相關的任何事情:
create_dendrogram(X,orientation='bottom',labels=None,colorscale=None,distfun=None,linkagefun=<function at 0x0000016F09D4CEE0>,hovertext=None,color_threshold=None)
scipy.cluster.hierarchy.dendrogram
在這里,當我們將其與源代碼進行比較時,我們可以看到在ff.create_dendrogram(X)
中實現 function 后,一些中心元素被遺漏了:
scipy.cluster.hierarchy.dendrogram(Z, p=30, truncate_mode=None, color_threshold=None, get_leaves=True, orientation='top', labels=None, count_sort=False, distance_sort=False, show_leaf_counts=True, no_plot=False, no_labels=False, leaf_font_size=None, leaf_rotation=None, leaf_label_func=None, show_contracted=False, link_color_func=None, ax=None, above_threshold_color='C0')
truncate_mode
應該正是我們正在尋找的。 所以,現在我們知道scipy
可能擁有我們為截斷樹狀圖構建基礎所需的一切,但下一步是什么?
ff.create_dendrogram(X)
中找到scipy.cluster.hierarchy.dendrogram
隱藏在哪里 ff.create_dendrogram.__code__
將顯示源代碼在系統中的位置。 就我而言,這是:
"C:\Users\vestland\Miniconda3\envs\dashy\lib\site-packages\plotly\figure_factory\_dendrogram.py"
因此,如果您願意,可以仔細查看相應文件夾中的完整源代碼。 如果你這樣做,你會看到一個特別有趣的部分,我們上面列出的一些屬性得到了處理:
def get_dendrogram_traces(
self, X, colorscale, distfun, linkagefun, hovertext, color_threshold
):
"""
Calculates all the elements needed for plotting a dendrogram.
.
.
.
P = sch.dendrogram(
Z,
orientation=self.orientation,
labels=self.labels,
no_plot=True,
color_threshold=color_threshold,
)
在這里,我們處於問題的核心。 完整回答您的問題的第一步就是在P
中包含truncate_mode
和p
,如下所示:
P = sch.dendrogram(
Z,
orientation=self.orientation,
labels=self.labels,
no_plot=True,
color_threshold=color_threshold,
truncate_mode = 'level',
p = 2
)
這是你如何做到的:
在 Python 中,monkey patch 一詞僅指在運行時對 class 或模塊的動態修改,這意味着猴子補丁是一段 Python 代碼在運行時擴展或修改其他代碼。 這是在我們的案例中如何做到這一點的精髓:
import plotly.figure_factory._dendrogram as original_dendrogram
original_dendrogram._Dendrogram.get_dendrogram_traces = modified_dendrogram_traces
其中modified_dendrogram_traces
是modified_dendrogram_traces()
的完整 function 定義以及我已經提到的修改。 以及一些將丟失的導入,否則會在您調用import plotly.figure_factory as ff
時運行
現在足夠詳細了。 下面是全部內容。 如果這是您可以使用的東西,我們也許可以使整個事情比硬編碼truncate_mode = 'level'
和p = 2
更具動態性。
from scipy.cluster.hierarchy import linkage
import plotly.figure_factory as ff
import plotly.figure_factory._dendrogram as original_dendrogram
import numpy as np
def modified_dendrogram_traces(
self, X, colorscale, distfun, linkagefun, hovertext, color_threshold
):
"""
Calculates all the elements needed for plotting a dendrogram.
:param (ndarray) X: Matrix of observations as array of arrays
:param (list) colorscale: Color scale for dendrogram tree clusters
:param (function) distfun: Function to compute the pairwise distance
from the observations
:param (function) linkagefun: Function to compute the linkage matrix
from the pairwise distances
:param (list) hovertext: List of hovertext for constituent traces of dendrogram
:rtype (tuple): Contains all the traces in the following order:
(a) trace_list: List of Plotly trace objects for dendrogram tree
(b) icoord: All X points of the dendrogram tree as array of arrays
with length 4
(c) dcoord: All Y points of the dendrogram tree as array of arrays
with length 4
(d) ordered_labels: leaf labels in the order they are going to
appear on the plot
(e) P['leaves']: left-to-right traversal of the leaves
"""
import plotly
from plotly import exceptions, optional_imports
np = optional_imports.get_module("numpy")
scp = optional_imports.get_module("scipy")
sch = optional_imports.get_module("scipy.cluster.hierarchy")
scs = optional_imports.get_module("scipy.spatial")
sch = optional_imports.get_module("scipy.cluster.hierarchy")
d = distfun(X)
Z = linkagefun(d)
P = sch.dendrogram(
Z,
orientation=self.orientation,
labels=self.labels,
no_plot=True,
color_threshold=color_threshold,
truncate_mode = 'level',
p = 2
)
icoord = scp.array(P["icoord"])
dcoord = scp.array(P["dcoord"])
ordered_labels = scp.array(P["ivl"])
color_list = scp.array(P["color_list"])
colors = self.get_color_dict(colorscale)
trace_list = []
for i in range(len(icoord)):
# xs and ys are arrays of 4 points that make up the '∩' shapes
# of the dendrogram tree
if self.orientation in ["top", "bottom"]:
xs = icoord[i]
else:
xs = dcoord[i]
if self.orientation in ["top", "bottom"]:
ys = dcoord[i]
else:
ys = icoord[i]
color_key = color_list[i]
hovertext_label = None
if hovertext:
hovertext_label = hovertext[i]
trace = dict(
type="scatter",
x=np.multiply(self.sign[self.xaxis], xs),
y=np.multiply(self.sign[self.yaxis], ys),
mode="lines",
marker=dict(color=colors[color_key]),
text=hovertext_label,
hoverinfo="text",
)
try:
x_index = int(self.xaxis[-1])
except ValueError:
x_index = ""
try:
y_index = int(self.yaxis[-1])
except ValueError:
y_index = ""
trace["xaxis"] = "x" + x_index
trace["yaxis"] = "y" + y_index
trace_list.append(trace)
return trace_list, icoord, dcoord, ordered_labels, P["leaves"]
original_dendrogram._Dendrogram.get_dendrogram_traces = modified_dendrogram_traces
X = np.random.rand(15, 12) # 15 samples, with 12 dimensions each
fig = ff.create_dendrogram(X)
fig.update_layout(width=800, height=500)
f = fig.full_figure_for_development(warn=False)
fig.show()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.