{"spec_id":"scatter-categorical","library":"bokeh","language":"python","code":"\"\"\" anyplot.ai\nscatter-categorical: Categorical Scatter Plot\nLibrary: bokeh 3.9.0 | Python 3.13.13\nQuality: 70/100 | Updated: 2026-05-12\n\"\"\"\n\nimport numpy as np\nfrom bokeh.io import export_png, output_file, save\nfrom bokeh.models import ColumnDataSource, Legend\nfrom bokeh.plotting import figure\n\n\n# Data\nnp.random.seed(42)\n\n# Generate three distinct groups with different patterns\nn_per_group = 50\n\n# Group A: Lower left cluster\nx_a = np.random.normal(25, 5, n_per_group)\ny_a = np.random.normal(30, 6, n_per_group)\ncat_a = [\"Product A\"] * n_per_group\n\n# Group B: Upper middle cluster\nx_b = np.random.normal(50, 7, n_per_group)\ny_b = np.random.normal(70, 8, n_per_group)\ncat_b = [\"Product B\"] * n_per_group\n\n# Group C: Right side, moderate y\nx_c = np.random.normal(75, 6, n_per_group)\ny_c = np.random.normal(50, 7, n_per_group)\ncat_c = [\"Product C\"] * n_per_group\n\n# Combine data\nx = np.concatenate([x_a, x_b, x_c])\ny = np.concatenate([y_a, y_b, y_c])\ncategories = cat_a + cat_b + cat_c\n\n# Define colors for each category (Python Blue, Python Yellow, colorblind-safe red)\ncolor_map = {\"Product A\": \"#306998\", \"Product B\": \"#FFD43B\", \"Product C\": \"#E74C3C\"}\n\n# Create figure with interactive tools\np = figure(\n    width=4800,\n    height=2700,\n    title=\"scatter-categorical · bokeh · pyplots.ai\",\n    x_axis_label=\"Marketing Spend ($K)\",\n    y_axis_label=\"Customer Engagement Score\",\n    tools=\"pan,wheel_zoom,box_zoom,reset,hover,save\",\n    tooltips=[(\"Category\", \"@cat\"), (\"X\", \"@x{0.1}\"), (\"Y\", \"@y{0.1}\")],\n)\n\n# Plot each category separately for legend\nlegend_items = []\n\nfor cat, color in color_map.items():\n    mask = [categories[i] == cat for i in range(len(categories))]\n    cat_x = [x[i] for i in range(len(x)) if mask[i]]\n    cat_y = [y[i] for i in range(len(y)) if mask[i]]\n    cat_source = ColumnDataSource(data={\"x\": cat_x, \"y\": cat_y, \"cat\": [cat] * len(cat_x)})\n    r = p.scatter(x=\"x\", y=\"y\", source=cat_source, size=25, color=color, alpha=0.7, line_color=\"white\", line_width=1)\n    legend_items.append((cat, [r]))\n\n# Add legend\nlegend = Legend(items=legend_items, location=\"top_right\")\nlegend.label_text_font_size = \"28pt\"\nlegend.glyph_height = 40\nlegend.glyph_width = 40\nlegend.spacing = 12\nlegend.padding = 15\nlegend.background_fill_alpha = 0.8\np.add_layout(legend)\n\n# Title styling\np.title.text_font_size = \"48pt\"\np.title.text_font_style = \"bold\"\n\n# Axis label styling\np.xaxis.axis_label_text_font_size = \"36pt\"\np.yaxis.axis_label_text_font_size = \"36pt\"\n\n# Tick label styling\np.xaxis.major_label_text_font_size = \"28pt\"\np.yaxis.major_label_text_font_size = \"28pt\"\n\n# Grid styling\np.grid.grid_line_alpha = 0.3\np.grid.grid_line_dash = \"dashed\"\n\n# Background\np.background_fill_color = \"#fafafa\"\n\n# Axis styling\np.axis.axis_line_width = 2\np.axis.major_tick_line_width = 2\n\n# Save PNG\nexport_png(p, filename=\"plot.png\")\n\n# Save interactive HTML\noutput_file(\"plot.html\", title=\"scatter-categorical · bokeh · pyplots.ai\")\nsave(p)\n"}