{"spec_id":"subplot-grid","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nsubplot-grid: Subplot Grid Layout\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 97/100 | Updated: 2026-05-13\n\"\"\"\n\nimport os\nimport sys\n\n\n# Remove current directory from sys.path to avoid shadowing installed packages\nsys.path = [p for p in sys.path if p not in (\"\", \".\")]\n\nimport numpy as np\nimport pandas as pd\nimport plotly.graph_objects as go\nfrom plotly.subplots import make_subplots\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\"\nGRID = \"rgba(26,26,23,0.10)\" if THEME == \"light\" else \"rgba(240,239,232,0.10)\"\n\n# Okabe-Ito palette\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\"]\n\n# Data - Financial dashboard example\nnp.random.seed(42)\n\n# Generate 60 days of stock data\ndays = 60\ndates = pd.date_range(\"2024-01-01\", periods=days, freq=\"D\")\n\n# Stock price with realistic walk\nreturns = np.random.normal(0.001, 0.02, days)\nprice = 100 * np.cumprod(1 + returns)\n\n# Volume data (correlated with absolute price movement)\nbase_volume = 1000000\nvolume = base_volume + np.abs(returns) * 50000000 + np.random.normal(0, 200000, days)\nvolume = np.clip(volume, 500000, 3000000)\n\n# Daily returns for histogram\ndaily_returns = np.diff(price) / price[:-1] * 100\n\n# Moving averages\nma_20 = pd.Series(price).rolling(20).mean().values\n\n# Create 2x2 subplot grid\nfig = make_subplots(\n    rows=2,\n    cols=2,\n    subplot_titles=(\"Stock Price & Moving Average\", \"Trading Volume\", \"Daily Returns Distribution\", \"Price vs Volume\"),\n    horizontal_spacing=0.1,\n    vertical_spacing=0.12,\n    specs=[[{\"type\": \"scatter\"}, {\"type\": \"bar\"}], [{\"type\": \"histogram\"}, {\"type\": \"scatter\"}]],\n)\n\n# Subplot 1: Line chart - Stock price with moving average\nfig.add_trace(\n    go.Scatter(x=dates, y=price, mode=\"lines\", name=\"Price\", line={\"color\": IMPRINT[0], \"width\": 3}), row=1, col=1\n)\nfig.add_trace(\n    go.Scatter(\n        x=dates, y=ma_20, mode=\"lines\", name=\"20-day MA\", line={\"color\": IMPRINT[1], \"width\": 2, \"dash\": \"dash\"}\n    ),\n    row=1,\n    col=1,\n)\n\n# Subplot 2: Bar chart - Volume\nvolume_colors = [IMPRINT[0] if r >= 0 else IMPRINT[1] for r in returns]\nfig.add_trace(go.Bar(x=dates, y=volume, name=\"Volume\", marker={\"color\": volume_colors, \"opacity\": 0.8}), row=1, col=2)\n\n# Subplot 3: Histogram - Daily returns distribution\nfig.add_trace(\n    go.Histogram(\n        x=daily_returns,\n        nbinsx=20,\n        name=\"Returns\",\n        marker={\"color\": IMPRINT[0], \"opacity\": 0.75, \"line\": {\"color\": PAGE_BG, \"width\": 1}},\n    ),\n    row=2,\n    col=1,\n)\n\n# Subplot 4: Scatter - Price vs Volume relationship\nfig.add_trace(\n    go.Scatter(\n        x=volume,\n        y=price,\n        mode=\"markers\",\n        name=\"Price-Volume\",\n        marker={\"color\": IMPRINT[0], \"size\": 14, \"opacity\": 0.7, \"line\": {\"color\": PAGE_BG, \"width\": 1}},\n    ),\n    row=2,\n    col=2,\n)\n\n# Update layout\nfig.update_layout(\n    title={\n        \"text\": \"subplot-grid · plotly · anyplot.ai\",\n        \"font\": {\"size\": 28, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    showlegend=True,\n    legend={\n        \"font\": {\"size\": 16, \"color\": INK_SOFT},\n        \"x\": 1.02,\n        \"y\": 1,\n        \"xanchor\": \"left\",\n        \"yanchor\": \"top\",\n        \"bgcolor\": ELEVATED_BG,\n        \"bordercolor\": INK_SOFT,\n        \"borderwidth\": 1,\n    },\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    font={\"color\": INK},\n    margin={\"l\": 80, \"r\": 150, \"t\": 120, \"b\": 80},\n)\n\n# Update all axes with theme-adaptive colors and gridlines\nfig.update_xaxes(\n    tickfont={\"size\": 18, \"color\": INK_SOFT},\n    title_font={\"size\": 22, \"color\": INK},\n    gridcolor=GRID,\n    showgrid=True,\n    gridwidth=1,\n    linecolor=INK_SOFT,\n    zerolinecolor=INK_SOFT,\n)\nfig.update_yaxes(\n    tickfont={\"size\": 18, \"color\": INK_SOFT},\n    title_font={\"size\": 22, \"color\": INK},\n    gridcolor=GRID,\n    showgrid=True,\n    gridwidth=1,\n    linecolor=INK_SOFT,\n    zerolinecolor=INK_SOFT,\n)\n\n# Specific axis labels\nfig.update_xaxes(title_text=\"Date\", row=1, col=1)\nfig.update_yaxes(title_text=\"Price ($)\", row=1, col=1)\nfig.update_xaxes(title_text=\"Date\", row=1, col=2)\nfig.update_yaxes(title_text=\"Volume\", row=1, col=2)\nfig.update_xaxes(title_text=\"Daily Return (%)\", row=2, col=1)\nfig.update_yaxes(title_text=\"Frequency\", row=2, col=1)\nfig.update_xaxes(title_text=\"Volume\", row=2, col=2)\nfig.update_yaxes(title_text=\"Price ($)\", row=2, col=2)\n\n# Update subplot titles font size and color\nfor annotation in fig[\"layout\"][\"annotations\"]:\n    annotation[\"font\"] = {\"size\": 20, \"color\": INK}\n\n# Save PNG (4800x2700 via scale=3)\nfig.write_image(f\"plot-{THEME}.png\", width=1600, height=900, scale=3)\n\n# Save interactive HTML\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}