From fbc94a2dff961e72873993632c3853aff2069098 Mon Sep 17 00:00:00 2001 From: SimaRaha Date: Wed, 1 Jan 2025 13:11:34 -0500 Subject: [PATCH 01/11] Added plotly-universities-1.ipynb for visualization updates --- plotly-universities-1.ipynb | 1360 +++++++++++++++++++++++++++++++++++ 1 file changed, 1360 insertions(+) create mode 100644 plotly-universities-1.ipynb diff --git a/plotly-universities-1.ipynb b/plotly-universities-1.ipynb new file mode 100644 index 0000000000..dbbaddb98f --- /dev/null +++ b/plotly-universities-1.ipynb @@ -0,0 +1,1360 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hoverinfo": "text", + "marker": { + "color": 0, + "size": 27, + "symbol": "square" + }, + "mode": "markers", + "name": "Haverford College", + "text": [ + "Haverford College: 1421" + ], + "type": "scatter", + "x": [ + 1 + ], + "y": [ + 1.05 + ] + }, + { + "mode": "text", + "showlegend": false, + "text": [ + "1421" + ], + "textfont": { + "color": "black", + "size": 14 + }, + "type": "scatter", + "x": [ + 1 + ], + "y": [ + 11 + ] + }, + { + "hoverinfo": "text", + "marker": { + "color": 1, + "size": 27, + "symbol": "square" + }, + "mode": "markers", + "name": "University of Mary Washington", + "text": [ + "University of Mary Washington: 3611", + "University of Mary Washington: 3611", + "University of Mary Washington: 3611", + "University of Mary Washington: 3611" + ], + "type": "scatter", + "x": [ + 2.005, + 2.005, + 2.005, + 2.005 + ], + "y": [ + 1.05, + 2.1, + 3.15, + 4.2 + ] + }, + { + "mode": "text", + "showlegend": false, + "text": [ + "3611" + ], + "textfont": { + "color": "black", + "size": 14 + }, + "type": "scatter", + "x": [ + 2.005 + ], + "y": [ + 11 + ] + }, + { + "hoverinfo": "text", + "marker": { + "color": 2, + "size": 27, + "symbol": "square" + }, + "mode": "markers", + "name": "Brown University", + "text": [ + "Brown University: 7226", + "Brown University: 7226", + "Brown University: 7226", + "Brown University: 7226", + "Brown University: 7226", + "Brown University: 7226", + "Brown University: 7226" + ], + "type": "scatter", + "x": [ + 3.01, + 3.01, + 3.01, + 3.01, + 3.01, + 3.01, + 3.01 + ], + "y": [ + 1.05, + 2.1, + 3.15, + 4.2, + 5.25, + 6.3, + 7.35 + ] + }, + { + "mode": "text", + "showlegend": false, + "text": [ + "7226" + ], + "textfont": { + "color": "black", + "size": 14 + }, + "type": "scatter", + "x": [ + 3.01 + ], + "y": [ + 11 + ] + }, + { + "hoverinfo": "text", + "marker": { + "color": 3, + "size": 27, + "symbol": "square" + }, + "mode": "markers", + "name": "Arizona State University", + "text": [ + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174", + "Arizona State University: 65174" + ], + "type": "scatter", + "x": [ + 4.015, + 4.015, + 4.015, + 4.015, + 4.015, + 4.015, + 4.015, + 4.015, + 4.015, + 4.015, + 5.015, + 5.015, + 5.015, + 5.015, + 5.015, + 5.015, + 5.015, + 5.015, + 5.015, + 5.015, + 6.015, + 6.015, + 6.015, + 6.015, + 6.015, + 6.015, + 6.015, + 6.015, + 6.015, + 6.015, + 7.015, + 7.015, + 7.015, + 7.015, + 7.015, + 7.015, + 7.015, + 7.015, + 7.015, + 7.015, + 8.015, + 8.015, + 8.015, + 8.015, + 8.015, + 8.015, + 8.015, + 8.015, + 8.015, + 8.015, + 9.015, + 9.015, + 9.015, + 9.015, + 9.015, + 9.015, + 9.015, + 9.015, + 9.015, + 9.015, + 10.015, + 10.015, + 10.015, + 10.015, + 10.015 + ], + "y": [ + 1.05, + 2.1, + 3.15, + 4.2, + 5.25, + 6.3, + 7.35, + 8.4, + 9.45, + 10.5, + 1.05, + 2.1, + 3.15, + 4.2, + 5.25, + 6.3, + 7.35, + 8.4, + 9.45, + 10.5, + 1.05, + 2.1, + 3.15, + 4.2, + 5.25, + 6.3, + 7.35, + 8.4, + 9.45, + 10.5, + 1.05, + 2.1, + 3.15, + 4.2, + 5.25, + 6.3, + 7.35, + 8.4, + 9.45, + 10.5, + 1.05, + 2.1, + 3.15, + 4.2, + 5.25, + 6.3, + 7.35, + 8.4, + 9.45, + 10.5, + 1.05, + 2.1, + 3.15, + 4.2, + 5.25, + 6.3, + 7.35, + 8.4, + 9.45, + 10.5, + 1.05, + 2.1, + 3.15, + 4.2, + 5.25 + ] + }, + { + "mode": "text", + "showlegend": false, + "text": [ + "65174" + ], + "textfont": { + "color": "black", + "size": 14 + }, + "type": "scatter", + "x": [ + 7.015 + ], + "y": [ + 11 + ] + } + ], + "layout": { + "height": 600, + "showlegend": false, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Undergraduate Enrollment at Participating Schools" + }, + "width": 1000, + "xaxis": { + "showgrid": false, + "tickangle": -45, + "ticktext": [ + "Haverford College", + "University of Mary Washington", + "Brown University", + "Arizona State University" + ], + "tickvals": [ + 1, + 2.005, + 3.01, + 7.015 + ], + "title": { + "text": "Categories" + } + }, + "yaxis": { + "showgrid": false, + "title": { + "text": "Units (1 icon = 1000)" + }, + "zeroline": false + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import plotly.graph_objects as go\n", + "import pandas as pd\n", + "\n", + "def pictogram_bar(data, title, icon_size, max_height=10, units_per_icon=1, column_spacing=0.005,icon_spacing=0.005):\n", + " \n", + " fig = go.Figure()\n", + " x_start = 1\n", + " tick_locations = []\n", + "\n", + " for i, (category, value) in enumerate(data.items()):\n", + " icon_count = round(value / units_per_icon)\n", + " num_columns = -(-icon_count // max_height) # Ceiling division\n", + "\n", + " x_coordinates, y_coordinates = [], []\n", + " for col in range(num_columns):\n", + " column_icons = min(max_height, icon_count - col * max_height)\n", + " x_coordinates.extend([x_start + col] * column_icons)\n", + " # y_coordinates.extend(range(1, column_icons + 1))\n", + " y_coordinates.extend([y + icon_spacing * y for y in range(1, column_icons + 1)])\n", + "\n", + "\n", + " # Add scatter plot for the category\n", + " fig.add_trace(go.Scatter(\n", + " x=x_coordinates,\n", + " y=y_coordinates,\n", + " mode='markers',\n", + " marker=dict(size=icon_size, symbol=\"square\", color= i),\n", + " name=category,\n", + " hoverinfo=\"text\",\n", + " text=[f\"{category}: {value}\" for _ in range(len(x_coordinates))]\n", + " ))\n", + " \n", + "\n", + " # Add value annotations above the section: new line of code \n", + " fig.add_trace(go.Scatter(\n", + " x=[x_start + (num_columns - 1) / 2],\n", + " y=[max_height + 1],\n", + " mode=\"text\",\n", + " text=[f\"{value}\"],\n", + " textfont=dict(size=14, color=\"black\"),\n", + " showlegend=False\n", + " ))\n", + "\n", + " # Track tick locations\n", + " tick_locations.append(x_start + (num_columns - 1) / 2)\n", + " x_start += num_columns + column_spacing\n", + "\n", + " # Update layout\n", + " fig.update_layout(\n", + " title=title,\n", + " xaxis=dict(\n", + " tickvals=tick_locations,\n", + " ticktext=list(data.keys()),\n", + " tickangle=-45,\n", + " showgrid=False,\n", + " title=\"Categories\"\n", + " ),\n", + " yaxis=dict(\n", + " title=f\"Units (1 icon = {units_per_icon})\",\n", + " showgrid=False,\n", + " zeroline=False,\n", + " ),\n", + " showlegend=False,\n", + " height=600,\n", + " width=(len(data) * 200 + 200) # Done adjused width based on number of categories\n", + " )\n", + "\n", + " fig.show()\n", + "\n", + "\n", + "# done as pd \n", + "df = pd.DataFrame({\n", + " 'School': [\"Haverford College\", \"University of Mary Washington\", \"Brown University\", \"Arizona State University\"],\n", + " 'Enrollment': [1421, 3611, 7226, 65174]\n", + "})\n", + "\n", + "pictogram_bar(\n", + " data={row['School']: row['Enrollment'] for _, row in df.iterrows()},\n", + " title=\"Undergraduate Enrollment at Participating Schools\",\n", + " units_per_icon=1000,\n", + " icon_size=27,\n", + " icon_spacing=0.05\n", + ")\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "3.11.9", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From f386c0baeaa1cf40bed3bad4158254b69de41bbf Mon Sep 17 00:00:00 2001 From: Rob Letzler <22990670+rl-utility-man@users.noreply.github.com> Date: Thu, 6 Feb 2025 00:11:12 -0500 Subject: [PATCH 02/11] butterfly with neutral column --- doc/python/horizontal-bar-charts.md | 105 +++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 2 deletions(-) diff --git a/doc/python/horizontal-bar-charts.md b/doc/python/horizontal-bar-charts.md index 25aa9d4f7d..f68a34989d 100644 --- a/doc/python/horizontal-bar-charts.md +++ b/doc/python/horizontal-bar-charts.md @@ -214,6 +214,107 @@ for yd, xd in zip(y_data, x_data): fig.update_layout(annotations=annotations) +fig.show() +``` +### Diverging Bar (or Butterfly) Chart with Neutral Column + +Diverging bar charts offer two imperfect options for responses that are neither positive nor negative: omit them, leaving them implicit when the categories add to 100%, as we did above or put them in a separate column, as we do in this example. Jonathan Schwabish discusses this on page 92-97 of _Better Data Visualizations_. + +``` +import pandas as pd +import plotly.graph_objects as go + +data = { + "Category": ["Content Quality", "Value for Money", "Ease of Use", "Customer Support", "Scale Fidelity"], + "Neutral": [10, 15, 18, 15,20], + "Somewhat Agree": [25, 25, 22, 20, 20], + "Strongly Agree": [35, 35, 25, 40, 20], + "Somewhat Disagree": [-20, -15, -20, -10, -20], + "Strongly Disagree": [-10, -10, -15, -15,-20] +} +df = pd.DataFrame(data) + +fig = go.Figure() +# this color palette conveys meaning: blues for negative, reds for positive, gray for neutral +color_by_category={ + "Strongly Agree":'darkblue', + "Somewhat Agree":'lightblue', + "Somewhat Disagree":'orange', + "Strongly Disagree":'red', + "Neutral":'gray', +} + +# We want the legend to be ordered in the same order that the categories appear, left to right -- +# which is different from the order in which we have to add the traces to the figure. +# since we need to create the "somewhat" traces before the "strongly" traces to display +# the segments in the desired order + +legend_rank_by_category={ + "Strongly Disagree":1, + "Somewhat Disagree":2, + "Somewhat Agree":3, + "Strongly Agree":4, + "Neutral":5 +} + +# Add bars +for col in df[["Somewhat Disagree","Strongly Disagree","Somewhat Agree","Strongly Agree","Neutral"]]: + fig.add_trace(go.Bar( + y=df["Category"], + x=df[col], + name=col, + orientation='h', + marker=dict(color=color_by_category[col]), + legendrank=legend_rank_by_category[col], + xaxis=f"x{1+(col=="Neutral")}", # in this context, putting neutral on a secondary x-axis on a different domain + # yields results equivalent to subplots with far less code + + + ) +) + +# make calculations to split the plot into two columns with a shared x axis scale +# by setting the domain and range of the x axes appropriately + +# Find the maximum width of the bars to the left and right sides of the origin; remember that the width of +# the plot is the sum of the longest negative bar and the longest positive bar even if they are on separate rows +max_left = min(df[["Somewhat Disagree","Strongly Disagree"]].sum(axis=1)) +max_right = max(df[["Somewhat Agree","Strongly Agree"]].sum(axis=1)) + +# we are working in percent, but coded the negative reactions as negative numbers; so we need to take the absolute value +max_width_signed = abs(max_left)+max_right +max_width_neutral = max(df["Neutral"]) + +fig.update_layout( + title="Reactions to the statement, 'The service met your expectations for':", + plot_bgcolor="white", + barmode='relative', # Allows bars to diverge from the center + ) +fig.update_xaxes( + zeroline=True, #the zero line distinguishes between positive and negative segments + zerolinecolor="black", + #starting here, we set domain and range to create a shared x-axis scale + # multiply by .98 to add space between the two columns + range=[max_left, max_right], + domain=[0, 0.98*(max_width_signed/(max_width_signed+max_width_neutral))] +) +fig.update_layout( + xaxis2=dict( + range=[0, max_width_neutral], + domain=[(1-.98*(1-max_width_signed/(max_width_signed+max_width_neutral))), 1.0], + ) +) +fig.update_legends( + orientation="h", # a horizontal legend matches the horizontal bars + yref="container", + yanchor="bottom", + y=0.02, + xanchor="center", + x=0.5 +) + +fig.update_yaxes(title="") + fig.show() ``` @@ -260,7 +361,7 @@ fig.append_trace(go.Scatter( ), 1, 2) fig.update_layout( - title='Household savings & net worth for eight OECD countries', + title=dict(text='Household savings & net worth for eight OECD countries'), yaxis=dict( showgrid=False, showline=False, @@ -335,4 +436,4 @@ fig.show() ### Reference -See more examples of bar charts and styling options [here](https://plotly.com/python/bar-charts/).
See https://plotly.com/python/reference/bar/ for more information and chart attribute options! \ No newline at end of file +See more examples of bar charts and styling options [here](https://plotly.com/python/bar-charts/).
See https://plotly.com/python/reference/bar/ for more information and chart attribute options! From 911b99348397d75e73ce018034efd186af69f49b Mon Sep 17 00:00:00 2001 From: Rob Letzler <22990670+rl-utility-man@users.noreply.github.com> Date: Thu, 6 Feb 2025 00:12:27 -0500 Subject: [PATCH 03/11] Delete scratchwork file --- plotly-universities-1.ipynb | 1360 ----------------------------------- 1 file changed, 1360 deletions(-) delete mode 100644 plotly-universities-1.ipynb diff --git a/plotly-universities-1.ipynb b/plotly-universities-1.ipynb deleted file mode 100644 index dbbaddb98f..0000000000 --- a/plotly-universities-1.ipynb +++ /dev/null @@ -1,1360 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.plotly.v1+json": { - "config": { - "plotlyServerURL": "https://plot.ly" - }, - "data": [ - { - "hoverinfo": "text", - "marker": { - "color": 0, - "size": 27, - "symbol": "square" - }, - "mode": "markers", - "name": "Haverford College", - "text": [ - "Haverford College: 1421" - ], - "type": "scatter", - "x": [ - 1 - ], - "y": [ - 1.05 - ] - }, - { - "mode": "text", - "showlegend": false, - "text": [ - "1421" - ], - "textfont": { - "color": "black", - "size": 14 - }, - "type": "scatter", - "x": [ - 1 - ], - "y": [ - 11 - ] - }, - { - "hoverinfo": "text", - "marker": { - "color": 1, - "size": 27, - "symbol": "square" - }, - "mode": "markers", - "name": "University of Mary Washington", - "text": [ - "University of Mary Washington: 3611", - "University of Mary Washington: 3611", - "University of Mary Washington: 3611", - "University of Mary Washington: 3611" - ], - "type": "scatter", - "x": [ - 2.005, - 2.005, - 2.005, - 2.005 - ], - "y": [ - 1.05, - 2.1, - 3.15, - 4.2 - ] - }, - { - "mode": "text", - "showlegend": false, - "text": [ - "3611" - ], - "textfont": { - "color": "black", - "size": 14 - }, - "type": "scatter", - "x": [ - 2.005 - ], - "y": [ - 11 - ] - }, - { - "hoverinfo": "text", - "marker": { - "color": 2, - "size": 27, - "symbol": "square" - }, - "mode": "markers", - "name": "Brown University", - "text": [ - "Brown University: 7226", - "Brown University: 7226", - "Brown University: 7226", - "Brown University: 7226", - "Brown University: 7226", - "Brown University: 7226", - "Brown University: 7226" - ], - "type": "scatter", - "x": [ - 3.01, - 3.01, - 3.01, - 3.01, - 3.01, - 3.01, - 3.01 - ], - "y": [ - 1.05, - 2.1, - 3.15, - 4.2, - 5.25, - 6.3, - 7.35 - ] - }, - { - "mode": "text", - "showlegend": false, - "text": [ - "7226" - ], - "textfont": { - "color": "black", - "size": 14 - }, - "type": "scatter", - "x": [ - 3.01 - ], - "y": [ - 11 - ] - }, - { - "hoverinfo": "text", - "marker": { - "color": 3, - "size": 27, - "symbol": "square" - }, - "mode": "markers", - "name": "Arizona State University", - "text": [ - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174", - "Arizona State University: 65174" - ], - "type": "scatter", - "x": [ - 4.015, - 4.015, - 4.015, - 4.015, - 4.015, - 4.015, - 4.015, - 4.015, - 4.015, - 4.015, - 5.015, - 5.015, - 5.015, - 5.015, - 5.015, - 5.015, - 5.015, - 5.015, - 5.015, - 5.015, - 6.015, - 6.015, - 6.015, - 6.015, - 6.015, - 6.015, - 6.015, - 6.015, - 6.015, - 6.015, - 7.015, - 7.015, - 7.015, - 7.015, - 7.015, - 7.015, - 7.015, - 7.015, - 7.015, - 7.015, - 8.015, - 8.015, - 8.015, - 8.015, - 8.015, - 8.015, - 8.015, - 8.015, - 8.015, - 8.015, - 9.015, - 9.015, - 9.015, - 9.015, - 9.015, - 9.015, - 9.015, - 9.015, - 9.015, - 9.015, - 10.015, - 10.015, - 10.015, - 10.015, - 10.015 - ], - "y": [ - 1.05, - 2.1, - 3.15, - 4.2, - 5.25, - 6.3, - 7.35, - 8.4, - 9.45, - 10.5, - 1.05, - 2.1, - 3.15, - 4.2, - 5.25, - 6.3, - 7.35, - 8.4, - 9.45, - 10.5, - 1.05, - 2.1, - 3.15, - 4.2, - 5.25, - 6.3, - 7.35, - 8.4, - 9.45, - 10.5, - 1.05, - 2.1, - 3.15, - 4.2, - 5.25, - 6.3, - 7.35, - 8.4, - 9.45, - 10.5, - 1.05, - 2.1, - 3.15, - 4.2, - 5.25, - 6.3, - 7.35, - 8.4, - 9.45, - 10.5, - 1.05, - 2.1, - 3.15, - 4.2, - 5.25, - 6.3, - 7.35, - 8.4, - 9.45, - 10.5, - 1.05, - 2.1, - 3.15, - 4.2, - 5.25 - ] - }, - { - "mode": "text", - "showlegend": false, - "text": [ - "65174" - ], - "textfont": { - "color": "black", - "size": 14 - }, - "type": "scatter", - "x": [ - 7.015 - ], - "y": [ - 11 - ] - } - ], - "layout": { - "height": 600, - "showlegend": false, - "template": { - "data": { - "bar": [ - { - "error_x": { - "color": "#2a3f5f" - }, - "error_y": { - "color": "#2a3f5f" - }, - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "bar" - } - ], - "barpolar": [ - { - "marker": { - "line": { - "color": "#E5ECF6", - "width": 0.5 - }, - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "barpolar" - } - ], - "carpet": [ - { - "aaxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "baxis": { - "endlinecolor": "#2a3f5f", - "gridcolor": "white", - "linecolor": "white", - "minorgridcolor": "white", - "startlinecolor": "#2a3f5f" - }, - "type": "carpet" - } - ], - "choropleth": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "choropleth" - } - ], - "contour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "contour" - } - ], - "contourcarpet": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "contourcarpet" - } - ], - "heatmap": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "heatmap" - } - ], - "heatmapgl": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "heatmapgl" - } - ], - "histogram": [ - { - "marker": { - "pattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - } - }, - "type": "histogram" - } - ], - "histogram2d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2d" - } - ], - "histogram2dcontour": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "histogram2dcontour" - } - ], - "mesh3d": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "type": "mesh3d" - } - ], - "parcoords": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "parcoords" - } - ], - "pie": [ - { - "automargin": true, - "type": "pie" - } - ], - "scatter": [ - { - "fillpattern": { - "fillmode": "overlay", - "size": 10, - "solidity": 0.2 - }, - "type": "scatter" - } - ], - "scatter3d": [ - { - "line": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatter3d" - } - ], - "scattercarpet": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattercarpet" - } - ], - "scattergeo": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergeo" - } - ], - "scattergl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattergl" - } - ], - "scattermapbox": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scattermapbox" - } - ], - "scatterpolar": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolar" - } - ], - "scatterpolargl": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterpolargl" - } - ], - "scatterternary": [ - { - "marker": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "type": "scatterternary" - } - ], - "surface": [ - { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - }, - "colorscale": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "type": "surface" - } - ], - "table": [ - { - "cells": { - "fill": { - "color": "#EBF0F8" - }, - "line": { - "color": "white" - } - }, - "header": { - "fill": { - "color": "#C8D4E3" - }, - "line": { - "color": "white" - } - }, - "type": "table" - } - ] - }, - "layout": { - "annotationdefaults": { - "arrowcolor": "#2a3f5f", - "arrowhead": 0, - "arrowwidth": 1 - }, - "autotypenumbers": "strict", - "coloraxis": { - "colorbar": { - "outlinewidth": 0, - "ticks": "" - } - }, - "colorscale": { - "diverging": [ - [ - 0, - "#8e0152" - ], - [ - 0.1, - "#c51b7d" - ], - [ - 0.2, - "#de77ae" - ], - [ - 0.3, - "#f1b6da" - ], - [ - 0.4, - "#fde0ef" - ], - [ - 0.5, - "#f7f7f7" - ], - [ - 0.6, - "#e6f5d0" - ], - [ - 0.7, - "#b8e186" - ], - [ - 0.8, - "#7fbc41" - ], - [ - 0.9, - "#4d9221" - ], - [ - 1, - "#276419" - ] - ], - "sequential": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ], - "sequentialminus": [ - [ - 0, - "#0d0887" - ], - [ - 0.1111111111111111, - "#46039f" - ], - [ - 0.2222222222222222, - "#7201a8" - ], - [ - 0.3333333333333333, - "#9c179e" - ], - [ - 0.4444444444444444, - "#bd3786" - ], - [ - 0.5555555555555556, - "#d8576b" - ], - [ - 0.6666666666666666, - "#ed7953" - ], - [ - 0.7777777777777778, - "#fb9f3a" - ], - [ - 0.8888888888888888, - "#fdca26" - ], - [ - 1, - "#f0f921" - ] - ] - }, - "colorway": [ - "#636efa", - "#EF553B", - "#00cc96", - "#ab63fa", - "#FFA15A", - "#19d3f3", - "#FF6692", - "#B6E880", - "#FF97FF", - "#FECB52" - ], - "font": { - "color": "#2a3f5f" - }, - "geo": { - "bgcolor": "white", - "lakecolor": "white", - "landcolor": "#E5ECF6", - "showlakes": true, - "showland": true, - "subunitcolor": "white" - }, - "hoverlabel": { - "align": "left" - }, - "hovermode": "closest", - "mapbox": { - "style": "light" - }, - "paper_bgcolor": "white", - "plot_bgcolor": "#E5ECF6", - "polar": { - "angularaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "radialaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "scene": { - "xaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "yaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - }, - "zaxis": { - "backgroundcolor": "#E5ECF6", - "gridcolor": "white", - "gridwidth": 2, - "linecolor": "white", - "showbackground": true, - "ticks": "", - "zerolinecolor": "white" - } - }, - "shapedefaults": { - "line": { - "color": "#2a3f5f" - } - }, - "ternary": { - "aaxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "baxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - }, - "bgcolor": "#E5ECF6", - "caxis": { - "gridcolor": "white", - "linecolor": "white", - "ticks": "" - } - }, - "title": { - "x": 0.05 - }, - "xaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - }, - "yaxis": { - "automargin": true, - "gridcolor": "white", - "linecolor": "white", - "ticks": "", - "title": { - "standoff": 15 - }, - "zerolinecolor": "white", - "zerolinewidth": 2 - } - } - }, - "title": { - "text": "Undergraduate Enrollment at Participating Schools" - }, - "width": 1000, - "xaxis": { - "showgrid": false, - "tickangle": -45, - "ticktext": [ - "Haverford College", - "University of Mary Washington", - "Brown University", - "Arizona State University" - ], - "tickvals": [ - 1, - 2.005, - 3.01, - 7.015 - ], - "title": { - "text": "Categories" - } - }, - "yaxis": { - "showgrid": false, - "title": { - "text": "Units (1 icon = 1000)" - }, - "zeroline": false - } - } - } - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import plotly.graph_objects as go\n", - "import pandas as pd\n", - "\n", - "def pictogram_bar(data, title, icon_size, max_height=10, units_per_icon=1, column_spacing=0.005,icon_spacing=0.005):\n", - " \n", - " fig = go.Figure()\n", - " x_start = 1\n", - " tick_locations = []\n", - "\n", - " for i, (category, value) in enumerate(data.items()):\n", - " icon_count = round(value / units_per_icon)\n", - " num_columns = -(-icon_count // max_height) # Ceiling division\n", - "\n", - " x_coordinates, y_coordinates = [], []\n", - " for col in range(num_columns):\n", - " column_icons = min(max_height, icon_count - col * max_height)\n", - " x_coordinates.extend([x_start + col] * column_icons)\n", - " # y_coordinates.extend(range(1, column_icons + 1))\n", - " y_coordinates.extend([y + icon_spacing * y for y in range(1, column_icons + 1)])\n", - "\n", - "\n", - " # Add scatter plot for the category\n", - " fig.add_trace(go.Scatter(\n", - " x=x_coordinates,\n", - " y=y_coordinates,\n", - " mode='markers',\n", - " marker=dict(size=icon_size, symbol=\"square\", color= i),\n", - " name=category,\n", - " hoverinfo=\"text\",\n", - " text=[f\"{category}: {value}\" for _ in range(len(x_coordinates))]\n", - " ))\n", - " \n", - "\n", - " # Add value annotations above the section: new line of code \n", - " fig.add_trace(go.Scatter(\n", - " x=[x_start + (num_columns - 1) / 2],\n", - " y=[max_height + 1],\n", - " mode=\"text\",\n", - " text=[f\"{value}\"],\n", - " textfont=dict(size=14, color=\"black\"),\n", - " showlegend=False\n", - " ))\n", - "\n", - " # Track tick locations\n", - " tick_locations.append(x_start + (num_columns - 1) / 2)\n", - " x_start += num_columns + column_spacing\n", - "\n", - " # Update layout\n", - " fig.update_layout(\n", - " title=title,\n", - " xaxis=dict(\n", - " tickvals=tick_locations,\n", - " ticktext=list(data.keys()),\n", - " tickangle=-45,\n", - " showgrid=False,\n", - " title=\"Categories\"\n", - " ),\n", - " yaxis=dict(\n", - " title=f\"Units (1 icon = {units_per_icon})\",\n", - " showgrid=False,\n", - " zeroline=False,\n", - " ),\n", - " showlegend=False,\n", - " height=600,\n", - " width=(len(data) * 200 + 200) # Done adjused width based on number of categories\n", - " )\n", - "\n", - " fig.show()\n", - "\n", - "\n", - "# done as pd \n", - "df = pd.DataFrame({\n", - " 'School': [\"Haverford College\", \"University of Mary Washington\", \"Brown University\", \"Arizona State University\"],\n", - " 'Enrollment': [1421, 3611, 7226, 65174]\n", - "})\n", - "\n", - "pictogram_bar(\n", - " data={row['School']: row['Enrollment'] for _, row in df.iterrows()},\n", - " title=\"Undergraduate Enrollment at Participating Schools\",\n", - " units_per_icon=1000,\n", - " icon_size=27,\n", - " icon_spacing=0.05\n", - ")\n", - "\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "3.11.9", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.4" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} From 40cd4c8e22d895b842edae8d30f3d4fef810135e Mon Sep 17 00:00:00 2001 From: Rob Letzler <22990670+rl-utility-man@users.noreply.github.com> Date: Sun, 16 Mar 2025 14:52:57 -0400 Subject: [PATCH 04/11] replaced hard coded data with a read_csv from github --- doc/python/horizontal-bar-charts.md | 54 ++++++++++++++--------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/doc/python/horizontal-bar-charts.md b/doc/python/horizontal-bar-charts.md index f68a34989d..52cd62f0ae 100644 --- a/doc/python/horizontal-bar-charts.md +++ b/doc/python/horizontal-bar-charts.md @@ -224,26 +224,27 @@ Diverging bar charts offer two imperfect options for responses that are neither import pandas as pd import plotly.graph_objects as go -data = { - "Category": ["Content Quality", "Value for Money", "Ease of Use", "Customer Support", "Scale Fidelity"], - "Neutral": [10, 15, 18, 15,20], - "Somewhat Agree": [25, 25, 22, 20, 20], - "Strongly Agree": [35, 35, 25, 40, 20], - "Somewhat Disagree": [-20, -15, -20, -10, -20], - "Strongly Disagree": [-10, -10, -15, -15,-20] -} -df = pd.DataFrame(data) + +df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/refs/heads/master/gss_2002_5_pt_likert.csv') +#data source details are in this CSV file +df.rename(columns={'Unnamed: 0':"Category"}, inplace=True) + + +#achieve the diverging effect by putting a negative sign on the "disagree" answers +for v in ["Disagree","Strongly Disagree"]: + df[v]=df[v]*-1 fig = go.Figure() -# this color palette conveys meaning: blues for negative, reds for positive, gray for neutral +# this color palette conveys meaning: blues for negative, reds for positive, gray for Neither Agree nor Disagree color_by_category={ "Strongly Agree":'darkblue', - "Somewhat Agree":'lightblue', - "Somewhat Disagree":'orange', + "Agree":'lightblue', + "Disagree":'orange', "Strongly Disagree":'red', - "Neutral":'gray', + "Neither Agree nor Disagree":'gray', } + # We want the legend to be ordered in the same order that the categories appear, left to right -- # which is different from the order in which we have to add the traces to the figure. # since we need to create the "somewhat" traces before the "strongly" traces to display @@ -251,14 +252,14 @@ color_by_category={ legend_rank_by_category={ "Strongly Disagree":1, - "Somewhat Disagree":2, - "Somewhat Agree":3, + "Disagree":2, + "Agree":3, "Strongly Agree":4, - "Neutral":5 + "Neither Agree nor Disagree":5 } # Add bars -for col in df[["Somewhat Disagree","Strongly Disagree","Somewhat Agree","Strongly Agree","Neutral"]]: +for col in df[["Disagree","Strongly Disagree","Agree","Strongly Agree","Neither Agree nor Disagree"]]: fig.add_trace(go.Bar( y=df["Category"], x=df[col], @@ -266,10 +267,8 @@ for col in df[["Somewhat Disagree","Strongly Disagree","Somewhat Agree","Strongl orientation='h', marker=dict(color=color_by_category[col]), legendrank=legend_rank_by_category[col], - xaxis=f"x{1+(col=="Neutral")}", # in this context, putting neutral on a secondary x-axis on a different domain + xaxis=f"x{1+(col=="Neither Agree nor Disagree")}", # in this context, putting "Neither Agree nor Disagree" on a secondary x-axis on a different domain # yields results equivalent to subplots with far less code - - ) ) @@ -278,15 +277,16 @@ for col in df[["Somewhat Disagree","Strongly Disagree","Somewhat Agree","Strongl # Find the maximum width of the bars to the left and right sides of the origin; remember that the width of # the plot is the sum of the longest negative bar and the longest positive bar even if they are on separate rows -max_left = min(df[["Somewhat Disagree","Strongly Disagree"]].sum(axis=1)) -max_right = max(df[["Somewhat Agree","Strongly Agree"]].sum(axis=1)) +max_left = min(df[["Disagree","Strongly Disagree"]].sum(axis=1)) +max_right = max(df[["Agree","Strongly Agree"]].sum(axis=1)) # we are working in percent, but coded the negative reactions as negative numbers; so we need to take the absolute value max_width_signed = abs(max_left)+max_right -max_width_neutral = max(df["Neutral"]) +max_width_neither = max(df["Neither Agree nor Disagree"]) fig.update_layout( - title="Reactions to the statement, 'The service met your expectations for':", + + title="Reactions to statements from the 2002 General Social Survey:", plot_bgcolor="white", barmode='relative', # Allows bars to diverge from the center ) @@ -296,12 +296,12 @@ fig.update_xaxes( #starting here, we set domain and range to create a shared x-axis scale # multiply by .98 to add space between the two columns range=[max_left, max_right], - domain=[0, 0.98*(max_width_signed/(max_width_signed+max_width_neutral))] + domain=[0, 0.98*(max_width_signed/(max_width_signed+max_width_neither))] ) fig.update_layout( xaxis2=dict( - range=[0, max_width_neutral], - domain=[(1-.98*(1-max_width_signed/(max_width_signed+max_width_neutral))), 1.0], + range=[0, max_width_neither], + domain=[(1-.98*(1-max_width_signed/(max_width_signed+max_width_neither))), 1.0], ) ) fig.update_legends( From 70b7f49b0036b0873c88a08fcd11f1f493caeb7c Mon Sep 17 00:00:00 2001 From: Rob Letzler <22990670+rl-utility-man@users.noreply.github.com> Date: Wed, 26 Mar 2025 16:21:00 -0400 Subject: [PATCH 05/11] improved the comments. --- doc/python/horizontal-bar-charts.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/python/horizontal-bar-charts.md b/doc/python/horizontal-bar-charts.md index 52cd62f0ae..d8a84d884e 100644 --- a/doc/python/horizontal-bar-charts.md +++ b/doc/python/horizontal-bar-charts.md @@ -218,7 +218,7 @@ fig.show() ``` ### Diverging Bar (or Butterfly) Chart with Neutral Column -Diverging bar charts offer two imperfect options for responses that are neither positive nor negative: omit them, leaving them implicit when the categories add to 100%, as we did above or put them in a separate column, as we do in this example. Jonathan Schwabish discusses this on page 92-97 of _Better Data Visualizations_. +Diverging bar charts offer two imperfect options for responses that are neither positive nor negative: put them in a separate column, as in this example or omit them as in the example above. That leaves the unreported neutral value implicit when the categories add to 100%, Jonathan Schwabish discusses this on page 92-97 of _Better Data Visualizations_. ``` import pandas as pd @@ -226,7 +226,6 @@ import plotly.graph_objects as go df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/refs/heads/master/gss_2002_5_pt_likert.csv') -#data source details are in this CSV file df.rename(columns={'Unnamed: 0':"Category"}, inplace=True) @@ -235,7 +234,7 @@ for v in ["Disagree","Strongly Disagree"]: df[v]=df[v]*-1 fig = go.Figure() -# this color palette conveys meaning: blues for negative, reds for positive, gray for Neither Agree nor Disagree +# this color palette conveys meaning: blues for agreement, reds and oranges for disagreement, gray for Neither Agree nor Disagree color_by_category={ "Strongly Agree":'darkblue', "Agree":'lightblue', @@ -285,11 +284,11 @@ max_width_signed = abs(max_left)+max_right max_width_neither = max(df["Neither Agree nor Disagree"]) fig.update_layout( - title="Reactions to statements from the 2002 General Social Survey:", plot_bgcolor="white", barmode='relative', # Allows bars to diverge from the center ) + fig.update_xaxes( zeroline=True, #the zero line distinguishes between positive and negative segments zerolinecolor="black", @@ -297,13 +296,15 @@ fig.update_xaxes( # multiply by .98 to add space between the two columns range=[max_left, max_right], domain=[0, 0.98*(max_width_signed/(max_width_signed+max_width_neither))] -) +) + fig.update_layout( xaxis2=dict( range=[0, max_width_neither], domain=[(1-.98*(1-max_width_signed/(max_width_signed+max_width_neither))), 1.0], ) ) + fig.update_legends( orientation="h", # a horizontal legend matches the horizontal bars yref="container", From 886078fc65e956044c5446d24a90c53ea6c066ed Mon Sep 17 00:00:00 2001 From: Rob Letzler <22990670+rl-utility-man@users.noreply.github.com> Date: Mon, 31 Mar 2025 15:36:51 -0400 Subject: [PATCH 06/11] add python decorator --- doc/python/horizontal-bar-charts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/python/horizontal-bar-charts.md b/doc/python/horizontal-bar-charts.md index d8a84d884e..6df6f16053 100644 --- a/doc/python/horizontal-bar-charts.md +++ b/doc/python/horizontal-bar-charts.md @@ -220,7 +220,7 @@ fig.show() Diverging bar charts offer two imperfect options for responses that are neither positive nor negative: put them in a separate column, as in this example or omit them as in the example above. That leaves the unreported neutral value implicit when the categories add to 100%, Jonathan Schwabish discusses this on page 92-97 of _Better Data Visualizations_. -``` +```python import pandas as pd import plotly.graph_objects as go From d5e2284e1e4290b6bd6eebf52bb7748e1aecb3cc Mon Sep 17 00:00:00 2001 From: Rob Letzler <22990670+rl-utility-man@users.noreply.github.com> Date: Tue, 8 Apr 2025 21:17:14 -0400 Subject: [PATCH 07/11] corrected quotation mark type --- doc/python/horizontal-bar-charts.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/python/horizontal-bar-charts.md b/doc/python/horizontal-bar-charts.md index 6df6f16053..f3afd0f437 100644 --- a/doc/python/horizontal-bar-charts.md +++ b/doc/python/horizontal-bar-charts.md @@ -258,7 +258,7 @@ legend_rank_by_category={ } # Add bars -for col in df[["Disagree","Strongly Disagree","Agree","Strongly Agree","Neither Agree nor Disagree"]]: +for col in ["Disagree","Strongly Disagree","Agree","Strongly Agree","Neither Agree nor Disagree"]: fig.add_trace(go.Bar( y=df["Category"], x=df[col], @@ -266,7 +266,7 @@ for col in df[["Disagree","Strongly Disagree","Agree","Strongly Agree","Neither orientation='h', marker=dict(color=color_by_category[col]), legendrank=legend_rank_by_category[col], - xaxis=f"x{1+(col=="Neither Agree nor Disagree")}", # in this context, putting "Neither Agree nor Disagree" on a secondary x-axis on a different domain + xaxis=f"x{1+(col=='Neither Agree nor Disagree')}", # in this context, putting "Neither Agree nor Disagree" on a secondary x-axis on a different domain # yields results equivalent to subplots with far less code ) ) From be52c356874246da013f5d9d4469cfb0e780154a Mon Sep 17 00:00:00 2001 From: Rob Letzler <22990670+rl-utility-man@users.noreply.github.com> Date: Tue, 15 Apr 2025 23:34:52 -0400 Subject: [PATCH 08/11] replace an update_layout call with a go.figure() call --- doc/python/horizontal-bar-charts.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/python/horizontal-bar-charts.md b/doc/python/horizontal-bar-charts.md index f3afd0f437..72900b4e48 100644 --- a/doc/python/horizontal-bar-charts.md +++ b/doc/python/horizontal-bar-charts.md @@ -233,7 +233,13 @@ df.rename(columns={'Unnamed: 0':"Category"}, inplace=True) for v in ["Disagree","Strongly Disagree"]: df[v]=df[v]*-1 -fig = go.Figure() +fig = go.Figure(layout=go.Layout( + title="Reactions to statements from the 2002 General Social Survey:", + plot_bgcolor="white", + barmode='relative' # Allows bars to diverge from the center + )) + + # this color palette conveys meaning: blues for agreement, reds and oranges for disagreement, gray for Neither Agree nor Disagree color_by_category={ "Strongly Agree":'darkblue', @@ -283,12 +289,6 @@ max_right = max(df[["Agree","Strongly Agree"]].sum(axis=1)) max_width_signed = abs(max_left)+max_right max_width_neither = max(df["Neither Agree nor Disagree"]) -fig.update_layout( - title="Reactions to statements from the 2002 General Social Survey:", - plot_bgcolor="white", - barmode='relative', # Allows bars to diverge from the center - ) - fig.update_xaxes( zeroline=True, #the zero line distinguishes between positive and negative segments zerolinecolor="black", From 2140af6eb7d9a68c20cd8d9ffedafb1d5b124d9b Mon Sep 17 00:00:00 2001 From: Rob Letzler <22990670+rl-utility-man@users.noreply.github.com> Date: Tue, 15 Apr 2025 23:47:22 -0400 Subject: [PATCH 09/11] moved yaxis title and legned layout to go.Figure() --- doc/python/horizontal-bar-charts.md | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/doc/python/horizontal-bar-charts.md b/doc/python/horizontal-bar-charts.md index 72900b4e48..e8a6875eda 100644 --- a/doc/python/horizontal-bar-charts.md +++ b/doc/python/horizontal-bar-charts.md @@ -236,8 +236,21 @@ for v in ["Disagree","Strongly Disagree"]: fig = go.Figure(layout=go.Layout( title="Reactions to statements from the 2002 General Social Survey:", plot_bgcolor="white", - barmode='relative' # Allows bars to diverge from the center - )) + barmode='relative', # Allows bars to diverge from the center + # Put the legend at the bottom center of the figure + legend=dict( + orientation="h", # a horizontal legend matches the horizontal bars + yref="container", + yanchor="bottom", + y=0.02, + xanchor="center", + x=0.5), + # use an unlabeled Y axis, since we're going to list specific questions on the y-axis. + yaxis=dict( + title="" + ), + ) +) # this color palette conveys meaning: blues for agreement, reds and oranges for disagreement, gray for Neither Agree nor Disagree @@ -305,17 +318,6 @@ fig.update_layout( ) ) -fig.update_legends( - orientation="h", # a horizontal legend matches the horizontal bars - yref="container", - yanchor="bottom", - y=0.02, - xanchor="center", - x=0.5 -) - -fig.update_yaxes(title="") - fig.show() ``` From a14f4cb9787ca6e100becee4b5103c4da0b12f0b Mon Sep 17 00:00:00 2001 From: Rob Letzler <22990670+rl-utility-man@users.noreply.github.com> Date: Tue, 15 Apr 2025 23:55:50 -0400 Subject: [PATCH 10/11] introductory text edit. --- doc/python/horizontal-bar-charts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/python/horizontal-bar-charts.md b/doc/python/horizontal-bar-charts.md index e8a6875eda..ba6544e2e5 100644 --- a/doc/python/horizontal-bar-charts.md +++ b/doc/python/horizontal-bar-charts.md @@ -218,7 +218,7 @@ fig.show() ``` ### Diverging Bar (or Butterfly) Chart with Neutral Column -Diverging bar charts offer two imperfect options for responses that are neither positive nor negative: put them in a separate column, as in this example or omit them as in the example above. That leaves the unreported neutral value implicit when the categories add to 100%, Jonathan Schwabish discusses this on page 92-97 of _Better Data Visualizations_. +The previous diverging bar chart example excluded neutral responses. This variation includes them in a separate column. Jonathan Schwabish discusses tradeoffs between these options on page 92-97 of _Better Data Visualizations_. ```python import pandas as pd From 8d0a2eb5d8e3e7cc3b2a748be71b906299eef071 Mon Sep 17 00:00:00 2001 From: Rob Letzler <22990670+rl-utility-man@users.noreply.github.com> Date: Tue, 29 Apr 2025 23:40:05 -0400 Subject: [PATCH 11/11] attempted to manually merge the latest changes to doc-prod so the new contribution is the second butterfly example --- doc/python/horizontal-bar-charts.md | 82 +++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 5 deletions(-) diff --git a/doc/python/horizontal-bar-charts.md b/doc/python/horizontal-bar-charts.md index ba6544e2e5..3181f5285a 100644 --- a/doc/python/horizontal-bar-charts.md +++ b/doc/python/horizontal-bar-charts.md @@ -5,10 +5,10 @@ jupyter: text_representation: extension: .md format_name: markdown - format_version: '1.1' - jupytext_version: 1.1.1 + format_version: '1.3' + jupytext_version: 1.16.4 kernelspec: - display_name: Python 3 + display_name: Python 3 (ipykernel) language: python name: python3 language_info: @@ -20,7 +20,7 @@ jupyter: name: python nbconvert_exporter: python pygments_lexer: ipython3 - version: 3.6.7 + version: 3.11.10 plotly: description: How to make horizontal bar charts in Python with Plotly. display_as: basic @@ -216,6 +216,78 @@ fig.update_layout(annotations=annotations) fig.show() ``` + +### Diverging Bar (or Butterfly) Chart + +Diverging bar charts show counts of positive outcomes or sentiments to the right of zero and counts of negative outcomes to the left of zero, allowing the reader to easily spot areas of excellence and concern. This example allows the reader of the graph to infer the number of people offering a neutral response because the neutral category, which is left implicit, would make the responses add to 100%. + +```python +import plotly.graph_objects as go +import pandas as pd + + +df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/refs/heads/master/gss_2002_5_pt_likert.csv') + +df.rename(columns={'Unnamed: 0':"Category"}, inplace=True) + +#achieve the diverging effect by putting a negative sign on the "disagree" answers +for v in ["Disagree","Strongly Disagree"]: + df[v]=df[v]*-1 + +fig = go.Figure() +# this color palette conveys meaning: blues for positive, red and orange for negative +color_by_category={ + "Strongly Agree":'darkblue', + "Agree":'lightblue', + "Disagree":'orange', + "Strongly Disagree":'red', +} + + +# We want the legend to be ordered in the same order that the categories appear, left to right -- +# which is different from the order in which we have to add the traces to the figure. +# since we need to create the "somewhat" traces before the "strongly" traces to display +# the segments in the desired order +legend_rank_by_category={ + "Strongly Disagree":1, + "Disagree":2, + "Agree":3, + "Strongly Agree":4, +} +# Add bars for each category +for col in ["Disagree","Strongly Disagree","Agree","Strongly Agree"]: + fig.add_trace(go.Bar( + y=df["Category"], + x=df[col], + name=col, + orientation='h', + marker=dict(color=color_by_category[col]), + legendrank=legend_rank_by_category[col] + )) + +fig.update_layout( + title="Reactions to statements from the 2002 General Social Survey:", + yaxis_title = "", + barmode='relative', # Allows bars to diverge from the center + plot_bgcolor="white", +) + +fig.update_xaxes( + title="Percent of Responses", + zeroline=True, # Ensure there's a zero line for divergence + zerolinecolor="black", + # use array tick mode to show that the counts to the left of zero are still positive. + # this is hard coded; generalize this if you plan to create a function that takes unknown or widely varying data + tickmode = 'array', + tickvals = [-50, 0, 50, 100], + ticktext = [50, 0, 50, 100] +) + +fig.show() + +``` + + ### Diverging Bar (or Butterfly) Chart with Neutral Column The previous diverging bar chart example excluded neutral responses. This variation includes them in a separate column. Jonathan Schwabish discusses tradeoffs between these options on page 92-97 of _Better Data Visualizations_. @@ -439,4 +511,4 @@ fig.show() ### Reference -See more examples of bar charts and styling options [here](https://plotly.com/python/bar-charts/).
See https://plotly.com/python/reference/bar/ for more information and chart attribute options! +See more examples of bar charts and styling options [here](https://plotly.com/python/bar-charts/).
See https://plotly.com/python/reference/bar/ for more information and chart attribute options! \ No newline at end of file