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
}