{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "# Lets-Plot Usage Guide\n",
    "\n",
    "<a href=\"https://opensource.org/licenses/MIT\">\n",
    "<img src=\"https://img.shields.io/badge/License-MIT-yellow.svg\" alt=\"Couldn't load MIT license svg\"/>\n",
    "</a>\n",
    "\n",
    "\n",
    "- [Installation](#install)\n",
    "- [Understanding architecture](#implementation)\n",
    "- [Learning API](#api)\n",
    "- [Getting started](#gsg)\n",
    "\n",
    "\n",
    "**Lets-Plot** is an open-source plotting library for statistical data. It is implemented using the \n",
    "[Kotlin programming language](https://kotlinlang.org/) that has a multi-platform nature.\n",
    "That's why Lets-Plot provides the plotting functionality that \n",
    "is packaged as a JavaScript library, a JVM library, and a native Python extension.\n",
    "\n",
    "The design of the Lets-Plot library is heavily influenced by [ggplot2](https://ggplot2.tidyverse.org) library.\n",
    "\n",
    "<a name=\"Installation\" id=\"install\"></a>\n",
    "## Installation\n",
    "\n",
    "Library is distributed via [Maven Central](https://central.sonatype.com/artifact/org.jetbrains.lets-plot/lets-plot-kotlin).\n",
    "You can include it in your Kotlin or Java project using Maven or Gradle configuration files (see also [Developer guide](https://github.com/JetBrains/lets-plot-kotlin/blob/master/USAGE_BATIK_JFX_JS.md)),\n",
    "or include it in your Jupyter notebook script via `%use lets-plot` annotation (see [Kotlin kernel for IPython/Jupyter](https://github.com/Kotlin/kotlin-jupyter)).\n",
    "\n",
    "<a name=\"Implementation\" id=\"implementation\"></a>\n",
    "## Understanding Lets-Plot architecture\n",
    "In `lets-plot`, the **plot** is represented at least by one\n",
    "**layer**. It can be built based on the default dataset with the aesthetics mappings, set of scales, or additional \n",
    "features applied.\n",
    "\n",
    "The **Layer** is responsible for creating the objects painted on the ‘canvas’ and it contains the following elements:\n",
    "- **Data** - the set of data specified either once for all layers or on a per layer basis.\n",
    "One plot can combine multiple different datasets (one per layer).\n",
    "- **Aesthetic mapping** - describes how variables in the dataset are mapped to the visual properties of the layer, such as color, shape, size, or position.\n",
    "- **Geometric object** - a geometric object that represents a particular type of charts.\n",
    "- **Statistical transformation** - computes some kind of statistical summary on the raw input data. \n",
    "For example, `bin` statistics is used for histograms and `smooth` is used for regression lines. \n",
    "Most stats take additional parameters to specify details of the statistical transformation of data.\n",
    "- **Position adjustment** - a method used to compute the final coordinates of geometry. \n",
    "Used to build variants of the same `geom` object or to avoid overplotting.\n",
    "\n",
    "![layer diagram](images/layer-small.png)\n",
    "\n",
    "<a name=\"API\" id=\"api\"></a>\n",
    "## Learning API\n",
    "The typical code fragment that plots a Lets-Plot chart looks as follows:\n",
    "\n",
    "```\n",
    "import org.jetbrains.letsPlot.*\n",
    "import org.jetbrains.letsPlot.geom.*\n",
    "import org.jetbrains.letsPlot.stat.*\n",
    "\n",
    "p = letsPlot(<dataframe>) \n",
    "p + geom<ChartType>(stat=<stat>, position=<adjustment>) { <aesthetics mapping> }\n",
    "```\n",
    "\n",
    "### Geometric objects `geom`\n",
    "\n",
    "You can add a new geometric object (or plot layer) by creating it using the `geomXxx()` function and then adding this object to `ggplot`:\n",
    "\n",
    "```\n",
    "p = letsPlot(data=df)\n",
    "p + geomPoint()\n",
    "```\n",
    "\n",
    "See the [geom reference](https://lets-plot.org/kotlin/api-reference/-lets--plot--kotlin/org.jetbrains.letsPlot.geom/index.html) for more information about the supported\n",
    "geometric objects, their arguments, and default values.\n",
    "\n",
    "There is also a few `statXxx()` functions which also create a plot layer.\n",
    "Occasionally, it feels more naturally to use `statXxx()` instead of `geomXxx()` function to add a new plot layer.\n",
    "For example, you might prefer to use `statCount()` instead of `geomBar()`.\n",
    "\n",
    "See the [stat layer reference](https://lets-plot.org/kotlin/api-reference/-lets--plot--kotlin/org.jetbrains.letsPlot.stat/index.html) for more information about the supported\n",
    "stat plot-layer objects, their arguments, and default values.\n",
    "\n",
    "\n",
    "### Collections of plots\n",
    "With the [GGBunch()](https://lets-plot.org/kotlin/api-reference/-lets--plot--kotlin/org.jetbrains.letsPlot/-g-g-bunch/index.html) object, you can\n",
    "render a collection of plots.\n",
    "Use the `addPlot()` method to add a plot to the bunch and set an arbitrary location and size for plots inside the grid:\n",
    "\n",
    "```\n",
    "bunch = GGBunch()\n",
    "            .addPlot(plot1, 0, 0)\n",
    "            .addPlot(plot2, 0, 200)\n",
    "bunch.show()\n",
    "```\n",
    "\n",
    "See the [ggbunch.ipynb](https://nbviewer.org/github/JetBrains/lets-plot-docs/blob/master/source/kotlin_examples/cookbook/ggbunch.ipynb)\n",
    " example for more information.\n",
    "\n",
    "### Stat `stat`\n",
    "\n",
    "Add `stat` as an argument to `geomXxx()` function to define statistical data transformations:\n",
    "\n",
    "`geomPoint(stat=Stat.count())`\n",
    "\n",
    "Supported statistical transformations:\n",
    "\n",
    "- `identity`:  leave the data unchanged\n",
    "- `count`:  calculate the number of points with same x-axis coordinate\n",
    "- `bin`:  calculate the number of points falling in each of adjacent equally sized ranges along the x-axis\n",
    "- `bin2d`:  calculate the number of points falling in each of adjacent equal sized rectangles on the plot plane\n",
    "- `smooth`:  perform smoothing\n",
    "- `contour`, `contourFilled`, : calculate contours of 3D data\n",
    "- `boxplot`: calculate components of a box plot.\n",
    "- `density`, `density2D`, `density2DFilled`: perform a kernel density estimation for 1D and 2D data\n",
    "\n",
    "See the [stat reference](https://lets-plot.org/kotlin/api-reference/-lets--plot--kotlin/org.jetbrains.letsPlot/-stat/index.html) for more information about the supported\n",
    "stat objects, their arguments, and default values.\n",
    "\n",
    "\n",
    "### Aesthetic mappings `mapping`\n",
    "With mappings, you can define how variables in dataset are mapped to the visual elements of the chart.\n",
    "Add the `{x=< >; y=< >; ...}` closure to `geom`, where:\n",
    "- `x`: the dataframe column to map to the x axis. \n",
    "- `y`: the dataframe column to map to the y axis.\n",
    "- `...`: other visual properties of the chart, such as color, shape, size, or position.\n",
    "\n",
    "`geom_point() {x = \"cty\"; y = \"hwy\"; color=\"cyl\"}`\n",
    "\n",
    "### Position adjustment `position`\n",
    "\n",
    "All layers have a position adjustment that computes the final coordinates of geometry.\n",
    "Position adjustment is used to build variances of the same plots and resolve overlapping.\n",
    "Override the default settings by using the `position` argument in the `geom` functions:\n",
    "\n",
    "`geomBar(position=positionFill)`\n",
    "\n",
    "or\n",
    "\n",
    "`geomBar(position=positionDodge(width=1.01))`\n",
    "\n",
    "Available adjustments:\n",
    "- `dodge`\n",
    "- `jitter`\n",
    "- `jitterdodge`\n",
    "- `nudge`\n",
    "- `identity`\n",
    "- `fill`\n",
    "- `stack`\n",
    "\n",
    "See [position functions reference](https://lets-plot.org/kotlin/api-reference/-lets--plot--kotlin/org.jetbrains.letsPlot.pos/index.html)\n",
    "for more information about position adjustments.\n",
    "\n",
    "### Features affecting the entire plot\n",
    "\n",
    "#### Scales\n",
    "\n",
    "Enables choosing a reasonable scale for each mapped variable depending on the variable attributes. Override default scales to tweak\n",
    "details like the axis labels or legend keys, or to use a completely different translation from data to aesthetic.\n",
    "For example, to override the fill color on the histogram:\n",
    "\n",
    "`p + geomHistogram() + scaleFillContinuous(\"red\", \"green\")`\n",
    "\n",
    "See the list of the available `scale` methods in the [scale reference](https://lets-plot.org/kotlin/api-reference/-lets--plot--kotlin/org.jetbrains.letsPlot.scale/index.html)\n",
    "\n",
    "#### Coordinated system\n",
    "\n",
    "The coordinate system determines how the x and y aesthetics combine to position elements in the plot.\n",
    "For example, to override the default X and Y ratio:\n",
    "\n",
    "`p + coordFixed(ratio=2)`\n",
    "\n",
    "See the list of the available methods in [coordinates reference](https://lets-plot.org/kotlin/api-reference/-lets--plot--kotlin/org.jetbrains.letsPlot.coord/index.html)\n",
    "\n",
    "#### Legend\n",
    "The axes and legends help users interpret plots.\n",
    "Use the `guide` methods or the `guide` argument of the `scale` method to customize the legend.\n",
    "For example, to define the number of columns in the legend:\n",
    "\n",
    "`p + scaleColorDiscrete(guide=guideLegend(ncol=2))`\n",
    "\n",
    "See more information about the `guideColorbar, guideLegend` functions in the [scale reference](https://lets-plot.org/kotlin/api-reference/-lets--plot--kotlin/org.jetbrains.letsPlot.scale/index.html)\n",
    "\n",
    "Adjust legend location on plot using the `theme` legendPosition, legendJustification and legendDirection methods, see:\n",
    "[theme reference](https://lets-plot.org/kotlin/api-reference/-lets--plot--kotlin/org.jetbrains.letsPlot.themes/index.html)\n",
    "\n",
    "#### Sampling\n",
    "\n",
    "Sampling is a special technique of data transformation built into Lets-Plot and it is applied after stat transformation.\n",
    "Sampling helps prevents UI freezes and out-of-memory crashes when attempting to plot an excessively large number of geometries.\n",
    "By default, the technique applies automatically when the data volume exceeds a certain threshold.\n",
    "The `samplingNone` value disables any sampling for the given layer. The sampling methods can be chained together using the + operator.\n",
    "\n",
    "Available methods:\n",
    "- `samplingRandomStratified`: randomly selects points from each group proportionally to the group size but also ensures\n",
    "that each group is represented by at least a specified minimum number of points.\n",
    "- `samplingRandom`: selects data points at randomly chosen indices without replacement.\n",
    "- `samplingPick`: analyses X-values and selects all points which X-values get in the set of first `n` X-values found in the population.\n",
    "- `samplingSystematic`: selects data points at evenly distributed indices.\n",
    "- `samplingCertexDP`, `samplingVertexVW`: simplifies plotting of polygons.\n",
    "There is a choice of two implementation algorithms: Douglas-Peucker (`DP`) and\n",
    "Visvalingam-Whyatt (`VW`).\n",
    "\n",
    "For more details, see the [sampling reference](https://lets-plot.org/kotlin/api-reference/-lets--plot--kotlin/org.jetbrains.letsPlot.sampling/index.html)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "<a name=\"GSG\" id=\"gsg\"></a>\n",
    "### Getting started\n",
    "\n",
    "Let's plot a point chart built using the mpg dataset.\n",
    "\n",
    "Create the `DataFrame` object and retrieve the data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    },
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "   <div id=\"wTNvDm\"></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.3.3/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(\"wTNvDm\").appendChild(div);\n",
       "           };\n",
       "           var e = document.getElementById(\"wTNvDm\");\n",
       "           e.appendChild(script);\n",
       "       })();\n",
       "   </script>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%useLatestDescriptors\n",
    "%use lets-plot\n",
    "@file:DependsOn(\"com.github.doyaaaaaken:kotlin-csv-jvm:0.7.3\")\n",
    "\n",
    "import com.github.doyaaaaaken.kotlincsv.client.*\n",
    "\n",
    "val csvData = java.io.File(\"mpg.csv\")\n",
    "\n",
    "val mpg: List<Map<String, String>> = CsvReader().readAllWithHeader(csvData)\n",
    "\n",
    "fun col(name: String, discrete: Boolean=false): List<*> {\n",
    "    return mpg.map {\n",
    "        val v = it[name]\n",
    "        if(discrete) v else v?.toDouble()\n",
    "    }\n",
    "}\n",
    "\n",
    "val df = mapOf(\n",
    "    \"displ\" to col(\"displ\"),\n",
    "    \"hwy\" to col(\"hwy\"),\n",
    "    \"cyl\" to col(\"cyl\"),\n",
    "    \"index\" to col(\"\"),\n",
    "    \"cty\" to col(\"cty\"),\n",
    "    \"drv\" to col(\"drv\", true),\n",
    "    \"year\" to col(\"year\")\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Plot the basic point chart."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Perform the following aesthetic mappings:\n",
    " - `x` = displ (the **displ** column of the dataframe)\n",
    " - `y` = hwy  (the **hwy** column of the dataframe)\n",
    " - `color` = cyl (the **cyl** column of the dataframe)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    },
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "   <div id=\"RpoXVU\"></div>\n",
       "   <script type=\"text/javascript\" data-lets-plot-script=\"plot\">\n",
       "       (function() {\n",
       "           var plotSpec={\n",
       "\"mapping\":{\n",
       "\"x\":\"displ\",\n",
       "\"y\":\"hwy\",\n",
       "\"color\":\"cyl\"\n",
       "},\n",
       "\"data\":{\n",
       "},\n",
       "\"kind\":\"plot\",\n",
       "\"scales\":[],\n",
       "\"layers\":[{\n",
       "\"mapping\":{\n",
       "},\n",
       "\"stat\":\"identity\",\n",
       "\"data\":{\n",
       "\"cyl\":[4.0,4.0,4.0,4.0,6.0,6.0,6.0,4.0,4.0,4.0,4.0,6.0,6.0,6.0,6.0,6.0,6.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,4.0,4.0,6.0,6.0,6.0,4.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,8.0,8.0,8.0,8.0,8.0,6.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,6.0,6.0,6.0,6.0,8.0,8.0,6.0,6.0,8.0,8.0,8.0,8.0,8.0,6.0,6.0,6.0,6.0,8.0,8.0,8.0,8.0,8.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,6.0,6.0,6.0,4.0,4.0,4.0,4.0,6.0,6.0,6.0,6.0,6.0,6.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,6.0,6.0,8.0,8.0,4.0,4.0,4.0,4.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,8.0,6.0,6.0,6.0,6.0,8.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,6.0,6.0,6.0,8.0,4.0,4.0,4.0,4.0,6.0,6.0,6.0,4.0,4.0,4.0,4.0,6.0,6.0,6.0,4.0,4.0,4.0,4.0,4.0,8.0,8.0,4.0,4.0,4.0,6.0,6.0,6.0,6.0,4.0,4.0,4.0,4.0,6.0,4.0,4.0,4.0,4.0,4.0,5.0,5.0,6.0,6.0,4.0,4.0,4.0,4.0,5.0,5.0,4.0,4.0,4.0,4.0,6.0,6.0,6.0],\n",
       "\"displ\":[1.8,1.8,2.0,2.0,2.8,2.8,3.1,1.8,1.8,2.0,2.0,2.8,2.8,3.1,3.1,2.8,3.1,4.2,5.3,5.3,5.3,5.7,6.0,5.7,5.7,6.2,6.2,7.0,5.3,5.3,5.7,6.5,2.4,2.4,3.1,3.5,3.6,2.4,3.0,3.3,3.3,3.3,3.3,3.3,3.8,3.8,3.8,4.0,3.7,3.7,3.9,3.9,4.7,4.7,4.7,5.2,5.2,3.9,4.7,4.7,4.7,5.2,5.7,5.9,4.7,4.7,4.7,4.7,4.7,4.7,5.2,5.2,5.7,5.9,4.6,5.4,5.4,4.0,4.0,4.0,4.0,4.6,5.0,4.2,4.2,4.6,4.6,4.6,5.4,5.4,3.8,3.8,4.0,4.0,4.6,4.6,4.6,4.6,5.4,1.6,1.6,1.6,1.6,1.6,1.8,1.8,1.8,2.0,2.4,2.4,2.4,2.4,2.5,2.5,3.3,2.0,2.0,2.0,2.0,2.7,2.7,2.7,3.0,3.7,4.0,4.7,4.7,4.7,5.7,6.1,4.0,4.2,4.4,4.6,5.4,5.4,5.4,4.0,4.0,4.6,5.0,2.4,2.4,2.5,2.5,3.5,3.5,3.0,3.0,3.5,3.3,3.3,4.0,5.6,3.1,3.8,3.8,3.8,5.3,2.5,2.5,2.5,2.5,2.5,2.5,2.2,2.2,2.5,2.5,2.5,2.5,2.5,2.5,2.7,2.7,3.4,3.4,4.0,4.7,2.2,2.2,2.4,2.4,3.0,3.0,3.5,2.2,2.2,2.4,2.4,3.0,3.0,3.3,1.8,1.8,1.8,1.8,1.8,4.7,5.7,2.7,2.7,2.7,3.4,3.4,4.0,4.0,2.0,2.0,2.0,2.0,2.8,1.9,2.0,2.0,2.0,2.0,2.5,2.5,2.8,2.8,1.9,1.9,2.0,2.0,2.5,2.5,1.8,1.8,2.0,2.0,2.8,2.8,3.6],\n",
       "\"hwy\":[29.0,29.0,31.0,30.0,26.0,26.0,27.0,26.0,25.0,28.0,27.0,25.0,25.0,25.0,25.0,24.0,25.0,23.0,20.0,15.0,20.0,17.0,17.0,26.0,23.0,26.0,25.0,24.0,19.0,14.0,15.0,17.0,27.0,30.0,26.0,29.0,26.0,24.0,24.0,22.0,22.0,24.0,24.0,17.0,22.0,21.0,23.0,23.0,19.0,18.0,17.0,17.0,19.0,19.0,12.0,17.0,15.0,17.0,17.0,12.0,17.0,16.0,18.0,15.0,16.0,12.0,17.0,17.0,16.0,12.0,15.0,16.0,17.0,15.0,17.0,17.0,18.0,17.0,19.0,17.0,19.0,19.0,17.0,17.0,17.0,16.0,16.0,17.0,15.0,17.0,26.0,25.0,26.0,24.0,21.0,22.0,23.0,22.0,20.0,33.0,32.0,32.0,29.0,32.0,34.0,36.0,36.0,29.0,26.0,27.0,30.0,31.0,26.0,26.0,28.0,26.0,29.0,28.0,27.0,24.0,24.0,24.0,22.0,19.0,20.0,17.0,12.0,19.0,18.0,14.0,15.0,18.0,18.0,15.0,17.0,16.0,18.0,17.0,19.0,19.0,17.0,29.0,27.0,31.0,32.0,27.0,26.0,26.0,25.0,25.0,17.0,17.0,20.0,18.0,26.0,26.0,27.0,28.0,25.0,25.0,24.0,27.0,25.0,26.0,23.0,26.0,26.0,26.0,26.0,25.0,27.0,25.0,27.0,20.0,20.0,19.0,17.0,20.0,17.0,29.0,27.0,31.0,31.0,26.0,26.0,28.0,27.0,29.0,31.0,31.0,26.0,26.0,27.0,30.0,33.0,35.0,37.0,35.0,15.0,18.0,20.0,20.0,22.0,17.0,19.0,18.0,20.0,29.0,26.0,29.0,29.0,24.0,44.0,29.0,26.0,29.0,29.0,29.0,29.0,23.0,24.0,44.0,41.0,29.0,26.0,28.0,29.0,29.0,29.0,28.0,29.0,26.0,26.0,26.0]\n",
       "},\n",
       "\"position\":\"identity\",\n",
       "\"geom\":\"point\"\n",
       "}]\n",
       "};\n",
       "           var plotContainer = document.getElementById(\"RpoXVU\");\n",
       "           window.letsPlotCall(function() {{\n",
       "               LetsPlot.buildPlotFromProcessedSpecs(plotSpec, -1, -1, plotContainer);\n",
       "           }});\n",
       "       })();\n",
       "   </script>"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "// Mapping\n",
    "letsPlot(df) {x = \"displ\"; y = \"hwy\"; color = \"cyl\"} + geomPoint(df)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Apply statistical data transformation to count the number of cases at each x position."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    },
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "   <div id=\"Qfd25O\"></div>\n",
       "   <script type=\"text/javascript\" data-lets-plot-script=\"plot\">\n",
       "       (function() {\n",
       "           var plotSpec={\n",
       "\"mapping\":{\n",
       "},\n",
       "\"data\":{\n",
       "},\n",
       "\"kind\":\"plot\",\n",
       "\"scales\":[],\n",
       "\"layers\":[{\n",
       "\"mapping\":{\n",
       "\"x\":\"displ\",\n",
       "\"color\":\"..count..\",\n",
       "\"size\":\"..count..\"\n",
       "},\n",
       "\"stat\":\"count\",\n",
       "\"data\":{\n",
       "\"..count..\":[14.0,21.0,10.0,6.0,4.0,6.0,8.0,1.0,2.0,1.0,1.0,13.0,5.0,2.0,8.0,9.0,8.0,15.0,3.0,3.0,17.0,5.0,2.0,11.0,8.0,2.0,5.0,20.0,8.0,1.0,1.0,1.0,6.0,4.0,3.0],\n",
       "\"displ\":[1.8,2.0,2.8,3.1,4.2,5.3,5.7,6.0,6.2,7.0,6.5,2.4,3.5,3.6,3.0,3.3,3.8,4.0,3.7,3.9,4.7,5.2,5.9,4.6,5.4,5.0,1.6,2.5,2.7,6.1,4.4,5.6,2.2,3.4,1.9]\n",
       "},\n",
       "\"position\":\"identity\",\n",
       "\"geom\":\"point\"\n",
       "}]\n",
       "};\n",
       "           var plotContainer = document.getElementById(\"Qfd25O\");\n",
       "           window.letsPlotCall(function() {{\n",
       "               LetsPlot.buildPlotFromProcessedSpecs(plotSpec, -1, -1, plotContainer);\n",
       "           }});\n",
       "       })();\n",
       "   </script>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "val p = letsPlot(df)\n",
    "p + geomPoint(df, stat = Stat.count()) {x = \"displ\"; color = \"..count..\"; size = \"..count..\"}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Change the pallete and the legend, add the title. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    },
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "   <div id=\"RiCH8Z\"></div>\n",
       "   <script type=\"text/javascript\" data-lets-plot-script=\"plot\">\n",
       "       (function() {\n",
       "           var plotSpec={\n",
       "\"ggtitle\":{\n",
       "\"text\":\"Displacement by horsepower\"\n",
       "},\n",
       "\"mapping\":{\n",
       "\"x\":\"displ\",\n",
       "\"y\":\"hwy\",\n",
       "\"color\":\"cyl\"\n",
       "},\n",
       "\"data\":{\n",
       "},\n",
       "\"kind\":\"plot\",\n",
       "\"scales\":[{\n",
       "\"aesthetic\":\"color\",\n",
       "\"scale_mapper_kind\":\"color_gradient\",\n",
       "\"high\":\"green\",\n",
       "\"low\":\"red\",\n",
       "\"guide\":{\n",
       "\"name\":\"legend\",\n",
       "\"ncol\":2\n",
       "}\n",
       "}],\n",
       "\"layers\":[{\n",
       "\"mapping\":{\n",
       "},\n",
       "\"stat\":\"identity\",\n",
       "\"data\":{\n",
       "\"cyl\":[4.0,4.0,4.0,4.0,6.0,6.0,6.0,4.0,4.0,4.0,4.0,6.0,6.0,6.0,6.0,6.0,6.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,4.0,4.0,6.0,6.0,6.0,4.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,8.0,8.0,8.0,8.0,8.0,6.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,6.0,6.0,6.0,6.0,8.0,8.0,6.0,6.0,8.0,8.0,8.0,8.0,8.0,6.0,6.0,6.0,6.0,8.0,8.0,8.0,8.0,8.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,6.0,6.0,6.0,4.0,4.0,4.0,4.0,6.0,6.0,6.0,6.0,6.0,6.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,8.0,6.0,6.0,8.0,8.0,4.0,4.0,4.0,4.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,6.0,8.0,6.0,6.0,6.0,6.0,8.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,4.0,6.0,6.0,6.0,8.0,4.0,4.0,4.0,4.0,6.0,6.0,6.0,4.0,4.0,4.0,4.0,6.0,6.0,6.0,4.0,4.0,4.0,4.0,4.0,8.0,8.0,4.0,4.0,4.0,6.0,6.0,6.0,6.0,4.0,4.0,4.0,4.0,6.0,4.0,4.0,4.0,4.0,4.0,5.0,5.0,6.0,6.0,4.0,4.0,4.0,4.0,5.0,5.0,4.0,4.0,4.0,4.0,6.0,6.0,6.0],\n",
       "\"displ\":[1.8,1.8,2.0,2.0,2.8,2.8,3.1,1.8,1.8,2.0,2.0,2.8,2.8,3.1,3.1,2.8,3.1,4.2,5.3,5.3,5.3,5.7,6.0,5.7,5.7,6.2,6.2,7.0,5.3,5.3,5.7,6.5,2.4,2.4,3.1,3.5,3.6,2.4,3.0,3.3,3.3,3.3,3.3,3.3,3.8,3.8,3.8,4.0,3.7,3.7,3.9,3.9,4.7,4.7,4.7,5.2,5.2,3.9,4.7,4.7,4.7,5.2,5.7,5.9,4.7,4.7,4.7,4.7,4.7,4.7,5.2,5.2,5.7,5.9,4.6,5.4,5.4,4.0,4.0,4.0,4.0,4.6,5.0,4.2,4.2,4.6,4.6,4.6,5.4,5.4,3.8,3.8,4.0,4.0,4.6,4.6,4.6,4.6,5.4,1.6,1.6,1.6,1.6,1.6,1.8,1.8,1.8,2.0,2.4,2.4,2.4,2.4,2.5,2.5,3.3,2.0,2.0,2.0,2.0,2.7,2.7,2.7,3.0,3.7,4.0,4.7,4.7,4.7,5.7,6.1,4.0,4.2,4.4,4.6,5.4,5.4,5.4,4.0,4.0,4.6,5.0,2.4,2.4,2.5,2.5,3.5,3.5,3.0,3.0,3.5,3.3,3.3,4.0,5.6,3.1,3.8,3.8,3.8,5.3,2.5,2.5,2.5,2.5,2.5,2.5,2.2,2.2,2.5,2.5,2.5,2.5,2.5,2.5,2.7,2.7,3.4,3.4,4.0,4.7,2.2,2.2,2.4,2.4,3.0,3.0,3.5,2.2,2.2,2.4,2.4,3.0,3.0,3.3,1.8,1.8,1.8,1.8,1.8,4.7,5.7,2.7,2.7,2.7,3.4,3.4,4.0,4.0,2.0,2.0,2.0,2.0,2.8,1.9,2.0,2.0,2.0,2.0,2.5,2.5,2.8,2.8,1.9,1.9,2.0,2.0,2.5,2.5,1.8,1.8,2.0,2.0,2.8,2.8,3.6],\n",
       "\"hwy\":[29.0,29.0,31.0,30.0,26.0,26.0,27.0,26.0,25.0,28.0,27.0,25.0,25.0,25.0,25.0,24.0,25.0,23.0,20.0,15.0,20.0,17.0,17.0,26.0,23.0,26.0,25.0,24.0,19.0,14.0,15.0,17.0,27.0,30.0,26.0,29.0,26.0,24.0,24.0,22.0,22.0,24.0,24.0,17.0,22.0,21.0,23.0,23.0,19.0,18.0,17.0,17.0,19.0,19.0,12.0,17.0,15.0,17.0,17.0,12.0,17.0,16.0,18.0,15.0,16.0,12.0,17.0,17.0,16.0,12.0,15.0,16.0,17.0,15.0,17.0,17.0,18.0,17.0,19.0,17.0,19.0,19.0,17.0,17.0,17.0,16.0,16.0,17.0,15.0,17.0,26.0,25.0,26.0,24.0,21.0,22.0,23.0,22.0,20.0,33.0,32.0,32.0,29.0,32.0,34.0,36.0,36.0,29.0,26.0,27.0,30.0,31.0,26.0,26.0,28.0,26.0,29.0,28.0,27.0,24.0,24.0,24.0,22.0,19.0,20.0,17.0,12.0,19.0,18.0,14.0,15.0,18.0,18.0,15.0,17.0,16.0,18.0,17.0,19.0,19.0,17.0,29.0,27.0,31.0,32.0,27.0,26.0,26.0,25.0,25.0,17.0,17.0,20.0,18.0,26.0,26.0,27.0,28.0,25.0,25.0,24.0,27.0,25.0,26.0,23.0,26.0,26.0,26.0,26.0,25.0,27.0,25.0,27.0,20.0,20.0,19.0,17.0,20.0,17.0,29.0,27.0,31.0,31.0,26.0,26.0,28.0,27.0,29.0,31.0,31.0,26.0,26.0,27.0,30.0,33.0,35.0,37.0,35.0,15.0,18.0,20.0,20.0,22.0,17.0,19.0,18.0,20.0,29.0,26.0,29.0,29.0,24.0,44.0,29.0,26.0,29.0,29.0,29.0,29.0,23.0,24.0,44.0,41.0,29.0,26.0,28.0,29.0,29.0,29.0,28.0,29.0,26.0,26.0,26.0]\n",
       "},\n",
       "\"position\":\"nudge\",\n",
       "\"geom\":\"point\"\n",
       "}]\n",
       "};\n",
       "           var plotContainer = document.getElementById(\"RiCH8Z\");\n",
       "           window.letsPlotCall(function() {{\n",
       "               LetsPlot.buildPlotFromProcessedSpecs(plotSpec, -1, -1, plotContainer);\n",
       "           }});\n",
       "       })();\n",
       "   </script>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "val p = letsPlot(df) {x = \"displ\"; y = \"hwy\"; color = \"cyl\"}\n",
    "p + \n",
    "    geomPoint(df, position = positionNudge()) + \n",
    "    scaleGradient(\"color\", low = \"red\", high = \"green\", guide = guideLegend(ncol=2)) + \n",
    "    ggtitle(\"Displacement by horsepower\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Apply the randomly stratified sampling to select points from each group proportionally \n",
    "to the group size."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    },
    "pycharm": {
     "is_executing": false,
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "   <div id=\"THmTYS\"></div>\n",
       "   <script type=\"text/javascript\" data-lets-plot-script=\"plot\">\n",
       "       (function() {\n",
       "           var plotSpec={\n",
       "\"mapping\":{\n",
       "\"x\":\"displ\",\n",
       "\"y\":\"hwy\",\n",
       "\"color\":\"cyl\"\n",
       "},\n",
       "\"data\":{\n",
       "},\n",
       "\"kind\":\"plot\",\n",
       "\"scales\":[{\n",
       "\"aesthetic\":\"color\",\n",
       "\"scale_mapper_kind\":\"color_gradient\",\n",
       "\"high\":\"pink\",\n",
       "\"low\":\"blue\",\n",
       "\"guide\":{\n",
       "\"name\":\"legend\",\n",
       "\"ncol\":2\n",
       "}\n",
       "}],\n",
       "\"layers\":[{\n",
       "\"mapping\":{\n",
       "},\n",
       "\"stat\":\"identity\",\n",
       "\"data\":{\n",
       "\"cyl\":[4.0,6.0,8.0,8.0,8.0,8.0,6.0,6.0,6.0,8.0,6.0,8.0,8.0,8.0,8.0,4.0,4.0,4.0,4.0,4.0,6.0,8.0,4.0,4.0,6.0,6.0,6.0,4.0,4.0,4.0,4.0,6.0,4.0,6.0,4.0,4.0,4.0,4.0,4.0,6.0],\n",
       "\"displ\":[2.0,2.8,5.3,5.3,5.7,5.7,3.8,4.0,3.7,4.7,3.9,4.7,5.7,4.6,4.6,1.8,1.8,2.4,2.0,2.0,2.7,4.7,2.4,2.5,3.5,3.0,3.0,2.5,2.5,2.5,2.5,3.4,2.2,3.0,2.2,1.8,2.7,2.0,2.0,2.8],\n",
       "\"hwy\":[31.0,26.0,20.0,15.0,17.0,15.0,21.0,23.0,18.0,12.0,17.0,12.0,17.0,16.0,17.0,34.0,36.0,31.0,26.0,28.0,24.0,17.0,29.0,31.0,27.0,26.0,25.0,25.0,24.0,26.0,27.0,19.0,27.0,26.0,29.0,30.0,20.0,26.0,29.0,26.0]\n",
       "},\n",
       "\"sampling\":{\n",
       "\"n\":40.0,\n",
       "\"name\":\"random_stratified\"\n",
       "},\n",
       "\"position\":\"nudge\",\n",
       "\"geom\":\"point\"\n",
       "}],\n",
       "\"computation_messages\":[\"sampling_random_stratified(n=40) was applied to [point/identity stat] layer\"]\n",
       "};\n",
       "           var plotContainer = document.getElementById(\"THmTYS\");\n",
       "           window.letsPlotCall(function() {{\n",
       "               LetsPlot.buildPlotFromProcessedSpecs(plotSpec, -1, -1, plotContainer);\n",
       "           }});\n",
       "       })();\n",
       "   </script>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "val p = letsPlot(df) {x = \"displ\"; y = \"hwy\"; color = \"cyl\"}\n",
    "p   + geomPoint(\n",
    "      data=df, position = positionNudge(), \n",
    "      sampling = samplingRandomStratified(40)\n",
    "  ) + scaleGradient(\n",
    "      \"color\", low = \"blue\", high = \"pink\",\n",
    "      guide = guideLegend(ncol=2)\n",
    "  )"
   ]
  }
 ],
 "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": "1.9.23"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}