|
1 | | -""" pyplots.ai |
| 1 | +"""pyplots.ai |
2 | 2 | stereonet-equal-area: Structural Geology Stereonet (Equal-Area Projection) |
3 | 3 | Library: plotly 6.6.0 | Python 3.14.3 |
4 | 4 | Quality: 85/100 | Created: 2026-03-15 |
|
34 | 34 | strikes = strikes % 360 |
35 | 35 | dips = np.clip(dips, 0, 90) |
36 | 36 |
|
37 | | -type_colors = {"Bedding": "#306998", "Joint Set 1": "#E07B39", "Joint Set 2": "#4CAF50", "Fault": "#8E24AA"} |
| 37 | +type_colors = {"Bedding": "#306998", "Joint Set 1": "#E07B39", "Joint Set 2": "#00897B", "Fault": "#8E24AA"} |
38 | 38 |
|
39 | 39 | # Equal-area (Schmidt) projection of poles to planes |
40 | 40 | # Pole to plane: trend = dip direction = strike + 90°, plunge = 90° - dip |
|
64 | 64 | z=Z, |
65 | 65 | colorscale=[ |
66 | 66 | [0, "rgba(255,255,255,0)"], |
67 | | - [0.3, "rgba(255,235,170,0.25)"], |
68 | | - [0.6, "rgba(255,180,80,0.35)"], |
69 | | - [1, "rgba(220,60,40,0.45)"], |
| 67 | + [0.25, "rgba(255,235,170,0.4)"], |
| 68 | + [0.5, "rgba(255,180,80,0.55)"], |
| 69 | + [0.75, "rgba(230,100,50,0.65)"], |
| 70 | + [1, "rgba(200,40,30,0.75)"], |
70 | 71 | ], |
71 | 72 | showscale=False, |
72 | 73 | contours={"coloring": "fill", "showlines": True, "showlabels": False}, |
|
161 | 162 | x=gc_proj_x.tolist(), |
162 | 163 | y=gc_proj_y.tolist(), |
163 | 164 | mode="lines", |
164 | | - line={"color": type_colors[feature_types[idx]], "width": 1.8}, |
165 | | - opacity=0.45, |
| 165 | + line={"color": type_colors[feature_types[idx]], "width": 2.2}, |
| 166 | + opacity=0.7, |
| 167 | + legendgroup=feature_types[idx], |
166 | 168 | showlegend=False, |
167 | 169 | hoverinfo="skip", |
168 | 170 | ) |
169 | 171 | ) |
170 | 172 |
|
171 | | -# Plot poles by feature type |
| 173 | +# Plot poles by feature type with Plotly customdata + hovertemplate |
172 | 174 | for feat_type in ["Bedding", "Joint Set 1", "Joint Set 2", "Fault"]: |
173 | 175 | mask = np.array([t == feat_type for t in feature_types]) |
174 | | - hover_texts = [ |
175 | | - f"<b>{feat_type}</b><br>Strike: {s:.0f}°<br>Dip: {d:.0f}°" |
176 | | - for s, d in zip(strikes[mask], dips[mask], strict=True) |
177 | | - ] |
| 176 | + customdata = np.column_stack([strikes[mask], dips[mask], (strikes[mask] + 90) % 360]) |
178 | 177 | fig.add_trace( |
179 | 178 | go.Scatter( |
180 | 179 | x=pole_x[mask].tolist(), |
181 | 180 | y=pole_y[mask].tolist(), |
182 | 181 | mode="markers", |
183 | 182 | name=feat_type, |
| 183 | + legendgroup=feat_type, |
184 | 184 | marker={ |
185 | 185 | "size": 13, |
186 | 186 | "color": type_colors[feat_type], |
187 | 187 | "line": {"width": 1.5, "color": "white"}, |
188 | 188 | "symbol": "circle", |
189 | 189 | }, |
190 | | - hovertext=hover_texts, |
191 | | - hoverinfo="text", |
| 190 | + customdata=customdata, |
| 191 | + hovertemplate=( |
| 192 | + f"<b>{feat_type}</b><br>" |
| 193 | + "Strike: %{customdata[0]:.0f}°<br>" |
| 194 | + "Dip: %{customdata[1]:.0f}°<br>" |
| 195 | + "Dip Direction: %{customdata[2]:.0f}°" |
| 196 | + "<extra></extra>" |
| 197 | + ), |
192 | 198 | ) |
193 | 199 | ) |
194 | 200 |
|
|
218 | 224 | yanchor="middle", |
219 | 225 | ) |
220 | 226 |
|
| 227 | +# Interactive buttons for density contour toggle (Plotly-specific feature) |
| 228 | +n_traces = len(fig.data) |
| 229 | +density_visible_on = [True] * n_traces |
| 230 | +density_visible_off = [True] * n_traces |
| 231 | +density_visible_off[0] = False # First trace is the density contour |
| 232 | + |
221 | 233 | # Style |
222 | 234 | fig.update_layout( |
| 235 | + updatemenus=[ |
| 236 | + { |
| 237 | + "type": "buttons", |
| 238 | + "direction": "left", |
| 239 | + "buttons": [ |
| 240 | + {"label": "Show Density", "method": "update", "args": [{"visible": density_visible_on}]}, |
| 241 | + {"label": "Hide Density", "method": "update", "args": [{"visible": density_visible_off}]}, |
| 242 | + ], |
| 243 | + "x": 0.01, |
| 244 | + "y": -0.02, |
| 245 | + "xanchor": "left", |
| 246 | + "yanchor": "top", |
| 247 | + "bgcolor": "rgba(255,255,255,0.9)", |
| 248 | + "bordercolor": "rgba(0,0,0,0.2)", |
| 249 | + "font": {"size": 14}, |
| 250 | + } |
| 251 | + ], |
223 | 252 | title={ |
224 | 253 | "text": "stereonet-equal-area · plotly · pyplots.ai<br><sup>Lower Hemisphere, Equal-Area (Schmidt) Projection</sup>", |
225 | 254 | "font": {"size": 28}, |
|
0 commit comments