|
1 | 1 | """ pyplots.ai |
2 | 2 | heatmap-basic: Basic Heatmap |
3 | | -Library: altair 6.0.0 | Python 3.13.11 |
4 | | -Quality: 91/100 | Created: 2025-12-23 |
| 3 | +Library: altair 6.0.0 | Python 3.14.3 |
| 4 | +Quality: 88/100 | Updated: 2026-02-16 |
5 | 5 | """ |
6 | 6 |
|
7 | 7 | import altair as alt |
8 | 8 | import numpy as np |
9 | 9 | import pandas as pd |
10 | 10 |
|
11 | 11 |
|
12 | | -# Data - create a matrix with patterns |
| 12 | +# Data - correlation matrix with realistic weather variables |
13 | 13 | np.random.seed(42) |
14 | | -rows = ["Row A", "Row B", "Row C", "Row D", "Row E", "Row F", "Row G", "Row H"] |
15 | | -cols = ["Col 1", "Col 2", "Col 3", "Col 4", "Col 5", "Col 6", "Col 7", "Col 8"] |
| 14 | +variables = [ |
| 15 | + "Temperature", |
| 16 | + "Humidity", |
| 17 | + "Wind Speed", |
| 18 | + "Pressure", |
| 19 | + "Visibility", |
| 20 | + "Cloud Cover", |
| 21 | + "Precipitation", |
| 22 | + "UV Index", |
| 23 | +] |
16 | 24 |
|
17 | | -# Generate values with some patterns (diagonal pattern + noise) |
18 | | -values = [] |
19 | | -for i, row in enumerate(rows): |
20 | | - for j, col in enumerate(cols): |
21 | | - # Create pattern: higher values near diagonal, add noise |
22 | | - base = 100 - abs(i - j) * 12 |
23 | | - noise = np.random.randn() * 10 |
24 | | - values.append({"x": col, "y": row, "value": base + noise}) |
| 25 | +n_samples = 200 |
| 26 | +raw = np.random.randn(n_samples, len(variables)) |
25 | 27 |
|
26 | | -df = pd.DataFrame(values) |
| 28 | +# Inject realistic correlations with stronger relationships |
| 29 | +raw[:, 1] += raw[:, 0] * 0.6 # Humidity ~ Temperature |
| 30 | +raw[:, 5] += raw[:, 1] * 0.7 # Cloud Cover ~ Humidity |
| 31 | +raw[:, 6] += raw[:, 5] * 0.65 # Precipitation ~ Cloud Cover |
| 32 | +raw[:, 4] -= raw[:, 5] * 0.9 # Visibility inversely ~ Cloud Cover |
| 33 | +raw[:, 7] -= raw[:, 5] * 0.7 # UV Index inversely ~ Cloud Cover |
| 34 | +raw[:, 7] += raw[:, 0] * 0.5 # UV Index ~ Temperature |
| 35 | +raw[:, 3] -= raw[:, 0] * 0.4 # Pressure inversely ~ Temperature |
| 36 | +raw[:, 2] += raw[:, 3] * 0.3 # Wind Speed ~ Pressure |
27 | 37 |
|
28 | | -# Plot - heatmap base |
| 38 | +corr = np.corrcoef(raw.T) |
| 39 | + |
| 40 | +# Build long-form dataframe using list comprehension |
| 41 | +df = pd.DataFrame( |
| 42 | + [ |
| 43 | + {"Row": row_var, "Column": col_var, "value": round(corr[i, j], 2)} |
| 44 | + for i, row_var in enumerate(variables) |
| 45 | + for j, col_var in enumerate(variables) |
| 46 | + ] |
| 47 | +) |
| 48 | + |
| 49 | +# Axis ordering |
| 50 | +axis_order = list(variables) |
| 51 | + |
| 52 | +# Plot - heatmap with colorblind-safe diverging color centered at 0 |
29 | 53 | heatmap = ( |
30 | 54 | alt.Chart(df) |
31 | | - .mark_rect() |
| 55 | + .mark_rect(stroke="#ffffff", strokeWidth=1.5, cornerRadius=2) |
32 | 56 | .encode( |
33 | | - x=alt.X("x:N", title="Column", axis=alt.Axis(labelFontSize=16, titleFontSize=20)), |
34 | | - y=alt.Y("y:N", title="Row", axis=alt.Axis(labelFontSize=16, titleFontSize=20)), |
| 57 | + x=alt.X( |
| 58 | + "Column:N", |
| 59 | + title="Weather Variable", |
| 60 | + sort=axis_order, |
| 61 | + axis=alt.Axis( |
| 62 | + labelFontSize=15, titleFontSize=18, labelAngle=-45, orient="top", labelPadding=8, titlePadding=10 |
| 63 | + ), |
| 64 | + ), |
| 65 | + y=alt.Y( |
| 66 | + "Row:N", |
| 67 | + title="Weather Variable", |
| 68 | + sort=axis_order, |
| 69 | + axis=alt.Axis(labelFontSize=15, titleFontSize=18, labelPadding=8, titlePadding=10), |
| 70 | + ), |
35 | 71 | color=alt.Color( |
36 | 72 | "value:Q", |
37 | | - scale=alt.Scale(scheme="blueorange", domainMid=50), |
38 | | - legend=alt.Legend(title="Value", titleFontSize=18, labelFontSize=16), |
| 73 | + scale=alt.Scale(scheme="blueorange", domain=[-1, 1], domainMid=0), |
| 74 | + legend=alt.Legend( |
| 75 | + title="Correlation", |
| 76 | + titleFontSize=16, |
| 77 | + labelFontSize=14, |
| 78 | + gradientLength=300, |
| 79 | + gradientThickness=16, |
| 80 | + titlePadding=6, |
| 81 | + offset=8, |
| 82 | + direction="vertical", |
| 83 | + ), |
39 | 84 | ), |
40 | | - tooltip=["x:N", "y:N", "value:Q"], |
| 85 | + tooltip=[ |
| 86 | + alt.Tooltip("Column:N", title="Column"), |
| 87 | + alt.Tooltip("Row:N", title="Row"), |
| 88 | + alt.Tooltip("value:Q", title="Correlation", format=".2f"), |
| 89 | + ], |
41 | 90 | ) |
42 | 91 | ) |
43 | 92 |
|
44 | | -# Add text annotations |
| 93 | +# Highlight cells with strong correlations using thicker borders |
| 94 | +highlight = ( |
| 95 | + alt.Chart(df) |
| 96 | + .transform_filter((alt.datum.value >= 0.7) | (alt.datum.value <= -0.7)) |
| 97 | + .mark_rect(stroke="#2a2a2a", strokeWidth=2.5, filled=False, cornerRadius=2) |
| 98 | + .encode(x=alt.X("Column:N", sort=axis_order), y=alt.Y("Row:N", sort=axis_order)) |
| 99 | +) |
| 100 | + |
| 101 | +# Text annotations with adaptive color |
45 | 102 | text = ( |
46 | 103 | alt.Chart(df) |
47 | | - .mark_text(fontSize=18) |
| 104 | + .mark_text(fontSize=15, fontWeight="bold") |
48 | 105 | .encode( |
49 | | - x=alt.X("x:N"), |
50 | | - y=alt.Y("y:N"), |
51 | | - text=alt.Text("value:Q", format=".0f"), |
52 | | - color=alt.condition(alt.datum.value > 70, alt.value("white"), alt.value("black")), |
| 106 | + x=alt.X("Column:N", sort=axis_order), |
| 107 | + y=alt.Y("Row:N", sort=axis_order), |
| 108 | + text=alt.Text("value:Q", format=".2f"), |
| 109 | + color=alt.when((alt.datum.value > 0.55) | (alt.datum.value < -0.55)) |
| 110 | + .then(alt.value("#ffffff")) |
| 111 | + .otherwise(alt.value("#333333")), |
53 | 112 | ) |
54 | 113 | ) |
55 | 114 |
|
56 | | -# Combine heatmap and text, then apply configuration |
| 115 | +# Combine layers and configure |
57 | 116 | chart = ( |
58 | | - (heatmap + text) |
59 | | - .properties(width=1400, height=800, title=alt.Title("heatmap-basic · altair · pyplots.ai", fontSize=28)) |
60 | | - .configure_axis(labelFontSize=16, titleFontSize=20, grid=False) |
| 117 | + (heatmap + highlight + text) |
| 118 | + .properties( |
| 119 | + width=740, |
| 120 | + height=766, |
| 121 | + title=alt.Title( |
| 122 | + "heatmap-basic · altair · pyplots.ai", |
| 123 | + subtitle=[ |
| 124 | + "Pairwise Pearson correlation coefficients for 8 weather metrics.", |
| 125 | + "Bold borders highlight strong relationships (|r| ≥ 0.7).", |
| 126 | + ], |
| 127 | + fontSize=26, |
| 128 | + subtitleFontSize=16, |
| 129 | + subtitleColor="#666666", |
| 130 | + anchor="start", |
| 131 | + offset=16, |
| 132 | + ), |
| 133 | + padding={"left": 20, "right": 20, "top": 20, "bottom": 20}, |
| 134 | + ) |
| 135 | + .configure_axis(grid=False) |
61 | 136 | .configure_view(strokeWidth=0) |
62 | 137 | ) |
63 | 138 |
|
64 | | -# Save |
65 | | -chart.save("plot.png", scale_factor=3.0) |
| 139 | +# Save — target: 3600×3600 square format |
| 140 | +chart.save("plot.png", scale_factor=3.6) |
66 | 141 | chart.save("plot.html") |
0 commit comments