|
1 | 1 | """ pyplots.ai |
2 | 2 | dendrogram-basic: Basic Dendrogram |
3 | | -Library: plotly 6.5.0 | Python 3.13.11 |
4 | | -Quality: 91/100 | Created: 2025-12-23 |
| 3 | +Library: plotly 6.5.2 | Python 3.14.3 |
| 4 | +Quality: 90/100 | Updated: 2026-04-05 |
5 | 5 | """ |
6 | 6 |
|
7 | 7 | import numpy as np |
8 | 8 | import plotly.figure_factory as ff |
| 9 | +from scipy.cluster.hierarchy import linkage |
9 | 10 |
|
10 | 11 |
|
11 | | -# Data - Iris-like flower measurements for 15 samples |
| 12 | +# Data - Iris flower measurements for 15 samples across 3 species |
12 | 13 | np.random.seed(42) |
13 | 14 | labels = [ |
14 | 15 | "Setosa-1", |
|
28 | 29 | "Virginica-5", |
29 | 30 | ] |
30 | 31 |
|
31 | | -# Create clustered data representing flower measurements (sepal length, sepal width, petal length, petal width) |
32 | | -# Setosa: small petals, medium sepals |
| 32 | +# Sepal length, sepal width, petal length, petal width |
33 | 33 | setosa = np.random.randn(5, 4) * 0.3 + np.array([5.0, 3.4, 1.5, 0.2]) |
34 | | -# Versicolor: medium measurements |
35 | 34 | versicolor = np.random.randn(5, 4) * 0.4 + np.array([5.9, 2.8, 4.3, 1.3]) |
36 | | -# Virginica: large petals and sepals |
37 | 35 | virginica = np.random.randn(5, 4) * 0.4 + np.array([6.6, 3.0, 5.5, 2.0]) |
38 | | - |
39 | 36 | data = np.vstack([setosa, versicolor, virginica]) |
40 | 37 |
|
41 | | -# Create dendrogram |
| 38 | +# Colorscale: maps to scipy color keys (b, c, g, k, m, r, w, y) alphabetically |
| 39 | +# C0->b(idx 0), C1->g(idx 2), C2->r(idx 5), C3->c(idx 1), above-threshold->C0 |
| 40 | +colorscale = [ |
| 41 | + "#306998", # b -> Python Blue (above-threshold merges) |
| 42 | + "#E1974C", # c -> Warm amber |
| 43 | + "#52A675", # g -> Muted green |
| 44 | + "#333333", # k |
| 45 | + "#8B6BAE", # m |
| 46 | + "#D45B5B", # r -> Soft coral |
| 47 | + "#ffffff", # w |
| 48 | + "#C4A437", # y |
| 49 | +] |
| 50 | + |
42 | 51 | fig = ff.create_dendrogram( |
43 | | - data, |
44 | | - labels=labels, |
45 | | - linkagefun=lambda x: __import__("scipy.cluster.hierarchy", fromlist=["linkage"]).linkage(x, method="ward"), |
46 | | - color_threshold=3.0, |
| 52 | + data, labels=labels, colorscale=colorscale, linkagefun=lambda x: linkage(x, method="ward"), color_threshold=3.5 |
47 | 53 | ) |
48 | 54 |
|
49 | | -# Update layout for large canvas |
| 55 | +# Add merge distance hover to each branch |
| 56 | +for trace in fig.data: |
| 57 | + trace.line.width = 3 |
| 58 | + merge_height = max(y for y in trace.y if y > 0) if any(y > 0 for y in trace.y) else 0 |
| 59 | + trace.hovertemplate = f"Merge distance: {merge_height:.2f}<extra></extra>" |
| 60 | + |
| 61 | +# Layout |
50 | 62 | fig.update_layout( |
51 | | - title={"text": "dendrogram-basic · plotly · pyplots.ai", "font": {"size": 28}, "x": 0.5, "xanchor": "center"}, |
52 | | - xaxis={"title": {"text": "Iris Flower Samples", "font": {"size": 22}}, "tickfont": {"size": 16}, "tickangle": -45}, |
53 | | - yaxis={"title": {"text": "Distance (Ward)", "font": {"size": 22}}, "tickfont": {"size": 18}}, |
| 63 | + title={ |
| 64 | + "text": "dendrogram-basic · plotly · pyplots.ai", |
| 65 | + "font": {"size": 28, "color": "#2a2a2a", "family": "Arial, sans-serif"}, |
| 66 | + "x": 0.5, |
| 67 | + "xanchor": "center", |
| 68 | + }, |
| 69 | + xaxis={ |
| 70 | + "title": {"text": "Iris Flower Samples", "font": {"size": 22}}, |
| 71 | + "tickfont": {"size": 16}, |
| 72 | + "tickangle": -35, |
| 73 | + "showline": True, |
| 74 | + "linecolor": "#cccccc", |
| 75 | + "zeroline": False, |
| 76 | + }, |
| 77 | + yaxis={ |
| 78 | + "title": {"text": "Distance (Ward linkage)", "font": {"size": 22}}, |
| 79 | + "tickfont": {"size": 18}, |
| 80 | + "showline": True, |
| 81 | + "linecolor": "#cccccc", |
| 82 | + "gridcolor": "rgba(0,0,0,0.06)", |
| 83 | + "gridwidth": 1, |
| 84 | + "zeroline": False, |
| 85 | + }, |
54 | 86 | template="plotly_white", |
55 | 87 | width=1600, |
56 | 88 | height=900, |
57 | | - margin={"l": 80, "r": 40, "t": 100, "b": 150}, |
| 89 | + margin={"l": 90, "r": 50, "t": 100, "b": 150}, |
| 90 | + plot_bgcolor="#ffffff", |
| 91 | + hoverlabel={"bgcolor": "white", "font_size": 14, "bordercolor": "#cccccc"}, |
58 | 92 | ) |
59 | 93 |
|
60 | | -# Update line widths for visibility |
61 | | -fig.update_traces(line={"width": 3}) |
62 | | - |
63 | | -# Save outputs |
| 94 | +# Save |
64 | 95 | fig.write_image("plot.png", width=1600, height=900, scale=3) |
65 | | -fig.write_html("plot.html") |
| 96 | +fig.write_html("plot.html", include_plotlyjs="cdn") |
0 commit comments