{"spec_id":"logistic-regression","library":"bokeh","language":"python","code":"\"\"\" anyplot.ai\nlogistic-regression: Logistic Regression Curve Plot\nLibrary: bokeh 3.9.0 | Python 3.13.13\nQuality: 89/100 | Updated: 2026-05-18\n\"\"\"\n\nimport os\n\n# Remove the current directory from sys.path to avoid circular imports with bokeh.py\nimport sys\nimport time\nfrom pathlib import Path\n\n\nsys.path = [p for p in sys.path if p not in (\"\", \".\", os.getcwd(), os.path.dirname(__file__))]\n\nimport numpy as np\nfrom bokeh.io import output_file, save\nfrom bokeh.models import ColumnDataSource, Label, Span\nfrom bokeh.plotting import figure\nfrom selenium import webdriver\nfrom selenium.webdriver.chrome.options import Options\nfrom sklearn.datasets import make_classification\nfrom sklearn.linear_model import LogisticRegression\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\"\n\n# Okabe-Ito colors\nCOLOR_0 = \"#009E73\"  # Class 0 - bluish green (brand color)\nCOLOR_1 = \"#C475FD\"  # Class 1 - vermillion\n\n# Data - Generate binary classification data\nnp.random.seed(42)\nX, y = make_classification(\n    n_samples=200, n_features=1, n_informative=1, n_redundant=0, n_clusters_per_class=1, flip_y=0.1, random_state=42\n)\nx = X.flatten()\n\n# Scale x to meaningful range (e.g., test score 20-80)\nx = (x - x.min()) / (x.max() - x.min()) * 60 + 20\n\n# Fit logistic regression\nmodel = LogisticRegression()\nmodel.fit(x.reshape(-1, 1), y)\n\n# Generate smooth curve for logistic regression\nx_curve = np.linspace(x.min() - 2, x.max() + 2, 300)\nprob_curve = model.predict_proba(x_curve.reshape(-1, 1))[:, 1]\n\n# Compute confidence intervals (using asymptotic approximation)\np_val = prob_curve\nse = np.sqrt(p_val * (1 - p_val) / len(x))\nz = 1.96\nci_lower = np.clip(prob_curve - z * se * 3, 0, 1)\nci_upper = np.clip(prob_curve + z * se * 3, 0, 1)\n\n# Jitter y values for visibility\njitter = np.random.uniform(-0.03, 0.03, len(y))\ny_jittered = y + jitter\n\n# Separate data by class\nclass_0_mask = y == 0\nclass_1_mask = y == 1\n\n# Create data sources\nsource_class0 = ColumnDataSource(data={\"x\": x[class_0_mask], \"y\": y_jittered[class_0_mask]})\nsource_class1 = ColumnDataSource(data={\"x\": x[class_1_mask], \"y\": y_jittered[class_1_mask]})\nsource_curve = ColumnDataSource(data={\"x\": x_curve, \"prob\": prob_curve, \"ci_lower\": ci_lower, \"ci_upper\": ci_upper})\n\n# Create figure\np = figure(\n    width=4800,\n    height=2700,\n    title=\"logistic-regression · python · bokeh · anyplot.ai\",\n    x_axis_label=\"Test Score\",\n    y_axis_label=\"Probability of Passing\",\n    x_range=(x.min() - 5, x.max() + 5),\n    y_range=(-0.08, 1.08),\n)\n\n# Confidence interval band\np.varea(\n    x=\"x\", y1=\"ci_lower\", y2=\"ci_upper\", source=source_curve, fill_color=COLOR_0, fill_alpha=0.15, legend_label=\"95% CI\"\n)\n\n# Logistic curve\np.line(x=\"x\", y=\"prob\", source=source_curve, line_color=COLOR_0, line_width=5, legend_label=\"Logistic Curve\")\n\n# Data points - Class 0\np.scatter(\n    x=\"x\",\n    y=\"y\",\n    source=source_class0,\n    size=20,\n    fill_color=COLOR_0,\n    fill_alpha=0.6,\n    line_color=PAGE_BG,\n    line_width=2,\n    legend_label=\"Class 0 (Failed)\",\n)\n\n# Data points - Class 1\np.scatter(\n    x=\"x\",\n    y=\"y\",\n    source=source_class1,\n    size=20,\n    fill_color=COLOR_1,\n    fill_alpha=0.6,\n    line_color=PAGE_BG,\n    line_width=2,\n    legend_label=\"Class 1 (Passed)\",\n)\n\n# Decision threshold line at p=0.5\nthreshold = Span(location=0.5, dimension=\"width\", line_color=INK_SOFT, line_width=4, line_dash=\"dashed\")\np.add_layout(threshold)\n\n# Add threshold label\nthreshold_label = Label(\n    x=x.max() - 5,\n    y=0.53,\n    text=\"Decision Threshold (p=0.5)\",\n    text_font_size=\"20pt\",\n    text_color=INK_SOFT,\n    text_align=\"right\",\n)\np.add_layout(threshold_label)\n\n# Model accuracy annotation\naccuracy = model.score(x.reshape(-1, 1), y)\naccuracy_label = Label(\n    x=x.min() + 2, y=0.92, text=f\"Model Accuracy: {accuracy:.1%}\", text_font_size=\"22pt\", text_color=INK\n)\np.add_layout(accuracy_label)\n\n# Styling\np.title.text_font_size = \"28pt\"\np.title.text_color = INK\np.xaxis.axis_label_text_font_size = \"22pt\"\np.yaxis.axis_label_text_font_size = \"22pt\"\np.xaxis.axis_label_text_color = INK\np.yaxis.axis_label_text_color = INK\np.xaxis.major_label_text_font_size = \"18pt\"\np.yaxis.major_label_text_font_size = \"18pt\"\np.xaxis.major_label_text_color = INK_SOFT\np.yaxis.major_label_text_color = INK_SOFT\n\n# Axis styling\np.xaxis.axis_line_color = INK_SOFT\np.yaxis.axis_line_color = INK_SOFT\np.xaxis.major_tick_line_color = INK_SOFT\np.yaxis.major_tick_line_color = INK_SOFT\n\n# Grid styling\np.xgrid.grid_line_color = INK\np.ygrid.grid_line_color = INK\np.xgrid.grid_line_alpha = 0.10\np.ygrid.grid_line_alpha = 0.10\n\n# Legend styling - repositioned to top-left to avoid data overlap\np.legend.location = \"top_left\"\np.legend.label_text_font_size = \"18pt\"\np.legend.label_text_color = INK_SOFT\np.legend.glyph_height = 35\np.legend.glyph_width = 35\np.legend.spacing = 12\np.legend.background_fill_color = ELEVATED_BG\np.legend.background_fill_alpha = 0.9\np.legend.border_line_color = INK_SOFT\np.legend.padding = 15\n\n# Background\np.background_fill_color = PAGE_BG\np.border_fill_color = PAGE_BG\np.outline_line_color = INK_SOFT\n\n# Save HTML\noutput_file(f\"plot-{THEME}.html\")\nsave(p)\n\n# Screenshot with Selenium\nW, H = 4800, 2700\nopts = Options()\nfor arg in (\n    \"--headless=new\",\n    \"--no-sandbox\",\n    \"--disable-dev-shm-usage\",\n    \"--disable-gpu\",\n    f\"--window-size={W},{H}\",\n    \"--hide-scrollbars\",\n):\n    opts.add_argument(arg)\ndriver = webdriver.Chrome(options=opts)\ndriver.set_window_size(W, H)\ndriver.get(f\"file://{Path(f'plot-{THEME}.html').resolve()}\")\ntime.sleep(3)\ndriver.save_screenshot(f\"plot-{THEME}.png\")\ndriver.quit()\n"}