source/kotlin_examples/cookbook/numeric_data_on_discrete_scale.ipynb (648 lines of code) (raw):

{ "cells": [ { "cell_type": "markdown", "id": "b0cb8f8e-adbd-4122-99ed-08ffcf793d12", "metadata": {}, "source": [ "# Combining Discrete and Continuous Layers\n", "\n", "This notebook demonstrates how to position continuous elements like background bands (`geomBand`) and annotations (`geomText`) relative to discrete elements like bars.\n", "\n", "When positioning continuous elements, keep in mind numeric equivalents of the discrete positions: in this example `0.0` for \"Outback\" through `7.0` for \"Pacer\"." ] }, { "cell_type": "code", "execution_count": 1, "id": "2c9f4f70-9667-42ae-93a3-013dafab2ea9", "metadata": { "execution": { "iopub.execute_input": "2025-12-03T16:02:02.219270Z", "iopub.status.busy": "2025-12-03T16:02:02.217666Z", "iopub.status.idle": "2025-12-03T16:02:04.785987Z", "shell.execute_reply": "2025-12-03T16:02:04.785824Z" } }, "outputs": [ { "data": { "text/html": [ " <div id=\"kotlin_out_0\"></div>\n", " <script type=\"text/javascript\">\n", " if(!window.kotlinQueues) {\n", " window.kotlinQueues = {};\n", " }\n", " if(!window.kotlinQueues[\"DataFrame\"]) {\n", " var resQueue = [];\n", " window.kotlinQueues[\"DataFrame\"] = resQueue;\n", " window[\"call_DataFrame\"] = function(f) {\n", " resQueue.push(f);\n", " }\n", " }\n", " (function (){\n", " var modifiers = [(function(script) {\n", " script.src = \"https://cdn.jsdelivr.net/gh/Kotlin/dataframe@3db46ccccaa1291c0627307d64133317f545e6ae/core/src/main/resources/init.js\"\n", " script.type = \"text/javascript\";\n", "})];\n", " var e = document.getElementById(\"kotlin_out_0\");\n", " modifiers.forEach(function (gen) {\n", " var script = document.createElement(\"script\");\n", " gen(script)\n", " script.addEventListener(\"load\", function() {\n", " window[\"call_DataFrame\"] = function(f) {f();};\n", " window.kotlinQueues[\"DataFrame\"].forEach(function(f) {f();});\n", " window.kotlinQueues[\"DataFrame\"] = [];\n", " }, false);\n", " script.addEventListener(\"error\", function() {\n", " window[\"call_DataFrame\"] = function(f) {};\n", " window.kotlinQueues[\"DataFrame\"] = [];\n", " var div = document.createElement(\"div\");\n", " div.style.color = 'darkred';\n", " div.textContent = 'Error loading resource DataFrame';\n", " document.getElementById(\"kotlin_out_0\").appendChild(div);\n", " }, false);\n", " \n", " e.appendChild(script);\n", " });\n", " })();\n", " </script>" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ " <style>\n", " :root {\n", " --background: #fff;\n", " --background-odd: #f5f5f5;\n", " --background-hover: #d9edfd;\n", " --header-text-color: #474747;\n", " --text-color: #848484;\n", " --text-color-dark: #000;\n", " --text-color-medium: #737373;\n", " --text-color-pale: #b3b3b3;\n", " --inner-border-color: #aaa;\n", " --bold-border-color: #000;\n", " --link-color: #296eaa;\n", " --link-color-pale: #296eaa;\n", " --link-hover: #1a466c;\n", "}\n", "\n", ":root[theme=\"dark\"], :root [data-jp-theme-light=\"false\"], .dataframe_dark{\n", " --background: #303030;\n", " --background-odd: #3c3c3c;\n", " --background-hover: #464646;\n", " --header-text-color: #dddddd;\n", " --text-color: #b3b3b3;\n", " --text-color-dark: #dddddd;\n", " --text-color-medium: #b2b2b2;\n", " --text-color-pale: #737373;\n", " --inner-border-color: #707070;\n", " --bold-border-color: #777777;\n", " --link-color: #008dc0;\n", " --link-color-pale: #97e1fb;\n", " --link-hover: #00688e;\n", "}\n", "\n", "p.dataframe_description {\n", " color: var(--text-color-dark);\n", "}\n", "\n", "table.dataframe {\n", " font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n", " font-size: 12px;\n", " background-color: var(--background);\n", " color: var(--text-color-dark);\n", " border: none;\n", " border-collapse: collapse;\n", "}\n", "\n", "table.dataframe th, td {\n", " padding: 6px;\n", " border: 1px solid transparent;\n", " text-align: left;\n", "}\n", "\n", "table.dataframe th {\n", " background-color: var(--background);\n", " color: var(--header-text-color);\n", "}\n", "\n", "table.dataframe td {\n", " vertical-align: top;\n", " white-space: nowrap;\n", "}\n", "\n", "table.dataframe th.bottomBorder {\n", " border-bottom-color: var(--bold-border-color);\n", "}\n", "\n", "table.dataframe tbody > tr:nth-child(odd) {\n", " background: var(--background-odd);\n", "}\n", "\n", "table.dataframe tbody > tr:nth-child(even) {\n", " background: var(--background);\n", "}\n", "\n", "table.dataframe tbody > tr:hover {\n", " background: var(--background-hover);\n", "}\n", "\n", "table.dataframe a {\n", " cursor: pointer;\n", " color: var(--link-color);\n", " text-decoration: none;\n", "}\n", "\n", "table.dataframe tr:hover > td a {\n", " color: var(--link-color-pale);\n", "}\n", "\n", "table.dataframe a:hover {\n", " color: var(--link-hover);\n", " text-decoration: underline;\n", "}\n", "\n", "table.dataframe img {\n", " max-width: fit-content;\n", "}\n", "\n", "table.dataframe th.complex {\n", " background-color: var(--background);\n", " border: 1px solid var(--background);\n", "}\n", "\n", "table.dataframe .leftBorder {\n", " border-left-color: var(--inner-border-color);\n", "}\n", "\n", "table.dataframe .rightBorder {\n", " border-right-color: var(--inner-border-color);\n", "}\n", "\n", "table.dataframe .rightAlign {\n", " text-align: right;\n", "}\n", "\n", "table.dataframe .expanderSvg {\n", " width: 8px;\n", " height: 8px;\n", " margin-right: 3px;\n", "}\n", "\n", "table.dataframe .expander {\n", " display: flex;\n", " align-items: center;\n", "}\n", "\n", "/* formatting */\n", "\n", "table.dataframe .null {\n", " color: var(--text-color-pale);\n", "}\n", "\n", "table.dataframe .structural {\n", " color: var(--text-color-medium);\n", " font-weight: bold;\n", "}\n", "\n", "table.dataframe .dataFrameCaption {\n", " font-weight: bold;\n", "}\n", "\n", "table.dataframe .numbers {\n", " color: var(--text-color-dark);\n", "}\n", "\n", "table.dataframe td:hover .formatted .structural, .null {\n", " color: var(--text-color-dark);\n", "}\n", "\n", "table.dataframe tr:hover .formatted .structural, .null {\n", " color: var(--text-color-dark);\n", "}\n", "\n", "\n", " </style>" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ " <div id=\"75qISu\"></div>\n", " <script type=\"text/javascript\" data-lets-plot-script=\"library\">\n", " if(!window.letsPlotCallQueue) {\n", " window.letsPlotCallQueue = [];\n", " }; \n", " window.letsPlotCall = function(f) {\n", " window.letsPlotCallQueue.push(f);\n", " };\n", " (function() {\n", " var script = document.createElement(\"script\");\n", " script.type = \"text/javascript\";\n", " script.src = \"https://cdn.jsdelivr.net/gh/JetBrains/lets-plot@v4.8.1/js-package/distr/lets-plot.min.js\";\n", " script.onload = function() {\n", " window.letsPlotCall = function(f) {f();};\n", " window.letsPlotCallQueue.forEach(function(f) {f();});\n", " window.letsPlotCallQueue = [];\n", " \n", " \n", " };\n", " script.onerror = function(event) {\n", " window.letsPlotCall = function(f) {};\n", " window.letsPlotCallQueue = [];\n", " var div = document.createElement(\"div\");\n", " div.style.color = 'darkred';\n", " div.textContent = 'Error loading Lets-Plot JS';\n", " document.getElementById(\"75qISu\").appendChild(div);\n", " };\n", " var e = document.getElementById(\"75qISu\");\n", " e.appendChild(script);\n", " })();\n", " </script>" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ " <div id=\"kotlin_out_1\"></div>\n", " <script type=\"text/javascript\">\n", " if(!window.kotlinQueues) {\n", " window.kotlinQueues = {};\n", " }\n", " if(!window.kotlinQueues[\"letsPlotJs\"]) {\n", " var resQueue = [];\n", " window.kotlinQueues[\"letsPlotJs\"] = resQueue;\n", " window[\"call_letsPlotJs\"] = function(f) {\n", " resQueue.push(f);\n", " }\n", " }\n", " (function (){\n", " var modifiers = [(function(script) {\n", " script.src = \"https://cdn.jsdelivr.net/gh/JetBrains/lets-plot@v4.8.1/js-package/distr/lets-plot.min.js\"\n", " script.type = \"text/javascript\";\n", "})];\n", " var e = document.getElementById(\"kotlin_out_1\");\n", " modifiers.forEach(function (gen) {\n", " var script = document.createElement(\"script\");\n", " gen(script)\n", " script.addEventListener(\"load\", function() {\n", " window[\"call_letsPlotJs\"] = function(f) {f();};\n", " window.kotlinQueues[\"letsPlotJs\"].forEach(function(f) {f();});\n", " window.kotlinQueues[\"letsPlotJs\"] = [];\n", " }, false);\n", " script.addEventListener(\"error\", function() {\n", " window[\"call_letsPlotJs\"] = function(f) {};\n", " window.kotlinQueues[\"letsPlotJs\"] = [];\n", " var div = document.createElement(\"div\");\n", " div.style.color = 'darkred';\n", " div.textContent = 'Error loading resource letsPlotJs';\n", " document.getElementById(\"kotlin_out_1\").appendChild(div);\n", " }, false);\n", " \n", " e.appendChild(script);\n", " });\n", " })();\n", " </script>" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%useLatestDescriptors\n", "%use dataframe\n", "%use lets-plot" ] }, { "cell_type": "code", "execution_count": 2, "id": "010e706b-afcd-4e03-8c80-383747b69353", "metadata": { "execution": { "iopub.execute_input": "2025-12-03T16:02:04.787663Z", "iopub.status.busy": "2025-12-03T16:02:04.787435Z", "iopub.status.idle": "2025-12-03T16:02:04.813920Z", "shell.execute_reply": "2025-12-03T16:02:04.813996Z" } }, "outputs": [ { "data": { "text/plain": [ "Lets-Plot Kotlin API v.4.12.0. Frontend: Notebook with dynamically loaded JS. Lets-Plot JS v.4.8.1.\n", "Outputs: Web (HTML+JS), Kotlin Notebook (Swing), Static SVG (hidden)" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "LetsPlot.getInfo()" ] }, { "cell_type": "code", "execution_count": 3, "id": "7ad25b3a-0b53-4e6c-8b2b-ce46169ec5bb", "metadata": { "execution": { "iopub.execute_input": "2025-12-03T16:02:04.815572Z", "iopub.status.busy": "2025-12-03T16:02:04.815344Z", "iopub.status.idle": "2025-12-03T16:02:05.001987Z", "shell.execute_reply": "2025-12-03T16:02:05.001771Z" } }, "outputs": [], "source": [ "import kotlin.random.Random\n", "\n", "val rand = Random(121)\n", "val cars = mapOf(\n", " \"Models\" to listOf(\"Outback\", \"Impresa\", \"BRZ\", \"Jetta\", \"Passat\", \"Matador\", \"Rambler\", \"Pacer\"),\n", " \"Val\" to List(8) { rand.nextDouble() * 100 }\n", ")\n", "\n", "// Data to use in `geomBand` and `geomText` layers\n", "\n", "val carsBand = mapOf(\n", " \"Brand\" to listOf(\"Subaru\", \"Volkswagen\", \"AMC\"),\n", " \"pos_minx\" to listOf(-0.5, 2.5, 4.5),\n", " \"pos_maxx\" to listOf(2.5, 4.5, 7.5),\n", " \"M\" to listOf(\"#41DC8E\", \"#E0FFFF\", \"#90D5FF\")\n", ")" ] }, { "cell_type": "code", "execution_count": 4, "id": "189eb2df-56d8-4cae-ab2f-19c2c60e7719", "metadata": { "execution": { "iopub.execute_input": "2025-12-03T16:02:05.004678Z", "iopub.status.busy": "2025-12-03T16:02:05.003989Z", "iopub.status.idle": "2025-12-03T16:02:05.254609Z", "shell.execute_reply": "2025-12-03T16:02:05.254351Z" } }, "outputs": [ { "data": { "text/html": [ " <div id=\"lWsuoG\" ></div>\n", " <script type=\"text/javascript\" data-lets-plot-script=\"plot\">\n", " \n", " (function() {\n", " // ----------\n", " \n", " const forceImmediateRender = false;\n", " const responsive = false;\n", " \n", " let sizing = {\n", " width_mode: \"MIN\",\n", " height_mode: \"SCALED\",\n", " width: null, \n", " height: null \n", " };\n", " \n", " const preferredWidth = document.body.dataset.letsPlotPreferredWidth;\n", " if (preferredWidth !== undefined) {\n", " sizing = {\n", " width_mode: 'FIXED',\n", " height_mode: 'SCALED',\n", " width: parseFloat(preferredWidth)\n", " };\n", " }\n", " \n", " const containerDiv = document.getElementById(\"lWsuoG\");\n", " let fig = null;\n", " \n", " function renderPlot() {\n", " if (fig === null) {\n", " const plotSpec = {\n", "\"mapping\":{\n", "\"x\":\"Models\",\n", "\"weight\":\"Val\"\n", "},\n", "\"data\":{\n", "},\n", "\"ggsize\":{\n", "\"width\":700.0,\n", "\"height\":400.0\n", "},\n", "\"kind\":\"plot\",\n", "\"scales\":[{\n", "\"aesthetic\":\"fill\",\n", "\"values\":[\"#41DC8E\",\"#E0FFFF\",\"#90D5FF\"]\n", "},{\n", "\"aesthetic\":\"color\",\n", "\"values\":[\"#41DC8E\",\"#E0FFFF\",\"#90D5FF\"]\n", "}],\n", "\"layers\":[{\n", "\"mapping\":{\n", "\"xmin\":\"pos_minx\",\n", "\"xmax\":\"pos_maxx\",\n", "\"color\":\"Brand\",\n", "\"fill\":\"Brand\"\n", "},\n", "\"stat\":\"identity\",\n", "\"data\":{\n", "\"Brand\":[\"Subaru\",\"Volkswagen\",\"AMC\"],\n", "\"pos_minx\":[-0.5,2.5,4.5],\n", "\"pos_maxx\":[2.5,4.5,7.5]\n", "},\n", "\"alpha\":0.5,\n", "\"position\":\"identity\",\n", "\"geom\":\"band\",\n", "\"data_meta\":{\n", "\"series_annotations\":[{\n", "\"type\":\"str\",\n", "\"column\":\"Brand\"\n", "},{\n", "\"type\":\"float\",\n", "\"column\":\"pos_minx\"\n", "},{\n", "\"type\":\"float\",\n", "\"column\":\"pos_maxx\"\n", "},{\n", "\"type\":\"str\",\n", "\"column\":\"M\"\n", "}]\n", "},\n", "\"tooltips\":\"none\"\n", "},{\n", "\"nudge_x\":0.1,\n", "\"mapping\":{\n", "\"x\":\"pos_minx\",\n", "\"label\":\"Brand\"\n", "},\n", "\"stat\":\"identity\",\n", "\"data\":{\n", "\"Brand\":[\"Subaru\",\"Volkswagen\",\"AMC\"],\n", "\"pos_minx\":[-0.5,2.5,4.5]\n", "},\n", "\"size\":8.0,\n", "\"y\":100.0,\n", "\"position\":\"identity\",\n", "\"geom\":\"text\",\n", "\"data_meta\":{\n", "\"series_annotations\":[{\n", "\"type\":\"str\",\n", "\"column\":\"Brand\"\n", "},{\n", "\"type\":\"float\",\n", "\"column\":\"pos_minx\"\n", "},{\n", "\"type\":\"float\",\n", "\"column\":\"pos_maxx\"\n", "},{\n", "\"type\":\"str\",\n", "\"column\":\"M\"\n", "}]\n", "},\n", "\"fontface\":\"bold\",\n", "\"hjust\":\"left\"\n", "},{\n", "\"mapping\":{\n", "},\n", "\"stat\":\"count\",\n", "\"position\":\"stack\",\n", "\"geom\":\"bar\",\n", "\"data\":{\n", "\"..count..\":[30.982135971584846,81.94197297717082,62.056013456715796,74.48653022993865,23.836577341202492,98.04480352819152,55.58493152593764,42.22334702028074],\n", "\"Models\":[\"Outback\",\"Impresa\",\"BRZ\",\"Jetta\",\"Passat\",\"Matador\",\"Rambler\",\"Pacer\"]\n", "}\n", "}],\n", "\"theme\":{\n", "\"axis_title_x\":{\n", "\"blank\":true\n", "},\n", "\"legend_position\":\"none\"\n", "},\n", "\"data_meta\":{\n", "\"series_annotations\":[{\n", "\"type\":\"str\",\n", "\"column\":\"Models\"\n", "},{\n", "\"type\":\"float\",\n", "\"column\":\"Val\"\n", "}]\n", "},\n", "\"spec_id\":\"1\"\n", "};\n", " window.letsPlotCall(function() { fig = LetsPlot.buildPlotFromProcessedSpecs(plotSpec, containerDiv, sizing); });\n", " } else {\n", " fig.updateView({});\n", " }\n", " }\n", " \n", " const renderImmediately = \n", " forceImmediateRender || (\n", " sizing.width_mode === 'FIXED' && \n", " (sizing.height_mode === 'FIXED' || sizing.height_mode === 'SCALED')\n", " );\n", " \n", " if (renderImmediately) {\n", " renderPlot();\n", " }\n", " \n", " if (!renderImmediately || responsive) {\n", " // Set up observer for initial sizing or continuous monitoring\n", " var observer = new ResizeObserver(function(entries) {\n", " for (let entry of entries) {\n", " if (entry.contentBoxSize && \n", " entry.contentBoxSize[0].inlineSize > 0) {\n", " if (!responsive && observer) {\n", " observer.disconnect();\n", " observer = null;\n", " }\n", " renderPlot();\n", " if (!responsive) {\n", " break;\n", " }\n", " }\n", " }\n", " });\n", " \n", " observer.observe(containerDiv);\n", " }\n", " \n", " // ----------\n", " })();\n", " \n", " </script>" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "val plot = letsPlot(cars) {\n", " x = \"Models\"\n", " weight = \"Val\"\n", " } + geomBand(\n", " data = carsBand,\n", " alpha = 0.5,\n", " tooltips = tooltipsNone\n", " ) {\n", " xmin = \"pos_minx\"\n", " xmax = \"pos_maxx\"\n", " fill = \"Brand\"\n", " color = \"Brand\"\n", " } + geomText(\n", " data = carsBand,\n", " y = 100.0,\n", " size = 8.0,\n", " fontface = \"bold\",\n", " hjust = \"left\",\n", " nudgeX = 0.1\n", " ) {\n", " x = \"pos_minx\"\n", " label = \"Brand\"\n", " } + geomBar() +\n", " scaleFillManual(values = carsBand[\"M\"]!!) +\n", " scaleColorManual(values = carsBand[\"M\"]!!) +\n", " theme(\n", " axisTitleX = elementBlank()\n", " ).legendPositionNone() +\n", " ggsize(700, 400)\n", "\n", "plot.show()" ] } ], "metadata": { "kernelspec": { "display_name": "Kotlin", "language": "kotlin", "name": "kotlin" }, "language_info": { "codemirror_mode": "text/x-kotlin", "file_extension": ".kt", "mimetype": "text/x-kotlin", "name": "kotlin", "nbconvert_exporter": "", "pygments_lexer": "kotlin", "version": "2.2.20-Beta2" } }, "nbformat": 4, "nbformat_minor": 5 }