{ "cells": [ { "cell_type": "markdown", "id": "7cf6e05a-7380-4904-ba9c-abf3612027e6", "metadata": {}, "source": [ "# Plot Layout Scheme and Theme Parameters" ] }, { "cell_type": "markdown", "id": "1ac7287b4ade2801", "metadata": {}, "source": [ "This demo illustrates the overall plot structure and the effect of various layout-related theme parameters. Understanding how they interact can help fine-tune the appearance and readability of your plots.\n", "\n", "- `plot_margin`\n", " adds outer space around the entire plot, including titles, captions, legends, and the plotting panel.\n", "\n", "- `plot_title: margin`, `plot_subtitle: margin`, `plot_caption: margin`, `axis_title_x: margin`, `axis_title_y: margin`\n", " control the spacing around the corresponding textual elements. These are passed via the `margin` argument to `element_text()`.\n", "\n", "- `axis_text_spacing_x`, `axis_text_spacing_y`\n", " define the spacing between axis ticks and their associated labels.\n", "\n", "- `panel_inset`\n", " adds internal padding between the plotting panel and the axes, shrinking the effective plotting area.\n", "\n", "- `plot_inset`\n", " adds padding inside the plot area (including the plot panel, axes, and axis labels) and other textual elements.\n", "\n", "- `legend_box_spacing`\n", " controls the spacing between the legend section and the plot area.\n" ] }, { "cell_type": "code", "execution_count": 1, "id": "96d0b1fa-5b18-47e3-b40f-b36d95f52121", "metadata": { "ExecuteTime": { "end_time": "2025-07-13T22:15:32.291941Z", "start_time": "2025-07-13T22:15:32.257088Z" } }, "outputs": [], "source": [ "import numpy as np\n", "from lets_plot import *" ] }, { "cell_type": "code", "execution_count": 2, "id": "3391aab4-81d4-452d-ab3a-6d0171570dd3", "metadata": { "ExecuteTime": { "end_time": "2025-07-13T22:15:32.314947Z", "start_time": "2025-07-13T22:15:32.298547Z" } }, "outputs": [ { "data": { "text/html": [ "\n", "
\n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "LetsPlot.setup_html()" ] }, { "cell_type": "code", "execution_count": 3, "id": "655da794-a561-450b-867a-d854349932c8", "metadata": { "ExecuteTime": { "end_time": "2025-07-13T22:15:32.582769Z", "start_time": "2025-07-13T22:15:32.574523Z" } }, "outputs": [], "source": [ "np.random.seed(42)\n", "\n", "x = list(range(210, 1000, 97))\n", "\n", "# Base rate increases with x (e.g., linear growth for lambda)\n", "lambdas = [5 + (xi - 210) / 100 for xi in x]\n", "\n", "y = [np.random.poisson(lam) * 30 + 90 for lam in lambdas]\n", "\n", "data = {'x': x, 'y': y}" ] }, { "cell_type": "code", "execution_count": 4, "id": "82918537-8f32-4580-961d-c3ef9179b893", "metadata": { "ExecuteTime": { "end_time": "2025-07-13T22:15:32.601768Z", "start_time": "2025-07-13T22:15:32.595180Z" } }, "outputs": [], "source": [ "SCALE_FACTOR = 2\n", "PAD = 11" ] }, { "cell_type": "code", "execution_count": 5, "id": "b62c87c5-01d4-438a-ba58-5b82254c53c1", "metadata": { "ExecuteTime": { "end_time": "2025-07-13T22:15:32.620903Z", "start_time": "2025-07-13T22:15:32.614613Z" } }, "outputs": [], "source": [ "def labeled_rect(xmin, xmax, ymin, ymax,\n", " inner_text='', border_text='',\n", " pad=PAD,\n", " **kwargs):\n", " xmin_s = xmin * SCALE_FACTOR + pad\n", " xmax_s = xmax * SCALE_FACTOR - pad\n", " ymin_s = ymin * SCALE_FACTOR + pad\n", " ymax_s = ymax * SCALE_FACTOR - pad\n", "\n", " is_horizontal = (xmax - xmin > (ymax - ymin) / 2)\n", "\n", " rect_layer = geom_rect(\n", " xmin=xmin_s, xmax=xmax_s, ymin=ymin_s, ymax=ymax_s, size=pad - 3,\n", " **kwargs\n", " )\n", "\n", " # Inner text: centered\n", " x_center = (xmin_s + xmax_s) / 2\n", " y_center = (ymin_s + ymax_s) / 2\n", " inner_layer = geom_text(\n", " x=x_center, y=y_center, label=inner_text,\n", " angle=0 if is_horizontal else 90,\n", " color='darkgray'\n", " )\n", "\n", " # Border text: near top-right (horizontal) or top-left (vertical)\n", " if is_horizontal:\n", " x_border = xmax_s\n", " y_border = ymin_s + pad / 2 - 1\n", " angle = 0\n", " vjust = 0\n", " else: # vertical\n", " x_border = xmin_s - pad / 2 - 5\n", " y_border = ymin_s\n", " angle = 90\n", " vjust = 1\n", "\n", " border_layer = geom_text(\n", " x=x_border, y=y_border, label=border_text,\n", " angle=angle, hjust=1, vjust=vjust,\n", " family='Courier',\n", " color='black'\n", " )\n", "\n", " return rect_layer + inner_layer + border_layer" ] }, { "cell_type": "code", "execution_count": 6, "id": "4dc5d4ae-6aee-41ad-8e83-21344b575e10", "metadata": { "ExecuteTime": { "end_time": "2025-07-13T22:15:32.636068Z", "start_time": "2025-07-13T22:15:32.629649Z" } }, "outputs": [], "source": [ "def annotation_arrow(x, y, xend, yend, label, hjust):\n", " x_s = x * SCALE_FACTOR\n", " y_s = y * SCALE_FACTOR\n", " xend_s = xend * SCALE_FACTOR\n", " yend_s = yend * SCALE_FACTOR\n", " with_arrow = arrow(length=8, ends='last', type='open', angle=20)\n", " label_x = x_s - 16\n", " label_y = y_s + 8\n", " if hjust == 1:\n", " label_x = x_s + 24\n", " label_y = y_s - 10\n", "\n", " return geom_segment(x=x_s, y=y_s, xend=xend_s, yend=yend_s, arrow=with_arrow) + \\\n", " geom_text(x=label_x, y=label_y, label=label, hjust=hjust, family='Courier', color='black')" ] }, { "cell_type": "code", "execution_count": 7, "id": "92c7f5ca-98e4-4724-b6bf-099e275faf84", "metadata": { "ExecuteTime": { "end_time": "2025-07-13T22:15:32.653455Z", "start_time": "2025-07-13T22:15:32.647955Z" } }, "outputs": [], "source": [ "def x_ticks(data, y_base=608, tick_length=8):\n", " ticks = {\n", " 'x': data['x'],\n", " 'xend': data['x'],\n", " 'y': [y_base] * len(data['x']),\n", " 'yend': [y_base + tick_length] * len(data['x']),\n", " }\n", " return geom_segment(aes(x='x', y='y', xend='xend', yend='yend'), data=ticks, color='gray50', size=1)\n", "\n", "\n", "def y_ticks(ymin=208, ymax=574, n_ticks=6, x_base=168, tick_length=8):\n", " y_ticks = np.linspace(ymin, ymax, n_ticks)\n", "\n", " ticks = {\n", " 'y': y_ticks,\n", " 'yend': y_ticks,\n", " 'x': [x_base] * n_ticks,\n", " 'xend': [x_base + tick_length] * n_ticks,\n", " }\n", "\n", " return geom_segment(aes(x='x', y='y', xend='xend', yend='yend'), data=ticks, color='gray50', size=1)" ] }, { "cell_type": "code", "execution_count": 8, "id": "5a65a3de-8de1-4615-8b0c-e7382c12ace0", "metadata": { "ExecuteTime": { "end_time": "2025-07-13T22:15:32.697080Z", "start_time": "2025-07-13T22:15:32.664743Z" } }, "outputs": [], "source": [ "COORDS = {\n", " 'PLOT_XMIN': 0, 'PLOT_XMAX': 620, 'PLOT_YMIN': 0, 'PLOT_YMAX': 420,\n", " 'PANEL_XMIN': 88, 'PANEL_XMAX': 506, 'PANEL_YMIN': 90, 'PANEL_YMAX': 304,\n", " 'TITLE_YMIN': 11, 'TITLE_YMAX': 44.5,\n", " 'SUBTITLE_YMIN': 44, 'SUBTITLE_YMAX': 78.5,\n", " 'X_TITLE_YMIN': 346.5, 'X_TITLE_YMAX': 378,\n", " 'Y_TITLE_XMIN': 11, 'Y_TITLE_XMAX': 44.5,\n", " 'X_TEXT_XMIN': 98, 'X_TEXT_XMAX': 498, 'X_TEXT_YMIN': 320, 'X_TEXT_YMAX': 334,\n", " 'Y_TEXT_XMIN': 56, 'Y_TEXT_XMAX': 72, 'Y_TEXT_YMIN': 98, 'Y_TEXT_YMAX': 294,\n", " 'PLOT_INSET_XMIN': 44.5, 'PLOT_INSET_XMAX': 517, 'PLOT_INSET_YMIN': 79, 'PLOT_INSET_YMAX': 346,\n", " 'CAPTION_YMIN': 378, 'CAPTION_YMAX': 410,\n", " 'LEGEND_XMIN': 532, 'LEGEND_XMAX': 610, 'LEGEND_YMIN': 137, 'LEGEND_YMAX': 254,\n", " 'LEGEND_SPACING_XMIN': 518, 'LEGEND_SPACING_XMAX': 532,\n", " 'FRAME_XMIN': 86.5, 'FRAME_XMAX': 509.5, 'FRAME_YMIN': 86, 'FRAME_YMAX': 305.5,\n", "}\n", "\n", "plotting_area = labeled_rect(xmin=COORDS['PLOT_XMIN'], xmax=COORDS['PLOT_XMAX'],\n", " ymin=COORDS['PLOT_YMIN'], ymax=COORDS['PLOT_YMAX'],\n", " inner_text='', border_text='',\n", " pad=1, fill='white', color='gold', alpha=0.0)\n", "\n", "plot_margin = labeled_rect(xmin=COORDS['PLOT_XMIN'], xmax=COORDS['PLOT_XMAX'],\n", " ymin=COORDS['PLOT_YMIN'], ymax=COORDS['PLOT_YMAX'],\n", " inner_text='', border_text='plot_margin',\n", " fill='white', color='lemon_chiffon', alpha=0.9)\n", "\n", "title_area = labeled_rect(xmin=COORDS['PANEL_XMIN'], xmax=COORDS['PANEL_XMAX'],\n", " ymin=COORDS['TITLE_YMIN'], ymax=COORDS['TITLE_YMAX'],\n", " inner_text='TITLE', border_text='plot_title: margin',\n", " fill='light_blue', color='light_blue', alpha=0.3)\n", "\n", "subtitle_area = labeled_rect(xmin=COORDS['PANEL_XMIN'], xmax=COORDS['PANEL_XMAX'],\n", " ymin=COORDS['SUBTITLE_YMIN'], ymax=COORDS['SUBTITLE_YMAX'],\n", " inner_text='SUBTITLE', border_text='plot_subtitle: margin',\n", " fill='light_green', color='light_green', alpha=0.3)\n", "\n", "y_title_area = labeled_rect(xmin=COORDS['Y_TITLE_XMIN'], xmax=COORDS['Y_TITLE_XMAX'],\n", " ymin=COORDS['PANEL_YMIN'], ymax=COORDS['PANEL_YMAX'],\n", " inner_text='Y-AXIS TITLE', border_text='axis_title_y: margin',\n", " fill='peach_puff', color='peach_puff', alpha=0.2)\n", "\n", "x_title_area = labeled_rect(xmin=COORDS['PANEL_XMIN'], xmax=COORDS['PANEL_XMAX'],\n", " ymin=COORDS['X_TITLE_YMIN'], ymax=COORDS['X_TITLE_YMAX'],\n", " inner_text='X-AXIS TITLE', border_text='axis_title_x: margin',\n", " fill='peach_puff', color='peach_puff', alpha=0.2)\n", "\n", "panel_area = labeled_rect(xmin=COORDS['PANEL_XMIN'], xmax=COORDS['PANEL_XMAX'],\n", " ymin=COORDS['PANEL_YMIN'], ymax=COORDS['PANEL_YMAX'],\n", " inner_text='PLOT\\nPANEL', border_text='panel_inset',\n", " fill='gray', color='light_gray', alpha=0.5)\n", "\n", "y_text_area = labeled_rect(xmin=COORDS['Y_TEXT_XMIN'], xmax=COORDS['Y_TEXT_XMAX'],\n", " ymin=COORDS['Y_TEXT_YMIN'], ymax=COORDS['Y_TEXT_YMAX'],\n", " inner_text='y-axis labels', border_text='',\n", " pad=0, fill='pink', color='light_pink', alpha=0.3)\n", "\n", "y_text_area2 = labeled_rect(xmin=COORDS['Y_TEXT_XMAX'], xmax=COORDS['Y_TEXT_XMAX'] + PAD + 1,\n", " ymin=COORDS['Y_TEXT_YMIN'], ymax=COORDS['Y_TEXT_YMAX'],\n", " inner_text='', border_text='axis_text_spacing_y',\n", " fill='pink', color='light_pink', alpha=0.3)\n", "\n", "x_text_area = labeled_rect(xmin=COORDS['X_TEXT_XMIN'], xmax=COORDS['X_TEXT_XMAX'],\n", " ymin=COORDS['X_TEXT_YMIN'], ymax=COORDS['X_TEXT_YMAX'],\n", " inner_text='x-axis labels', border_text='',\n", " pad=0, fill='pink', color='light_pink', alpha=0.3)\n", "\n", "x_text_area2 = labeled_rect(xmin=COORDS['X_TEXT_XMIN'], xmax=COORDS['X_TEXT_XMAX'],\n", " ymin=COORDS['X_TEXT_YMIN'] - PAD - 1, ymax=COORDS['X_TEXT_YMAX'] - PAD - 4,\n", " inner_text='', border_text='axis_text_spacing_x',\n", " fill='pink', color='light_pink', alpha=0.3)\n", "\n", "caption_area = labeled_rect(xmin=COORDS['PANEL_XMIN'], xmax=COORDS['PANEL_XMAX'],\n", " ymin=COORDS['CAPTION_YMIN'], ymax=COORDS['CAPTION_YMAX'],\n", " inner_text='CAPTION', border_text='plot_caption: margin',\n", " fill='sky_blue', color='sky_blue', alpha=0.3)\n", "\n", "legend_area = labeled_rect(xmin=COORDS['LEGEND_XMIN'], xmax=COORDS['LEGEND_XMAX'],\n", " ymin=COORDS['LEGEND_YMIN'], ymax=COORDS['LEGEND_YMAX'],\n", " pad=1, inner_text='LEGEND', border_text='',\n", " fill='chocolate', color='chocolate', alpha=0.1)\n", "\n", "legend_spacing = labeled_rect(xmin=COORDS['LEGEND_SPACING_XMIN'], xmax=COORDS['LEGEND_SPACING_XMAX'],\n", " ymin=COORDS['LEGEND_YMIN'], ymax=COORDS['LEGEND_YMAX'],\n", " pad=11, inner_text='', border_text='legend_box_spacing',\n", " fill='gray93', color='gray93')\n", "\n", "plot_inset_area = labeled_rect(xmin=COORDS['PLOT_INSET_XMIN'], xmax=COORDS['PLOT_INSET_XMAX'],\n", " ymin=COORDS['PLOT_INSET_YMIN'], ymax=COORDS['PLOT_INSET_YMAX'],\n", " inner_text='', border_text='plot_inset',\n", " fill='white', color='plum', alpha=0.5)" ] }, { "cell_type": "code", "execution_count": 9, "id": "78514ff8-a4bb-43de-bb39-e8fcc47d6db9", "metadata": { "ExecuteTime": { "end_time": "2025-07-13T22:15:32.787724Z", "start_time": "2025-07-13T22:15:32.709087Z" } }, "outputs": [ { "data": { "text/html": [ " \n", " " ], "text/plain": [ "