{"spec_id":"scatter-lag","library":"bokeh","language":"python","code":"\"\"\" anyplot.ai\nscatter-lag: Lag Plot for Time Series Autocorrelation Diagnosis\nLibrary: bokeh 3.9.1 | Python 3.13.14\nQuality: 90/100 | Updated: 2026-06-24\n\"\"\"\n\nimport os\nimport sys\n\n\n# Prevent self-import: this file is named bokeh.py which shadows the installed\n# bokeh package when its directory is at the front of sys.path.\n_this_dir = os.path.dirname(os.path.abspath(__file__))\nsys.path = [p for p in sys.path if os.path.abspath(p or \".\") != _this_dir]\n\nimport time\nfrom pathlib import Path\n\nimport numpy as np\nfrom bokeh.io import output_file, save\nfrom bokeh.models import ColorBar, ColumnDataSource, HoverTool, Label, LinearColorMapper\nfrom bokeh.plotting import figure\nfrom bokeh.transform import linear_cmap\nfrom selenium import webdriver\nfrom selenium.webdriver.chrome.options import Options\n\n\n# Theme tokens (Imprint palette — see prompts/default-style-guide.md)\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\n\n# Imprint sequential colormap for time index (single-polarity: green → blue)\n_seq = np.round(np.linspace([0x00, 0x9E, 0x73], [0x44, 0x67, 0xA3], 256)).astype(int)\nIMPRINT_SEQ256 = [\"#{:02X}{:02X}{:02X}\".format(*row) for row in _seq]\ndel _seq\n\n# Data — AR(1) process with strong positive autocorrelation (phi=0.85)\nnp.random.seed(42)\nn_obs = 500\nphi = 0.85\nnoise = np.random.normal(0, 1, n_obs)\nseries = np.zeros(n_obs)\nseries[0] = noise[0]\nfor i in range(1, n_obs):\n    series[i] = phi * series[i - 1] + noise[i]\n\nlag = 1\ny_t = series[:-lag]\ny_t_lag = series[lag:]\ntime_index = np.arange(len(y_t))\ncorrelation = np.corrcoef(y_t, y_t_lag)[0, 1]\n\nsource = ColumnDataSource(data={\"y_t\": y_t, \"y_t_lag\": y_t_lag, \"time_index\": time_index})\n\n# Plot\ntitle = \"scatter-lag · python · bokeh · anyplot.ai\"\n\np = figure(\n    width=3200,\n    height=1800,\n    title=title,\n    x_axis_label=\"AR(1) Series y(t)\",\n    y_axis_label=\"AR(1) Series y(t + 1)\",\n    toolbar_location=None,\n    min_border_bottom=160,\n    min_border_left=180,\n    min_border_top=110,\n    min_border_right=200,\n)\n\ncmap = linear_cmap(\"time_index\", palette=IMPRINT_SEQ256, low=time_index.min(), high=time_index.max())\n\np.scatter(\n    x=\"y_t\", y=\"y_t_lag\", source=source, size=25, fill_color=cmap, line_color=PAGE_BG, line_width=0.8, fill_alpha=0.75\n)\n\n# Diagonal reference line (y = x)\naxis_min = min(y_t.min(), y_t_lag.min()) - 0.5\naxis_max = max(y_t.max(), y_t_lag.max()) + 0.5\np.line(\n    [axis_min, axis_max], [axis_min, axis_max], line_color=INK_SOFT, line_dash=\"dashed\", line_width=3, line_alpha=0.5\n)\n\n# Color bar for temporal progression\ncolor_mapper = LinearColorMapper(palette=IMPRINT_SEQ256, low=time_index.min(), high=time_index.max())\ncolor_bar = ColorBar(\n    color_mapper=color_mapper,\n    title=\"Time Step\",\n    title_text_font_size=\"28pt\",\n    title_text_color=INK,\n    title_standoff=20,\n    major_label_text_font_size=\"24pt\",\n    major_label_text_color=INK_SOFT,\n    label_standoff=12,\n    width=60,\n    padding=40,\n    background_fill_color=PAGE_BG,\n)\np.add_layout(color_bar, \"right\")\n\n# Correlation annotation\ncorr_label = Label(\n    x=axis_min + 0.3,\n    y=axis_max - 0.7,\n    text=f\"r = {correlation:.3f}\",\n    text_font_size=\"32pt\",\n    text_color=INK,\n    text_font_style=\"bold\",\n)\np.add_layout(corr_label)\n\n# HoverTool — distinctive Bokeh interactive feature (active in HTML export)\nhover = HoverTool(tooltips=[(\"y(t)\", \"@y_t{0.000}\"), (\"y(t + 1)\", \"@y_t_lag{0.000}\"), (\"Time step\", \"@time_index\")])\np.add_tools(hover)\n\n# Style — canonical font sizes for 3200×1800 (see prompts/library/bokeh.md)\np.title.text_font_size = \"50pt\"\np.title.text_font_style = \"normal\"\np.title.text_color = INK\n\np.xaxis.axis_label_text_font_size = \"42pt\"\np.yaxis.axis_label_text_font_size = \"42pt\"\np.xaxis.axis_label_text_color = INK\np.yaxis.axis_label_text_color = INK\n\np.xaxis.major_label_text_font_size = \"34pt\"\np.yaxis.major_label_text_font_size = \"34pt\"\np.xaxis.major_label_text_color = INK_SOFT\np.yaxis.major_label_text_color = INK_SOFT\n\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\np.xaxis.minor_tick_line_color = None\np.yaxis.minor_tick_line_color = None\n\np.xgrid.grid_line_color = INK\np.ygrid.grid_line_color = INK\np.xgrid.grid_line_alpha = 0.15\np.ygrid.grid_line_alpha = 0.15\n\np.outline_line_color = None\np.background_fill_color = PAGE_BG\np.border_fill_color = PAGE_BG\n\n# Save HTML (interactive catalog artifact) then PNG via headless Chrome\noutput_file(f\"plot-{THEME}.html\")\nsave(p)\n\nW, H = 3200, 1800\nWIN_H = H + 150  # browser viewport offset buffer\nopts = Options()\nfor arg in (\n    \"--headless=new\",\n    \"--no-sandbox\",\n    \"--disable-dev-shm-usage\",\n    \"--disable-gpu\",\n    f\"--window-size={W},{WIN_H}\",\n    \"--hide-scrollbars\",\n):\n    opts.add_argument(arg)\ndriver = webdriver.Chrome(options=opts)\ndriver.set_window_size(W, WIN_H)\ndriver.get(f\"file://{Path(f'plot-{THEME}.html').resolve()}\")\ntime.sleep(3)\ndriver.execute_script(\n    \"document.body.style.backgroundColor = arguments[0];document.documentElement.style.backgroundColor = arguments[0];\",\n    PAGE_BG,\n)\ntime.sleep(1)\ndriver.save_screenshot(f\"plot-{THEME}.png\")\ndriver.quit()\n"}