{"spec_id":"subplot-grid","library":"altair","language":"python","code":"\"\"\" anyplot.ai\nsubplot-grid: Subplot Grid Layout\nLibrary: altair 6.1.0 | Python 3.13.13\nQuality: 98/100 | Updated: 2026-05-13\n\"\"\"\n\nimport os\n\nimport altair as alt\nimport numpy as np\nimport pandas as pd\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 palette (first series always #009E73)\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\"]\nBRAND = IMPRINT[0]\nSECONDARY = IMPRINT[1]\n\n# Data\nnp.random.seed(42)\n\n# Panel 1: Scatter plot - Product metrics\nn_products = 50\nproducts_df = pd.DataFrame(\n    {\n        \"Units Sold\": np.random.randint(100, 1000, n_products),\n        \"Revenue ($K)\": np.random.uniform(10, 100, n_products),\n        \"Product\": [f\"P{i}\" for i in range(n_products)],\n    }\n)\n\n# Panel 2: Line plot - Monthly performance\nmonths = pd.date_range(\"2024-01\", periods=12, freq=\"ME\")\nmonthly_df = pd.DataFrame(\n    {\"Month\": months, \"Sales\": np.cumsum(np.random.normal(50, 15, 12)) + 500, \"Target\": np.linspace(500, 700, 12)}\n)\nmonthly_df = monthly_df.melt(id_vars=[\"Month\"], var_name=\"Metric\", value_name=\"Value\")\n\n# Panel 3: Bar plot - Regional performance\nregions_df = pd.DataFrame(\n    {\"Region\": [\"North\", \"South\", \"East\", \"West\", \"Central\"], \"Performance\": [85, 72, 91, 68, 79]}\n)\n\n# Panel 4: Histogram - Distribution of order values\norder_values = np.random.lognormal(mean=4.5, sigma=0.5, size=200)\nhistogram_df = pd.DataFrame({\"Order Value ($)\": order_values})\n\n# Chart 1: Scatter plot\nscatter = (\n    alt.Chart(products_df)\n    .mark_circle(size=120, opacity=0.7)\n    .encode(\n        x=alt.X(\"Units Sold:Q\", title=\"Units Sold\"),\n        y=alt.Y(\"Revenue ($K):Q\", title=\"Revenue ($K)\"),\n        color=alt.value(BRAND),\n        tooltip=[\"Product\", \"Units Sold\", \"Revenue ($K)\"],\n    )\n    .properties(width=750, height=420, title=alt.Title(\"Product Performance\", fontSize=22, anchor=\"start\"))\n)\n\n# Chart 2: Line plot\nline = (\n    alt.Chart(monthly_df)\n    .mark_line(strokeWidth=3)\n    .encode(\n        x=alt.X(\"Month:T\", title=\"Month\"),\n        y=alt.Y(\"Value:Q\", title=\"Sales ($K)\", scale=alt.Scale(zero=False)),\n        color=alt.Color(\n            \"Metric:N\",\n            scale=alt.Scale(domain=[\"Sales\", \"Target\"], range=[BRAND, SECONDARY]),\n            legend=alt.Legend(title=\"Metric\", titleFontSize=16, labelFontSize=14),\n        ),\n        strokeDash=alt.StrokeDash(\n            \"Metric:N\", scale=alt.Scale(domain=[\"Sales\", \"Target\"], range=[[0], [5, 5]]), legend=None\n        ),\n    )\n    .properties(width=750, height=420, title=alt.Title(\"Monthly Sales Trend\", fontSize=22, anchor=\"start\"))\n)\n\n# Chart 3: Bar plot\nbar = (\n    alt.Chart(regions_df)\n    .mark_bar(size=60)\n    .encode(\n        x=alt.X(\"Region:N\", title=\"Region\", axis=alt.Axis(labelAngle=0)),\n        y=alt.Y(\"Performance:Q\", title=\"Performance Score\", scale=alt.Scale(domain=[0, 100])),\n        color=alt.condition(alt.datum.Performance >= 80, alt.value(BRAND), alt.value(SECONDARY)),\n        tooltip=[\"Region\", \"Performance\"],\n    )\n    .properties(width=750, height=420, title=alt.Title(\"Regional Performance\", fontSize=22, anchor=\"start\"))\n)\n\n# Chart 4: Histogram\nhistogram = (\n    alt.Chart(histogram_df)\n    .mark_bar(opacity=0.8)\n    .encode(\n        x=alt.X(\"Order Value ($):Q\", bin=alt.Bin(maxbins=25), title=\"Order Value ($)\"),\n        y=alt.Y(\"count():Q\", title=\"Frequency\"),\n        color=alt.value(BRAND),\n        tooltip=[alt.Tooltip(\"count()\", title=\"Count\")],\n    )\n    .properties(width=750, height=420, title=alt.Title(\"Order Value Distribution\", fontSize=22, anchor=\"start\"))\n)\n\n# Combine into 2x2 grid\nrow1 = alt.hconcat(scatter, line, spacing=60)\nrow2 = alt.hconcat(bar, histogram, spacing=60)\n\nchart = (\n    alt.vconcat(row1, row2, spacing=60)\n    .properties(\n        background=PAGE_BG,\n        title=alt.Title(\"subplot-grid · altair · anyplot.ai\", fontSize=28, anchor=\"middle\", offset=20),\n    )\n    .configure_axis(\n        labelFontSize=16,\n        titleFontSize=18,\n        gridOpacity=0.10,\n        domainColor=INK_SOFT,\n        tickColor=INK_SOFT,\n        gridColor=INK,\n        labelColor=INK_SOFT,\n        titleColor=INK,\n    )\n    .configure_view(strokeWidth=0, fill=PAGE_BG)\n    .configure_title(color=INK, fontSize=22)\n    .configure_legend(\n        fillColor=ELEVATED_BG,\n        strokeColor=INK_SOFT,\n        labelColor=INK_SOFT,\n        titleColor=INK,\n        titleFontSize=16,\n        labelFontSize=14,\n    )\n)\n\n# Save outputs\nchart.save(f\"plot-{THEME}.png\", scale_factor=3.0)\nchart.save(f\"plot-{THEME}.html\")\n"}