Skip to content

Commit b4f3cd4

Browse files
fix(bokeh): address review feedback for column-stratigraphic
Attempt 1/3 - fixes based on AI review
1 parent 98f0167 commit b4f3cd4

1 file changed

Lines changed: 45 additions & 42 deletions

File tree

  • plots/column-stratigraphic/implementations

plots/column-stratigraphic/implementations/bokeh.py

Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,51 @@
1-
""" pyplots.ai
1+
"""pyplots.ai
22
column-stratigraphic: Stratigraphic Column with Lithology Patterns
33
Library: bokeh 3.9.0 | Python 3.14.3
4-
Quality: 83/100 | Created: 2026-03-15
54
"""
65

76
from bokeh.io import export_png
8-
from bokeh.models import ColumnDataSource, HoverTool, Label, Legend, LegendItem, Range1d
7+
from bokeh.models import ColumnDataSource, HoverTool, Label, Legend, LegendItem, Range1d, Span
98
from bokeh.plotting import figure, output_file, save
109

1110

12-
# Data: Synthetic sedimentary section with 10 layers
11+
# Data: Synthetic sedimentary section with 10 layers (varied thicknesses)
1312
layers = [
14-
{"top": 0, "bottom": 15, "lithology": "Sandstone", "formation": "Dakota Fm", "age": "Late Cretaceous"},
15-
{"top": 15, "bottom": 35, "lithology": "Shale", "formation": "Mancos Fm", "age": "Late Cretaceous"},
16-
{"top": 35, "bottom": 50, "lithology": "Limestone", "formation": "Niobrara Fm", "age": "Late Cretaceous"},
17-
{"top": 50, "bottom": 65, "lithology": "Siltstone", "formation": "Pierre Fm", "age": "Late Cretaceous"},
18-
{"top": 65, "bottom": 90, "lithology": "Sandstone", "formation": "Fox Hills Fm", "age": "Late Cretaceous"},
19-
{"top": 90, "bottom": 110, "lithology": "Conglomerate", "formation": "Dawson Fm", "age": "Paleocene"},
20-
{"top": 110, "bottom": 135, "lithology": "Shale", "formation": "Green River Fm", "age": "Eocene"},
21-
{"top": 135, "bottom": 155, "lithology": "Limestone", "formation": "Leadville Fm", "age": "Eocene"},
22-
{"top": 155, "bottom": 175, "lithology": "Sandstone", "formation": "Wasatch Fm", "age": "Eocene"},
23-
{"top": 175, "bottom": 200, "lithology": "Siltstone", "formation": "Uinta Fm", "age": "Eocene"},
13+
{"top": 0, "bottom": 12, "lithology": "Sandstone", "formation": "Dakota Fm", "age": "Late Cretaceous"},
14+
{"top": 12, "bottom": 38, "lithology": "Shale", "formation": "Mancos Fm", "age": "Late Cretaceous"},
15+
{"top": 38, "bottom": 52, "lithology": "Limestone", "formation": "Niobrara Fm", "age": "Late Cretaceous"},
16+
{"top": 52, "bottom": 60, "lithology": "Siltstone", "formation": "Pierre Fm", "age": "Late Cretaceous"},
17+
{"top": 60, "bottom": 88, "lithology": "Sandstone", "formation": "Fox Hills Fm", "age": "Late Cretaceous"},
18+
{"top": 88, "bottom": 112, "lithology": "Conglomerate", "formation": "Dawson Fm", "age": "Paleocene"},
19+
{"top": 112, "bottom": 140, "lithology": "Shale", "formation": "Green River Fm", "age": "Eocene"},
20+
{"top": 140, "bottom": 158, "lithology": "Limestone", "formation": "Leadville Fm", "age": "Eocene"},
21+
{"top": 158, "bottom": 180, "lithology": "Sandstone", "formation": "Wasatch Fm", "age": "Eocene"},
22+
{"top": 180, "bottom": 200, "lithology": "Siltstone", "formation": "Uinta Fm", "age": "Eocene"},
2423
]
2524

26-
# Lithology style mapping: color, hatch_pattern
25+
# Lithology style mapping: color, hatch_pattern (improved color differentiation)
2726
lithology_styles = {
2827
"Sandstone": {"color": "#F5DEB3", "hatch_pattern": ".", "hatch_color": "#8B7355"},
2928
"Shale": {"color": "#A9A9A9", "hatch_pattern": "-", "hatch_color": "#4A4A4A"},
3029
"Limestone": {"color": "#87CEEB", "hatch_pattern": "+", "hatch_color": "#2E5A88"},
31-
"Siltstone": {"color": "#C4B7A6", "hatch_pattern": "/", "hatch_color": "#6B5B4A"},
32-
"Conglomerate": {"color": "#D2691E", "hatch_pattern": "o", "hatch_color": "#5C2E00"},
30+
"Siltstone": {"color": "#8B6F5E", "hatch_pattern": "/", "hatch_color": "#3E2F23"},
31+
"Conglomerate": {"color": "#E8923F", "hatch_pattern": "o", "hatch_color": "#6B3A00"},
3332
}
3433

35-
# Build data arrays
36-
tops = [layer["top"] for layer in layers]
37-
bottoms = [layer["bottom"] for layer in layers]
38-
lithologies = [layer["lithology"] for layer in layers]
39-
formations = [layer["formation"] for layer in layers]
40-
ages = [layer["age"] for layer in layers]
41-
thicknesses = [layer["bottom"] - layer["top"] for layer in layers]
42-
43-
fill_colors = [lithology_styles[lith]["color"] for lith in lithologies]
44-
hatch_patterns = [lithology_styles[lith]["hatch_pattern"] for lith in lithologies]
45-
hatch_colors = [lithology_styles[lith]["hatch_color"] for lith in lithologies]
46-
47-
# Column x-position and width
48-
col_left = 0.0
49-
col_right = 1.0
34+
# K-Pg boundary depth (between Fox Hills Fm / Late Cretaceous and Dawson Fm / Paleocene)
35+
KPG_DEPTH = 88
36+
37+
# Column x-position and width (wider column for better canvas use)
5038
col_center = 0.5
5139
col_width = 1.0
5240

53-
# Plot
41+
# Plot (tighter x_range for better horizontal utilization)
5442
p = figure(
5543
width=4800,
5644
height=2700,
5745
title="column-stratigraphic · bokeh · pyplots.ai",
5846
y_axis_label="Depth (m)",
5947
toolbar_location=None,
60-
x_range=Range1d(-0.8, 2.5),
48+
x_range=Range1d(-0.7, 2.0),
6149
y_range=Range1d(210, -10),
6250
)
6351

@@ -96,12 +84,10 @@
9684
hatch_weight=2,
9785
)
9886

99-
# Track renderers for legend (one entry per lithology)
10087
lith = layer["lithology"]
10188
if lith not in legend_items_dict:
10289
legend_items_dict[lith] = renderer
10390

104-
# Hover tool per layer
10591
hover = HoverTool(
10692
renderers=[renderer],
10793
tooltips=[
@@ -115,11 +101,28 @@
115101
)
116102
p.add_tools(hover)
117103

104+
# K-Pg boundary emphasis — bold red dashed line with annotation
105+
kpg_span = Span(location=KPG_DEPTH, dimension="width", line_color="#CC0000", line_width=4, line_dash="dashed")
106+
p.add_layout(kpg_span)
107+
108+
kpg_label = Label(
109+
x=col_center,
110+
y=KPG_DEPTH,
111+
text="K-Pg Boundary (~66 Ma)",
112+
text_font_size="16pt",
113+
text_font_style="bold",
114+
text_color="#CC0000",
115+
text_align="center",
116+
text_baseline="bottom",
117+
y_offset=8,
118+
)
119+
p.add_layout(kpg_label)
120+
118121
# Formation labels on the right side
119122
for layer in layers:
120123
mid_y = (layer["top"] + layer["bottom"]) / 2
121124
label = Label(
122-
x=col_right + 0.08,
125+
x=1.08,
123126
y=mid_y,
124127
text=layer["formation"],
125128
text_font_size="18pt",
@@ -129,7 +132,7 @@
129132
)
130133
p.add_layout(label)
131134

132-
# Age labels on the left side
135+
# Age labels on the left side with brackets
133136
age_groups = {}
134137
for layer in layers:
135138
age = layer["age"]
@@ -153,16 +156,15 @@
153156
)
154157
p.add_layout(label)
155158

156-
# Draw bracket line for age span
157159
p.line(x=[-0.05, -0.05], y=[bounds["top"], bounds["bottom"]], line_color="#2C2C2C", line_width=2)
158160
p.line(x=[-0.07, -0.05], y=[bounds["top"], bounds["top"]], line_color="#2C2C2C", line_width=2)
159161
p.line(x=[-0.07, -0.05], y=[bounds["bottom"], bounds["bottom"]], line_color="#2C2C2C", line_width=2)
160162

161-
# Legend
163+
# Legend — positioned adjacent to column, not in far corner
162164
legend_items = [LegendItem(label=lith, renderers=[rend]) for lith, rend in legend_items_dict.items()]
163165
legend = Legend(
164166
items=legend_items,
165-
location="bottom_right",
167+
location="top_right",
166168
label_text_font_size="20pt",
167169
spacing=12,
168170
padding=20,
@@ -173,7 +175,7 @@
173175
title_text_font_size="22pt",
174176
title_text_font_style="bold",
175177
)
176-
p.add_layout(legend)
178+
p.add_layout(legend, "right")
177179

178180
# Style
179181
p.title.text_font_size = "36pt"
@@ -187,6 +189,7 @@
187189

188190
p.yaxis.minor_tick_line_color = None
189191
p.outline_line_color = None
192+
p.background_fill_color = "#FAFAFA"
190193

191194
# Save
192195
export_png(p, filename="plot.png")

0 commit comments

Comments
 (0)