{"spec_id":"area-basic","library":"altair","language":"python","code":"\"\"\" anyplot.ai\narea-basic: Basic Area Chart\nLibrary: altair 6.1.0 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-28\n\"\"\"\n\nimport os\nimport sys\n\n\n# Prevent self-import: this file is named altair.py, so remove its directory\n# from sys.path before importing the altair package.\n_this_dir = os.path.dirname(os.path.abspath(__file__))\nsys.path = [p for p in sys.path if p and os.path.abspath(p) != _this_dir]\n\nimport altair as alt\nimport numpy as np\nimport pandas as pd\nfrom PIL import Image\n\n\n# Theme\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 - daily website visitors over January 2024\nnp.random.seed(42)\ndates = pd.date_range(start=\"2024-01-01\", periods=30, freq=\"D\")\nbase = 5000\ntrend = np.linspace(0, 2000, 30)\nweekly_pattern = np.array([1.2, 1.1, 1.0, 1.05, 1.15, 0.8, 0.7] * 5)[:30]\nnoise = np.random.randn(30) * 300\nvisitors = (base + trend) * weekly_pattern + noise\nvisitors[14] *= 1.4\nvisitors = np.maximum(visitors, 1000).astype(int)\ndf = pd.DataFrame({\"date\": dates, \"visitors\": visitors})\n\n# Peak annotation data\npeak_idx = df[\"visitors\"].idxmax()\npeak_row = df.loc[peak_idx]\npeak_df = pd.DataFrame(\n    {\"date\": [peak_row[\"date\"]], \"visitors\": [peak_row[\"visitors\"]], \"label\": [f\"Peak: {int(peak_row['visitors']):,}\"]}\n)\n\n# Chart title\ntitle = \"area-basic · python · altair · anyplot.ai\"\n\n# Area layer\narea = (\n    alt.Chart(df)\n    .mark_area(\n        line={\"color\": BRAND, \"strokeWidth\": 2.5},\n        color=alt.Gradient(\n            gradient=\"linear\",\n            stops=[\n                alt.GradientStop(color=\"rgba(0, 158, 115, 0.05)\", offset=0),\n                alt.GradientStop(color=\"rgba(0, 158, 115, 0.60)\", offset=1),\n            ],\n            x1=1,\n            x2=1,\n            y1=1,\n            y2=0,\n        ),\n    )\n    .encode(\n        x=alt.X(\"date:T\", title=\"Date\", axis=alt.Axis(format=\"%b %d\", labelAngle=-30)),\n        y=alt.Y(\n            \"visitors:Q\", title=\"Daily Visitors (count)\", scale=alt.Scale(domain=[0, int(df[\"visitors\"].max() * 1.15)])\n        ),\n        tooltip=[\n            alt.Tooltip(\"date:T\", title=\"Date\", format=\"%b %d, %Y\"),\n            alt.Tooltip(\"visitors:Q\", title=\"Visitors\", format=\",\"),\n        ],\n    )\n)\n\n# Vertical rule at peak\npeak_rule = (\n    alt.Chart(peak_df).mark_rule(color=BRAND, strokeDash=[4, 4], strokeWidth=1.5, opacity=0.5).encode(x=alt.X(\"date:T\"))\n)\n\n# Text label at peak\npeak_text = (\n    alt.Chart(peak_df)\n    .mark_text(align=\"left\", dx=8, dy=-10, color=INK, fontSize=9, fontWeight=\"bold\")\n    .encode(x=alt.X(\"date:T\"), y=alt.Y(\"visitors:Q\"), text=\"label:N\")\n)\n\nchart = (\n    alt.layer(area, peak_rule, peak_text)\n    .properties(width=620, height=320, background=PAGE_BG, title=alt.Title(title, fontSize=16))\n    .configure_view(continuousWidth=620, continuousHeight=320, fill=PAGE_BG, strokeWidth=0)\n    .configure_axis(\n        domainColor=INK_SOFT,\n        tickColor=INK_SOFT,\n        gridColor=INK,\n        gridOpacity=0.15,\n        labelColor=INK_SOFT,\n        titleColor=INK,\n        labelFontSize=10,\n        titleFontSize=12,\n    )\n    .configure_axisX(grid=False)\n    .configure_title(color=INK)\n    .configure_legend(fillColor=ELEVATED_BG, strokeColor=INK_SOFT, labelColor=INK_SOFT, titleColor=INK)\n)\n\n# Save PNG\nchart.save(f\"plot-{THEME}.png\", scale_factor=4.0)\n\n# Pad to exact 3200×1800\nTW, TH = 3200, 1800\n_img = Image.open(f\"plot-{THEME}.png\").convert(\"RGB\")\n_w, _h = _img.size\nif _w > TW or _h > TH:\n    raise SystemExit(\n        f\"altair vl-convert produced {_w}×{_h}, exceeds target {TW}×{TH}. \"\n        f\"Shrink chart .properties(width=, height=) values and re-render.\"\n    )\nif _w < TW or _h < TH:\n    _canvas = Image.new(\"RGB\", (TW, TH), PAGE_BG)\n    _canvas.paste(_img, ((TW - _w) // 2, (TH - _h) // 2))\n    _canvas.save(f\"plot-{THEME}.png\")\n\n# Save HTML\nchart.save(f\"plot-{THEME}.html\")\n"}