Skip to content

Commit 79a0c25

Browse files
update(heatmap-basic): bokeh — comprehensive quality review
Comprehensive quality review: fix weaknesses from prior reviews, preserve strengths, improve quality across all dimensions.
1 parent 89f6f3b commit 79a0c25

4 files changed

Lines changed: 87 additions & 76 deletions

File tree

Lines changed: 79 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,122 +1,132 @@
1-
""" pyplots.ai
1+
"""pyplots.ai
22
heatmap-basic: Basic Heatmap
3-
Library: bokeh 3.8.1 | Python 3.13.11
4-
Quality: 92/100 | Created: 2025-12-23
3+
Library: bokeh 3.8.2 | Python 3.14.3
4+
Quality: /100 | Updated: 2026-02-15
55
"""
66

77
import numpy as np
8+
import pandas as pd
89
from bokeh.io import export_png, save
9-
from bokeh.models import BasicTicker, ColorBar, ColumnDataSource, LabelSet, LinearColorMapper
10-
from bokeh.palettes import Viridis256
10+
from bokeh.models import BasicTicker, ColumnDataSource, HoverTool, LabelSet
1111
from bokeh.plotting import figure
1212
from bokeh.resources import CDN
13+
from bokeh.transform import linear_cmap
1314

1415

15-
# Data - Monthly sales performance by product category
16+
# Data - Monthly temperature anomalies (°C) by city
1617
np.random.seed(42)
17-
x_labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug"]
18-
y_labels = ["Product A", "Product B", "Product C", "Product D", "Product E", "Product F"]
19-
20-
# Generate heatmap values (sales performance 0-100)
21-
values = np.random.rand(len(y_labels), len(x_labels)) * 100
22-
23-
# Flatten data for ColumnDataSource
24-
x_data = []
25-
y_data = []
26-
value_data = []
27-
text_data = []
28-
text_color_data = []
29-
30-
for i, y in enumerate(y_labels):
31-
for j, x in enumerate(x_labels):
32-
x_data.append(x)
33-
y_data.append(y)
18+
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct"]
19+
cities = ["Oslo", "Berlin", "Madrid", "Cairo", "Mumbai", "Tokyo", "Sydney"]
20+
21+
# Generate realistic temperature anomalies with geographic patterns
22+
base_anomalies = np.random.randn(len(cities), len(months)) * 0.6
23+
# Northern cities: colder winters, warmer summers
24+
for i, city in enumerate(cities):
25+
seasonal = np.sin(np.linspace(-np.pi / 2, 3 * np.pi / 4, len(months)))
26+
if city in ("Oslo", "Berlin"):
27+
base_anomalies[i] += seasonal * 1.5 - 0.3
28+
elif city in ("Madrid", "Cairo"):
29+
base_anomalies[i] += seasonal * 1.2 + 0.4
30+
elif city == "Mumbai":
31+
base_anomalies[i] += 0.8
32+
elif city == "Sydney":
33+
base_anomalies[i] -= seasonal * 0.9
34+
elif city == "Tokyo":
35+
base_anomalies[i] += seasonal * 0.7
36+
37+
values = np.round(base_anomalies, 1)
38+
39+
# Flatten to DataFrame for ColumnDataSource
40+
records = []
41+
for i, city in enumerate(cities):
42+
for j, month in enumerate(months):
3443
val = values[i, j]
35-
value_data.append(val)
36-
text_data.append(f"{val:.0f}")
37-
# Use white text on dark cells, black on light cells
38-
text_color_data.append("white" if val > 50 else "black")
39-
40-
source = ColumnDataSource(
41-
data={"x": x_data, "y": y_data, "value": value_data, "text": text_data, "text_color": text_color_data}
42-
)
43-
44-
# Color mapper
45-
color_mapper = LinearColorMapper(palette=Viridis256, low=0, high=100)
46-
47-
# Create figure with categorical axes
44+
records.append(
45+
{
46+
"month": month,
47+
"city": city,
48+
"anomaly": val,
49+
"label": f"{val:+.1f}",
50+
"text_color": "white" if abs(val) > 1.2 else "#333333",
51+
}
52+
)
53+
54+
source = ColumnDataSource(pd.DataFrame(records))
55+
56+
# Color mapping — diverging palette for positive/negative anomalies
57+
blues = ["#2166ac", "#4393c3", "#92c5de", "#d1e5f0"]
58+
reds = ["#fddbc7", "#f4a582", "#d6604d", "#b2182b"]
59+
diverging_palette = blues[::-1] + ["#f7f7f7"] + reds
60+
61+
# Create figure
4862
p = figure(
4963
width=4800,
5064
height=2700,
51-
x_range=x_labels,
52-
y_range=y_labels,
65+
x_range=months,
66+
y_range=list(reversed(cities)),
5367
title="heatmap-basic · bokeh · pyplots.ai",
54-
x_axis_label="Month",
55-
y_axis_label="Product",
68+
x_axis_label="Month (2024)",
69+
y_axis_label="City",
5670
toolbar_location=None,
5771
tools="",
5872
)
5973

60-
# Plot heatmap rectangles
61-
p.rect(
62-
x="x",
63-
y="y",
64-
width=1,
65-
height=1,
66-
source=source,
67-
fill_color={"field": "value", "transform": color_mapper},
68-
line_color=None,
69-
)
74+
# Plot heatmap rectangles with linear_cmap
75+
cmap = linear_cmap("anomaly", diverging_palette, low=-2.5, high=2.5)
76+
r = p.rect(x="month", y="city", width=1, height=1, source=source, fill_color=cmap, line_color="white", line_width=2)
7077

71-
# Add value annotations in cells
78+
# Add value annotations
7279
labels = LabelSet(
73-
x="x",
74-
y="y",
75-
text="text",
80+
x="month",
81+
y="city",
82+
text="label",
7683
text_color="text_color",
7784
source=source,
7885
text_align="center",
7986
text_baseline="middle",
80-
text_font_size="24pt",
87+
text_font_size="22pt",
8188
)
8289
p.add_layout(labels)
8390

84-
# Add color bar
85-
color_bar = ColorBar(
86-
color_mapper=color_mapper,
91+
# Color bar from renderer (idiomatic Bokeh pattern)
92+
color_bar = r.construct_color_bar(
93+
width=40,
8794
ticker=BasicTicker(desired_num_ticks=10),
8895
label_standoff=16,
8996
major_label_text_font_size="18pt",
9097
border_line_color=None,
91-
location=(0, 0),
92-
width=40,
93-
title="Sales Score",
98+
padding=10,
99+
title="Anomaly (°C)",
94100
title_text_font_size="20pt",
101+
title_standoff=20,
95102
)
96103
p.add_layout(color_bar, "right")
97104

105+
# HoverTool for interactive HTML version
106+
hover = HoverTool(tooltips=[("City", "@city"), ("Month", "@month"), ("Anomaly", "@anomaly{+0.0} °C")], renderers=[r])
107+
p.add_tools(hover)
108+
98109
# Styling for 4800x2700 px
99110
p.title.text_font_size = "28pt"
100111
p.xaxis.axis_label_text_font_size = "22pt"
101112
p.yaxis.axis_label_text_font_size = "22pt"
102113
p.xaxis.major_label_text_font_size = "18pt"
103114
p.yaxis.major_label_text_font_size = "18pt"
104115

105-
# Grid styling - disabled for heatmap
116+
# Grid and axes
106117
p.xgrid.grid_line_color = None
107118
p.ygrid.grid_line_color = None
108-
109-
# Axis styling
110-
p.axis.axis_line_color = "#cccccc"
111-
p.axis.major_tick_line_color = "#cccccc"
119+
p.axis.axis_line_color = None
120+
p.axis.major_tick_line_color = None
121+
p.outline_line_color = None
112122

113123
# Background
114-
p.background_fill_color = "#f8f8f8"
124+
p.min_border_right = 120
125+
p.background_fill_color = "#fafafa"
115126
p.border_fill_color = "white"
116-
p.outline_line_color = None
117127

118128
# Save PNG
119129
export_png(p, filename="plot.png")
120130

121-
# Save HTML for interactive version
131+
# Save HTML with interactive hover
122132
save(p, filename="plot.html", resources=CDN, title="heatmap-basic · bokeh · pyplots.ai")

plots/heatmap-basic/metadata/bokeh.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
library: bokeh
22
specification_id: heatmap-basic
33
created: '2025-12-23T00:48:06Z'
4-
updated: '2025-12-23T01:21:11Z'
5-
generated_by: claude-opus-4-5-20251101
4+
updated: '2026-02-15T21:25:00+00:00'
5+
generated_by: claude-opus-4-6
66
workflow_run: 20447966194
77
issue: 0
8-
python_version: 3.13.11
9-
library_version: 3.8.1
8+
python_version: 3.14.3
9+
library_version: 3.8.2
1010
preview_url: https://storage.googleapis.com/pyplots-images/plots/heatmap-basic/bokeh/plot.png
1111
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/heatmap-basic/bokeh/plot_thumb.png
1212
preview_html: https://storage.googleapis.com/pyplots-images/plots/heatmap-basic/bokeh/plot.html
13-
quality_score: 92
13+
quality_score: null
1414
impl_tags:
1515
dependencies: []
1616
techniques:

plots/heatmap-basic/specification.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@ A heatmap displaying values in a matrix format using color intensity. Each cell'
2323
- Use a diverging colormap for data with positive/negative values
2424
- Add value annotations in cells when readable
2525
- Include a colorbar legend
26-
- Consider clustering rows/columns for better pattern visibility
26+
- Order rows/columns logically (alphabetical, by magnitude, or by similarity)

plots/heatmap-basic/specification.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ title: Basic Heatmap
66

77
# Specification tracking
88
created: 2025-12-14T09:02:34Z
9-
updated: 2025-12-14T09:02:34Z
9+
updated: 2026-02-15T12:00:00Z
1010
issue: 691
1111
suggested: MarkusNeusinger
1212

@@ -18,6 +18,7 @@ tags:
1818
data_type:
1919
- numeric
2020
- categorical
21+
- matrix
2122
domain:
2223
- statistics
2324
- general

0 commit comments

Comments
 (0)