{"spec_id":"column-stratigraphic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\ncolumn-stratigraphic: Stratigraphic Column with Lithology Patterns\nLibrary: plotly 6.8.0 | Python 3.13.14\nQuality: 91/100 | Updated: 2026-06-17\n\"\"\"\n\nimport os\n\nimport plotly.graph_objects as go\n\n\n# Theme tokens (see prompts/default-style-guide.md \"Theme-adaptive Chrome\")\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nGRID = \"rgba(26,26,23,0.15)\" if THEME == \"light\" else \"rgba(240,239,232,0.15)\"\nINK_RGB = \"26,26,23\" if THEME == \"light\" else \"240,239,232\"\n\n# Constant data-mark styling (kept identical across themes so the column reads the same)\nPATTERN_FG = \"rgba(26,26,23,0.5)\"\nBAR_EDGE = \"rgba(26,26,23,0.55)\"\n\n# Data - synthetic sedimentary section based on Western Interior Seaway formations\nlayers = [\n    {\"top\": 0, \"bottom\": 15, \"lithology\": \"Sandstone\", \"formation\": \"Dakota Fm\", \"age\": \"Late Cretaceous\"},\n    {\"top\": 15, \"bottom\": 30, \"lithology\": \"Shale\", \"formation\": \"Graneros Sh\", \"age\": \"Late Cretaceous\"},\n    {\"top\": 30, \"bottom\": 50, \"lithology\": \"Limestone\", \"formation\": \"Greenhorn Ls\", \"age\": \"Late Cretaceous\"},\n    {\"top\": 50, \"bottom\": 62, \"lithology\": \"Shale\", \"formation\": \"Carlile Sh\", \"age\": \"Late Cretaceous\"},\n    {\"top\": 62, \"bottom\": 78, \"lithology\": \"Siltstone\", \"formation\": \"Niobrara Fm\", \"age\": \"Late Cretaceous\"},\n    {\"top\": 78, \"bottom\": 100, \"lithology\": \"Limestone\", \"formation\": \"Fort Hays Ls\", \"age\": \"Late Cretaceous\"},\n    {\"top\": 100, \"bottom\": 125, \"lithology\": \"Sandstone\", \"formation\": \"Fox Hills Ss\", \"age\": \"Maastrichtian\"},\n    {\"top\": 125, \"bottom\": 148, \"lithology\": \"Conglomerate\", \"formation\": \"Lance Fm\", \"age\": \"Maastrichtian\"},\n    {\"top\": 148, \"bottom\": 170, \"lithology\": \"Shale\", \"formation\": \"Fort Union Fm\", \"age\": \"Paleocene\"},\n    {\"top\": 170, \"bottom\": 195, \"lithology\": \"Sandstone\", \"formation\": \"Wasatch Fm\", \"age\": \"Eocene\"},\n]\n\n# Lithology fills from the Imprint palette (canonical order, brand green first),\n# each paired with a distinct fill pattern approximating FGDC/USGS map symbols.\nlithology_styles = {\n    \"Sandstone\": {\"color\": \"#009E73\", \"pattern_shape\": \".\", \"pattern_size\": 9},\n    \"Shale\": {\"color\": \"#C475FD\", \"pattern_shape\": \"-\", \"pattern_size\": 7},\n    \"Limestone\": {\"color\": \"#4467A3\", \"pattern_shape\": \"+\", \"pattern_size\": 9},\n    \"Siltstone\": {\"color\": \"#BD8233\", \"pattern_shape\": \"/\", \"pattern_size\": 7},\n    \"Conglomerate\": {\"color\": \"#2ABCCD\", \"pattern_shape\": \"x\", \"pattern_size\": 11},\n}\n\n# Subtle theme-adaptive shading deepens with each younger period (top -> bottom)\nage_alpha = {\"Late Cretaceous\": 0.035, \"Maastrichtian\": 0.06, \"Paleocene\": 0.085, \"Eocene\": 0.11}\n\n# Plot\nfig = go.Figure()\n\n# Group consecutive layers by age for boundary markers and left-side labels\nage_groups = []\ncurrent_age = layers[0][\"age\"]\ncurrent_top = layers[0][\"top\"]\nprev_bottom = layers[0][\"bottom\"]\nfor layer in layers:\n    if layer[\"age\"] != current_age:\n        age_groups.append({\"age\": current_age, \"top\": current_top, \"bottom\": prev_bottom})\n        current_age = layer[\"age\"]\n        current_top = layer[\"top\"]\n    prev_bottom = layer[\"bottom\"]\nage_groups.append({\"age\": current_age, \"top\": current_top, \"bottom\": prev_bottom})\n\n# Subtle age-period background shading\nfor group in age_groups:\n    fig.add_shape(\n        type=\"rect\",\n        x0=0.62,\n        x1=1.38,\n        y0=group[\"top\"],\n        y1=group[\"bottom\"],\n        fillcolor=f\"rgba({INK_RGB},{age_alpha.get(group['age'], 0.04)})\",\n        line={\"width\": 0},\n        layer=\"below\",\n    )\n\n# Age boundary lines (heavier dotted lines at period transitions)\nfor i in range(1, len(age_groups)):\n    boundary_depth = age_groups[i][\"top\"]\n    fig.add_shape(\n        type=\"line\",\n        x0=0.62,\n        x1=1.38,\n        y0=boundary_depth,\n        y1=boundary_depth,\n        line={\"color\": INK_SOFT, \"width\": 2, \"dash\": \"dot\"},\n        layer=\"above\",\n    )\n\n# Layer bars\nfor layer in layers:\n    style = lithology_styles[layer[\"lithology\"]]\n    thickness = layer[\"bottom\"] - layer[\"top\"]\n    mid_depth = (layer[\"top\"] + layer[\"bottom\"]) / 2\n\n    fig.add_trace(\n        go.Bar(\n            x=[1],\n            y=[thickness],\n            base=layer[\"top\"],\n            orientation=\"v\",\n            marker={\n                \"color\": style[\"color\"],\n                \"pattern\": {\n                    \"shape\": style[\"pattern_shape\"],\n                    \"size\": style[\"pattern_size\"],\n                    \"solidity\": 0.6,\n                    \"fgcolor\": PATTERN_FG,\n                },\n                \"line\": {\"color\": BAR_EDGE, \"width\": 1.5},\n            },\n            width=0.6,\n            showlegend=False,\n            hovertemplate=(\n                f\"<b>{layer['formation']}</b><br>\"\n                f\"Lithology: {layer['lithology']}<br>\"\n                f\"Depth: {layer['top']}-{layer['bottom']} m<br>\"\n                f\"Thickness: {thickness} m<br>\"\n                f\"Age: {layer['age']}\"\n                \"<extra></extra>\"\n            ),\n        )\n    )\n\n    # Formation name + lithology label (right of the column)\n    fig.add_annotation(\n        x=1.46,\n        y=mid_depth,\n        text=f\"<b>{layer['formation']}</b><br><i>{layer['lithology']}</i>\",\n        showarrow=False,\n        font={\"size\": 11, \"color\": INK},\n        xanchor=\"left\",\n        yanchor=\"middle\",\n    )\n\n# Age period labels on the left side\nfor group in age_groups:\n    mid = (group[\"top\"] + group[\"bottom\"]) / 2\n    fig.add_annotation(\n        x=0.54,\n        y=mid,\n        text=f\"<b>{group['age']}</b>\",\n        showarrow=False,\n        font={\"size\": 11, \"color\": INK_SOFT},\n        xanchor=\"right\",\n        yanchor=\"middle\",\n    )\n\n# Legend for lithology types with pattern swatches\nfor lithology, style in lithology_styles.items():\n    fig.add_trace(\n        go.Bar(\n            x=[None],\n            y=[None],\n            marker={\n                \"color\": style[\"color\"],\n                \"pattern\": {\n                    \"shape\": style[\"pattern_shape\"],\n                    \"size\": style[\"pattern_size\"],\n                    \"solidity\": 0.6,\n                    \"fgcolor\": PATTERN_FG,\n                },\n                \"line\": {\"color\": BAR_EDGE, \"width\": 1},\n            },\n            name=lithology,\n            showlegend=True,\n        )\n    )\n\n# Style\nfig.update_layout(\n    autosize=False,\n    title={\n        \"text\": \"column-stratigraphic · python · plotly · anyplot.ai\",\n        \"font\": {\"size\": 16, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    yaxis={\n        \"title\": {\"text\": \"Depth (m)\", \"font\": {\"size\": 12, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"range\": [198, -3],\n        \"dtick\": 20,\n        \"gridcolor\": GRID,\n        \"gridwidth\": 1,\n        \"zeroline\": False,\n        \"linecolor\": INK_SOFT,\n        \"side\": \"left\",\n    },\n    xaxis={\"showticklabels\": False, \"showgrid\": False, \"zeroline\": False, \"range\": [0.3, 2.2], \"fixedrange\": True},\n    plot_bgcolor=PAGE_BG,\n    paper_bgcolor=PAGE_BG,\n    font={\"color\": INK},\n    barmode=\"overlay\",\n    bargap=0,\n    legend={\n        \"title\": {\"text\": \"<b>Lithology</b>\", \"font\": {\"size\": 13, \"color\": INK}},\n        \"font\": {\"size\": 11, \"color\": INK_SOFT},\n        \"x\": 0.99,\n        \"y\": 0.99,\n        \"xanchor\": \"right\",\n        \"yanchor\": \"top\",\n        \"bgcolor\": ELEVATED_BG,\n        \"bordercolor\": INK_SOFT,\n        \"borderwidth\": 1,\n    },\n    margin={\"l\": 140, \"r\": 40, \"t\": 80, \"b\": 60},\n)\n\n# Save\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}