{"spec_id":"line-confidence","library":"altair","language":"python","code":"\"\"\" anyplot.ai\nline-confidence: Line Plot with Confidence Interval\nLibrary: altair 6.1.0 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-09\n\"\"\"\n\nimport os\nimport sys\n\n\nif sys.path[0] == os.path.dirname(__file__):\n    sys.path.pop(0)\n\nimport altair as alt\nimport numpy as np\nimport pandas as pd\n\n\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\"\nBRAND = \"#009E73\"\n\n# Data: Time series forecast with 95% confidence interval\nnp.random.seed(42)\nn_points = 50\ndays = np.arange(n_points)\n\n# Generate trend with natural curvature\ntrend = 100 + 0.5 * days + 0.02 * days**2 + np.sin(days / 5) * 5\nnoise = np.random.normal(0, 3, n_points)\ny_mean = trend + noise\n\n# Confidence interval widening over time (realistic for forecasts)\nuncertainty = 5 + 0.15 * days\ny_lower = y_mean - 1.96 * uncertainty / 2\ny_upper = y_mean + 1.96 * uncertainty / 2\n\ndf = pd.DataFrame({\"Day\": days, \"Predicted Mean\": y_mean, \"Lower\": y_lower, \"Upper\": y_upper})\n\n# Use actual data range for y-axis, not starting at 0\ny_min = df[\"Lower\"].min()\ny_max = df[\"Upper\"].max()\ny_padding = (y_max - y_min) * 0.05\ny_scale = alt.Scale(domain=[y_min - y_padding, y_max + y_padding])\n\n# Reshape data for layered encoding: band needs separate rows for fill\nband_data = df.copy()\n\n# Create the confidence band (area)\nband = (\n    alt.Chart(band_data)\n    .mark_area(opacity=0.25, color=BRAND)\n    .encode(\n        x=alt.X(\n            \"Day:Q\", title=\"Day\", axis=alt.Axis(labelFontSize=18, titleFontSize=22, labelColor=INK_SOFT, titleColor=INK)\n        ),\n        y=alt.Y(\n            \"Lower:Q\",\n            title=\"Predicted Value\",\n            scale=y_scale,\n            axis=alt.Axis(labelFontSize=18, titleFontSize=22, labelColor=INK_SOFT, titleColor=INK),\n        ),\n        y2=\"Upper:Q\",\n    )\n)\n\n# Create the central line with larger stroke width\nline = alt.Chart(df).mark_line(strokeWidth=5, color=BRAND).encode(x=\"Day:Q\", y=alt.Y(\"Predicted Mean:Q\", scale=y_scale))\n\n# Add point markers on the line\npoints = (\n    alt.Chart(df)\n    .mark_point(size=150, filled=True, color=BRAND)\n    .encode(x=\"Day:Q\", y=alt.Y(\"Predicted Mean:Q\", scale=y_scale))\n)\n\n# Combine all layers\nchart = (\n    alt.layer(band, line, points)\n    .properties(\n        width=1600,\n        height=900,\n        background=PAGE_BG,\n        title=alt.Title(\"line-confidence · altair · anyplot.ai\", fontSize=28, color=INK, anchor=\"middle\"),\n    )\n    .configure_view(fill=PAGE_BG, stroke=INK_SOFT, strokeWidth=1)\n    .configure_axis(domainColor=INK_SOFT, tickColor=INK_SOFT, gridColor=INK, gridOpacity=0.10)\n    .configure_title(fontSize=28, color=INK)\n)\n\n# Save as PNG (scale_factor=3 gives 4800x2700)\nchart.save(f\"plot-{THEME}.png\", scale_factor=3.0)\n\n# Save as HTML with interactivity and tooltips\ninteractive_band = (\n    alt.Chart(band_data)\n    .mark_area(opacity=0.25, color=BRAND)\n    .encode(\n        x=alt.X(\"Day:Q\", title=\"Day\"),\n        y=alt.Y(\"Lower:Q\", title=\"Predicted Value\", scale=y_scale),\n        y2=\"Upper:Q\",\n        tooltip=[\n            alt.Tooltip(\"Day:Q\", title=\"Day\", format=\"d\"),\n            alt.Tooltip(\"Lower:Q\", title=\"Lower Bound\", format=\".1f\"),\n            alt.Tooltip(\"Upper:Q\", title=\"Upper Bound\", format=\".1f\"),\n        ],\n    )\n)\n\ninteractive_line = (\n    alt.Chart(df)\n    .mark_line(strokeWidth=5, color=BRAND)\n    .encode(\n        x=\"Day:Q\",\n        y=alt.Y(\"Predicted Mean:Q\", scale=y_scale),\n        tooltip=alt.Tooltip(\"Predicted Mean:Q\", title=\"Predicted Mean\", format=\".1f\"),\n    )\n)\n\ninteractive_points = (\n    alt.Chart(df)\n    .mark_point(size=150, filled=True, color=BRAND)\n    .encode(\n        x=\"Day:Q\",\n        y=alt.Y(\"Predicted Mean:Q\", scale=y_scale),\n        tooltip=[\n            alt.Tooltip(\"Day:Q\", title=\"Day\", format=\"d\"),\n            alt.Tooltip(\"Predicted Mean:Q\", title=\"Predicted Mean\", format=\".1f\"),\n        ],\n    )\n)\n\ninteractive_chart = (\n    alt.layer(interactive_band, interactive_line, interactive_points)\n    .properties(\n        width=1600,\n        height=900,\n        background=PAGE_BG,\n        title=alt.Title(\"line-confidence · altair · anyplot.ai\", fontSize=28, color=INK, anchor=\"middle\"),\n    )\n    .configure_view(fill=PAGE_BG, stroke=INK_SOFT, strokeWidth=1)\n    .configure_axis(\n        domainColor=INK_SOFT,\n        tickColor=INK_SOFT,\n        gridColor=INK,\n        gridOpacity=0.10,\n        labelColor=INK_SOFT,\n        titleColor=INK,\n        labelFontSize=18,\n        titleFontSize=22,\n    )\n    .configure_title(fontSize=28, color=INK)\n    .interactive()\n)\n\ninteractive_chart.save(f\"plot-{THEME}.html\")\n"}