|
1 | | -""" pyplots.ai |
| 1 | +"""pyplots.ai |
2 | 2 | column-stratigraphic: Stratigraphic Column with Lithology Patterns |
3 | 3 | Library: plotly 6.6.0 | Python 3.14.3 |
4 | 4 | Quality: 86/100 | Created: 2026-03-15 |
|
7 | 7 | import plotly.graph_objects as go |
8 | 8 |
|
9 | 9 |
|
10 | | -# Data - synthetic sedimentary section with 10 layers |
| 10 | +# Data - synthetic sedimentary section based on Western Interior Seaway formations |
11 | 11 | layers = [ |
12 | 12 | {"top": 0, "bottom": 15, "lithology": "Sandstone", "formation": "Dakota Fm", "age": "Late Cretaceous"}, |
13 | 13 | {"top": 15, "bottom": 30, "lithology": "Shale", "formation": "Graneros Sh", "age": "Late Cretaceous"}, |
|
21 | 21 | {"top": 170, "bottom": 195, "lithology": "Sandstone", "formation": "Wasatch Fm", "age": "Eocene"}, |
22 | 22 | ] |
23 | 23 |
|
| 24 | +# Refined earth-tone palette with Python Blue accent for limestone |
24 | 25 | lithology_styles = { |
25 | | - "Sandstone": {"color": "#F5DEB3", "pattern_shape": ".", "pattern_size": 8}, |
26 | | - "Shale": {"color": "#8B8682", "pattern_shape": "-", "pattern_size": 6}, |
27 | | - "Limestone": {"color": "#87CEEB", "pattern_shape": "+", "pattern_size": 8}, |
28 | | - "Siltstone": {"color": "#C4A882", "pattern_shape": "/", "pattern_size": 6}, |
29 | | - "Conglomerate": {"color": "#D2691E", "pattern_shape": "x", "pattern_size": 10}, |
| 26 | + "Sandstone": {"color": "#E8D5A3", "pattern_shape": ".", "pattern_size": 8}, |
| 27 | + "Shale": {"color": "#9E9A91", "pattern_shape": "-", "pattern_size": 6}, |
| 28 | + "Limestone": {"color": "#7BA7C9", "pattern_shape": "+", "pattern_size": 8}, |
| 29 | + "Siltstone": {"color": "#C9B897", "pattern_shape": "/", "pattern_size": 6}, |
| 30 | + "Conglomerate": {"color": "#B8763C", "pattern_shape": "x", "pattern_size": 10}, |
| 31 | +} |
| 32 | + |
| 33 | +# Age boundary colors for subtle background shading |
| 34 | +age_colors = { |
| 35 | + "Late Cretaceous": "rgba(48, 105, 152, 0.04)", |
| 36 | + "Maastrichtian": "rgba(48, 105, 152, 0.08)", |
| 37 | + "Paleocene": "rgba(48, 105, 152, 0.12)", |
| 38 | + "Eocene": "rgba(48, 105, 152, 0.16)", |
30 | 39 | } |
31 | 40 |
|
32 | 41 | # Plot |
33 | 42 | fig = go.Figure() |
34 | 43 |
|
| 44 | +# Group consecutive layers by age for boundary markers and left-side labels |
| 45 | +age_groups = [] |
| 46 | +current_age = layers[0]["age"] |
| 47 | +current_top = layers[0]["top"] |
| 48 | +prev_bottom = layers[0]["bottom"] |
| 49 | +for layer in layers: |
| 50 | + if layer["age"] != current_age: |
| 51 | + age_groups.append({"age": current_age, "top": current_top, "bottom": prev_bottom}) |
| 52 | + current_age = layer["age"] |
| 53 | + current_top = layer["top"] |
| 54 | + prev_bottom = layer["bottom"] |
| 55 | +age_groups.append({"age": current_age, "top": current_top, "bottom": prev_bottom}) |
| 56 | + |
| 57 | +# Add subtle age-period background shading using shapes |
| 58 | +for group in age_groups: |
| 59 | + fig.add_shape( |
| 60 | + type="rect", |
| 61 | + x0=0.3, |
| 62 | + x1=1.95, |
| 63 | + y0=group["top"], |
| 64 | + y1=group["bottom"], |
| 65 | + fillcolor=age_colors.get(group["age"], "rgba(0,0,0,0.02)"), |
| 66 | + line={"width": 0}, |
| 67 | + layer="below", |
| 68 | + ) |
| 69 | + |
| 70 | +# Add age boundary lines (heavier horizontal lines at period transitions) |
| 71 | +for i in range(1, len(age_groups)): |
| 72 | + boundary_depth = age_groups[i]["top"] |
| 73 | + fig.add_shape( |
| 74 | + type="line", |
| 75 | + x0=0.3, |
| 76 | + x1=1.95, |
| 77 | + y0=boundary_depth, |
| 78 | + y1=boundary_depth, |
| 79 | + line={"color": "#306998", "width": 2.5, "dash": "dot"}, |
| 80 | + layer="above", |
| 81 | + ) |
| 82 | + |
| 83 | +# Add layer bars |
35 | 84 | for layer in layers: |
36 | 85 | style = lithology_styles[layer["lithology"]] |
37 | 86 | thickness = layer["bottom"] - layer["top"] |
|
49 | 98 | "shape": style["pattern_shape"], |
50 | 99 | "size": style["pattern_size"], |
51 | 100 | "solidity": 0.6, |
52 | | - "fgcolor": "rgba(0,0,0,0.5)", |
| 101 | + "fgcolor": "rgba(0,0,0,0.45)", |
53 | 102 | }, |
54 | | - "line": {"color": "black", "width": 1.5}, |
| 103 | + "line": {"color": "#2C2C2C", "width": 1.5}, |
55 | 104 | }, |
56 | | - width=0.6, |
| 105 | + width=0.65, |
57 | 106 | showlegend=False, |
58 | 107 | hovertemplate=( |
59 | 108 | f"<b>{layer['formation']}</b><br>" |
60 | 109 | f"Lithology: {layer['lithology']}<br>" |
61 | 110 | f"Depth: {layer['top']}–{layer['bottom']} m<br>" |
| 111 | + f"Thickness: {thickness} m<br>" |
62 | 112 | f"Age: {layer['age']}" |
63 | 113 | "<extra></extra>" |
64 | 114 | ), |
65 | 115 | ) |
66 | 116 | ) |
67 | 117 |
|
68 | | - # Formation name annotation (right side) |
| 118 | + # Formation name annotation (right side) - increased font size |
69 | 119 | fig.add_annotation( |
70 | | - x=1.42, |
| 120 | + x=1.38, |
71 | 121 | y=mid_depth, |
72 | 122 | text=f"<b>{layer['formation']}</b><br><i>{layer['lithology']}</i>", |
73 | 123 | showarrow=False, |
74 | | - font={"size": 13}, |
| 124 | + font={"size": 15, "color": "#1A1A1A"}, |
75 | 125 | xanchor="left", |
76 | 126 | yanchor="middle", |
77 | 127 | ) |
78 | 128 |
|
79 | | -# Group consecutive layers by age for left-side labels |
80 | | -age_groups = [] |
81 | | -current_age = layers[0]["age"] |
82 | | -current_top = layers[0]["top"] |
83 | | -prev_bottom = layers[0]["bottom"] |
84 | | -for layer in layers: |
85 | | - if layer["age"] != current_age: |
86 | | - age_groups.append({"age": current_age, "top": current_top, "bottom": prev_bottom}) |
87 | | - current_age = layer["age"] |
88 | | - current_top = layer["top"] |
89 | | - prev_bottom = layer["bottom"] |
90 | | -age_groups.append({"age": current_age, "top": current_top, "bottom": prev_bottom}) |
91 | | - |
| 129 | +# Age labels on the left side |
92 | 130 | for group in age_groups: |
93 | 131 | mid = (group["top"] + group["bottom"]) / 2 |
94 | 132 | fig.add_annotation( |
95 | | - x=0.58, |
| 133 | + x=0.55, |
96 | 134 | y=mid, |
97 | | - text=f"<i>{group['age']}</i>", |
| 135 | + text=f"<b>{group['age']}</b>", |
98 | 136 | showarrow=False, |
99 | | - font={"size": 12, "color": "#444444"}, |
| 137 | + font={"size": 14, "color": "#306998"}, |
100 | 138 | xanchor="right", |
101 | 139 | yanchor="middle", |
102 | 140 | ) |
103 | 141 |
|
104 | | -# Legend for lithology types |
| 142 | +# Legend for lithology types with pattern swatches |
105 | 143 | for lithology, style in lithology_styles.items(): |
106 | 144 | fig.add_trace( |
107 | 145 | go.Bar( |
|
113 | 151 | "shape": style["pattern_shape"], |
114 | 152 | "size": style["pattern_size"], |
115 | 153 | "solidity": 0.6, |
116 | | - "fgcolor": "rgba(0,0,0,0.5)", |
| 154 | + "fgcolor": "rgba(0,0,0,0.45)", |
117 | 155 | }, |
118 | | - "line": {"color": "black", "width": 1}, |
| 156 | + "line": {"color": "#2C2C2C", "width": 1}, |
119 | 157 | }, |
120 | 158 | name=lithology, |
121 | 159 | showlegend=True, |
|
124 | 162 |
|
125 | 163 | # Style |
126 | 164 | fig.update_layout( |
127 | | - title={"text": "column-stratigraphic · plotly · pyplots.ai", "font": {"size": 28}, "x": 0.5, "xanchor": "center"}, |
| 165 | + title={ |
| 166 | + "text": "column-stratigraphic · plotly · pyplots.ai", |
| 167 | + "font": {"size": 28, "color": "#1A1A1A"}, |
| 168 | + "x": 0.5, |
| 169 | + "xanchor": "center", |
| 170 | + }, |
128 | 171 | yaxis={ |
129 | | - "title": {"text": "Depth (m)", "font": {"size": 22}}, |
| 172 | + "title": {"text": "Depth (m)", "font": {"size": 22, "color": "#2C2C2C"}}, |
130 | 173 | "tickfont": {"size": 16}, |
131 | 174 | "autorange": "reversed", |
132 | 175 | "dtick": 20, |
133 | | - "gridcolor": "rgba(0,0,0,0.1)", |
| 176 | + "gridcolor": "rgba(0,0,0,0.07)", |
134 | 177 | "gridwidth": 1, |
135 | 178 | "zeroline": False, |
| 179 | + "side": "left", |
136 | 180 | }, |
137 | | - xaxis={"showticklabels": False, "showgrid": False, "zeroline": False, "range": [0.2, 2.0], "fixedrange": True}, |
| 181 | + xaxis={"showticklabels": False, "showgrid": False, "zeroline": False, "range": [0.3, 1.95], "fixedrange": True}, |
138 | 182 | template="plotly_white", |
139 | 183 | plot_bgcolor="white", |
140 | 184 | paper_bgcolor="white", |
141 | 185 | barmode="overlay", |
142 | 186 | bargap=0, |
143 | 187 | legend={ |
144 | | - "title": {"text": "Lithology", "font": {"size": 18}}, |
145 | | - "font": {"size": 14}, |
146 | | - "x": 0.92, |
| 188 | + "title": {"text": "<b>Lithology</b>", "font": {"size": 18}}, |
| 189 | + "font": {"size": 15}, |
| 190 | + "x": 0.88, |
147 | 191 | "y": 0.98, |
148 | | - "bgcolor": "rgba(255,255,255,0.9)", |
149 | | - "bordercolor": "rgba(0,0,0,0.2)", |
| 192 | + "bgcolor": "rgba(255,255,255,0.95)", |
| 193 | + "bordercolor": "rgba(48,105,152,0.3)", |
150 | 194 | "borderwidth": 1, |
151 | 195 | }, |
152 | | - margin={"l": 140, "r": 200, "t": 80, "b": 40}, |
| 196 | + margin={"l": 130, "r": 140, "t": 80, "b": 40}, |
153 | 197 | height=900, |
154 | 198 | width=1600, |
155 | 199 | ) |
|
0 commit comments