{"spec_id":"bar-diverging","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nbar-diverging: Diverging Bar Chart\nLibrary: plotly 6.9.0 | Python 3.13.15\nQuality: 94/100 | Updated: 2026-08-18\n\"\"\"\n\nimport os\n\nimport plotly.graph_objects as go\n\n\n# Theme tokens\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)\"\n\n# Imprint palette: position 1 (brand green) for positive, position 5 (matte\n# red) for negative — sentiment/polarity semantic exception\nPOSITIVE_COLOR = \"#009E73\"\nNEGATIVE_COLOR = \"#AE3030\"\n\n# Data: Customer satisfaction survey results by department\n# Scores range from -100 (very dissatisfied) to +100 (very satisfied)\ncategories = [\n    \"Customer Support\",\n    \"Product Quality\",\n    \"Delivery Speed\",\n    \"Website Experience\",\n    \"Return Policy\",\n    \"Price Value\",\n    \"Mobile App\",\n    \"Payment Options\",\n    \"Product Variety\",\n    \"Checkout Process\",\n]\nvalues = [72, 58, -25, 45, -42, 31, -15, 68, 22, -8]\n\n# Sort by value for better pattern recognition\nsorted_data = sorted(zip(categories, values, strict=True), key=lambda x: x[1])\ncategories_sorted = [item[0] for item in sorted_data]\nvalues_sorted = [item[1] for item in sorted_data]\n\n# Assign colors: Imprint brand green for positive, matte red for negative\ncolors = [POSITIVE_COLOR if v >= 0 else NEGATIVE_COLOR for v in values_sorted]\n\n# Redundant non-color encoding beyond bar direction + sign: a diagonal hatch\n# flags negative bars, distinctive Plotly marker.pattern usage\npatterns = [\"\" if v >= 0 else \"/\" for v in values_sorted]\n\n# The two extreme bars (sorted ascending, so index 0 and -1) get a bolder\n# outline to draw the eye to the highest/lowest departments\nextreme_indices = {0, len(values_sorted) - 1}\nline_widths = [2.5 if i in extreme_indices else 1 for i in range(len(values_sorted))]\nline_colors = [INK if i in extreme_indices else PAGE_BG for i in range(len(values_sorted))]\n\n# Net sentiment context for the subtitle and richer hover cards\nnet_avg = sum(values_sorted) / len(values_sorted)\nbottom_cat, bottom_val = sorted_data[0]\ntop_cat, top_val = sorted_data[-1]\nsentiment_labels = [\"Positive\" if v >= 0 else \"Negative\" for v in values_sorted]\ncustomdata = list(zip(sentiment_labels, [abs(v) for v in values_sorted], strict=True))\n\n# Create horizontal diverging bar chart\nfig = go.Figure()\n\nfig.add_trace(\n    go.Bar(\n        y=categories_sorted,\n        x=values_sorted,\n        orientation=\"h\",\n        marker={\n            \"color\": colors,\n            \"line\": {\"color\": line_colors, \"width\": line_widths},\n            \"pattern\": {\"shape\": patterns, \"fgcolor\": PAGE_BG, \"size\": 6, \"solidity\": 0.25},\n        },\n        text=[f\"{v:+d}\" for v in values_sorted],\n        textposition=\"outside\",\n        textfont={\"size\": 12, \"color\": colors},\n        customdata=customdata,\n        hovertemplate=(\n            \"<b>%{y}</b><br>Score: %{x:+d}<br>Sentiment: %{customdata[0]}<br>\"\n            \"Magnitude: %{customdata[1]} of 100<extra></extra>\"\n        ),\n    )\n)\n\n# Add zero baseline\nfig.add_vline(x=0, line={\"color\": INK_SOFT, \"width\": 2})\n\n# Layout styling for 3200x1800\nfig.update_layout(\n    autosize=False,\n    title={\n        \"text\": (\n            \"bar-diverging · python · plotly · anyplot.ai<br>\"\n            f\"<span style='font-size:13px;font-weight:normal;color:{INK_SOFT}'>\"\n            f\"Net sentiment {net_avg:+.0f} avg · {top_cat} leads ({top_val:+d}) · \"\n            f\"{bottom_cat} trails ({bottom_val:+d})</span>\"\n        ),\n        \"font\": {\"size\": 20, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    xaxis={\n        \"title\": {\"text\": \"Satisfaction Score (-100 to +100)\", \"font\": {\"size\": 16, \"color\": INK}},\n        \"tickfont\": {\"size\": 13, \"color\": INK_SOFT},\n        \"range\": [-100, 100],\n        \"dtick\": 25,\n        \"gridcolor\": GRID,\n        \"linecolor\": INK_SOFT,\n        \"zeroline\": False,\n    },\n    yaxis={\n        \"title\": {\"text\": \"Department\", \"font\": {\"size\": 16, \"color\": INK}},\n        \"tickfont\": {\"size\": 13, \"color\": INK_SOFT},\n        \"automargin\": True,\n        \"linecolor\": INK_SOFT,\n    },\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    showlegend=False,\n    margin={\"l\": 20, \"r\": 60, \"t\": 110, \"b\": 70},\n    bargap=0.3,\n)\n\n# Save outputs\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}