{ "cells": [ { "cell_type": "markdown", "id": "f6b68dfa-a402-4c30-802b-a8cbaec69a7b", "metadata": {}, "source": [ "# Palmer Penguins\n", "\n", "This notebook is inspired by an example [Radar chart with ggradar](https://r-graph-gallery.com/web-radar-chart-with-R.html)." ] }, { "cell_type": "code", "execution_count": 1, "id": "aebbd473-7db1-4144-8bae-a61aefc67e9d", "metadata": { "execution": { "iopub.execute_input": "2025-12-03T16:13:57.846074Z", "iopub.status.busy": "2025-12-03T16:13:57.844394Z", "iopub.status.idle": "2025-12-03T16:14:00.375463Z", "shell.execute_reply": "2025-12-03T16:14:00.375206Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", " " ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%useLatestDescriptors\n", "%use dataframe\n", "%use lets-plot" ] }, { "cell_type": "code", "execution_count": 2, "id": "d5f7ef92-18ee-4435-850b-ce1eda0a98cd", "metadata": { "execution": { "iopub.execute_input": "2025-12-03T16:14:00.378111Z", "iopub.status.busy": "2025-12-03T16:14:00.377500Z", "iopub.status.idle": "2025-12-03T16:14:00.409530Z", "shell.execute_reply": "2025-12-03T16:14:00.409094Z" } }, "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": "4cc8902f-7761-43ef-9fa9-26c72c2b8f00", "metadata": { "execution": { "iopub.execute_input": "2025-12-03T16:14:00.412421Z", "iopub.status.busy": "2025-12-03T16:14:00.411635Z", "iopub.status.idle": "2025-12-03T16:14:00.939262Z", "shell.execute_reply": "2025-12-03T16:14:00.938999Z" } }, "outputs": [], "source": [ "fun rescaleInGroupDataFrame(df: DataFrame<*>, valueCol: String, groupCol: String, rescaledCol: String? = null): DataFrame<*> {\n", " val rescaledColName = if (rescaledCol == null) {\n", " \"rescaled_${valueCol}\"\n", " } else {\n", " rescaledCol\n", " }\n", " fun rescaleSubDataFrame(subDf: DataFrame<*>): DataFrame<*> {\n", " val minValue = subDf.minByOrNull(valueCol)?.let { it[valueCol] } as Double\n", " val maxValue = subDf.maxByOrNull(valueCol)?.let { it[valueCol] } as Double\n", " return subDf.add(rescaledColName) { (valueCol() - minValue) / (maxValue - minValue) }\n", " }\n", " return df.select(groupCol).distinct().map { v -> rescaleSubDataFrame(df.filter { groupCol() == v[groupCol] }) }.concat()\n", "}\n", "\n", "fun getData(): DataFrame<*> {\n", " val df = DataFrame.readCSV(\"https://raw.githubusercontent.com/JetBrains/lets-plot-docs/master/data/penguins.csv\")\n", " .dropNulls()\n", " .rename(\"bill_length_mm\", \"bill_depth_mm\", \"flipper_length_mm\", \"body_mass_g\")\n", " .into(\"avg. bill length\", \"avg. bill depth\", \"avg. flipper length\", \"avg. body mass\")\n", " .groupBy(\"species\")\n", " .mean()\n", " .gather(\"avg. bill length\", \"avg. bill depth\", \"avg. flipper length\", \"avg. body mass\")\n", " .into(\"variable\", \"value\")\n", " .update { \"value\"() }\n", " .where { \"variable\"() == \"avg. body mass\" }\n", " .with { it / 1000 }\n", " .add(\"units\") {\n", " when (\"variable\"()) {\n", " \"avg. body mass\" -> \"kg\"\n", " else -> \"mm\"\n", " }\n", " }\n", " return rescaleInGroupDataFrame(df, \"value\", \"variable\")\n", " .add(\"rescaled_value_pct\") { floor(100 * \"rescaled_value\"()) }\n", " .convert { \"rescaled_value_pct\"() }.to()\n", " .sortBy(\"species\")\n", "}" ] }, { "cell_type": "code", "execution_count": 4, "id": "8f01ce8f-807a-457b-a91f-6a68568f883f", "metadata": { "execution": { "iopub.execute_input": "2025-12-03T16:14:00.941597Z", "iopub.status.busy": "2025-12-03T16:14:00.941180Z", "iopub.status.idle": "2025-12-03T16:14:01.538989Z", "shell.execute_reply": "2025-12-03T16:14:01.538643Z" } }, "outputs": [ { "data": { "application/kotlindataframe+json": "{\"nrow\":4,\"ncol\":6,\"columns\":[\"species\",\"variable\",\"value\",\"units\",\"rescaled_value\",\"rescaled_value_pct\"],\"is_formatted\":false,\"kotlin_dataframe\":[{\"species\":\"Adelie\",\"variable\":\"avg. bill length\",\"value\":38.82397260273974,\"units\":\"mm\",\"rescaled_value\":0.0,\"rescaled_value_pct\":0},{\"species\":\"Adelie\",\"variable\":\"avg. bill depth\",\"value\":18.347260273972594,\"units\":\"mm\",\"rescaled_value\":0.9785838080813327,\"rescaled_value_pct\":97},{\"species\":\"Adelie\",\"variable\":\"avg. flipper length\",\"value\":190.1027397260274,\"units\":\"mm\",\"rescaled_value\":0.0,\"rescaled_value_pct\":0},{\"species\":\"Adelie\",\"variable\":\"avg. body mass\",\"value\":3.7061643835616436,\"units\":\"kg\",\"rescaled_value\":0.0,\"rescaled_value_pct\":0}]}", "text/html": [ " \n", " \n", " \n", " \n", " \n", "
\n", "\n", "

DataFrame: rowsCount = 4, columnsCount = 6

\n", "
speciesvariablevalueunitsrescaled_valuerescaled_value_pct
Adelieavg. bill length38.823973mm0.0000000
Adelieavg. bill depth18.347260mm0.97858497
Adelieavg. flipper length190.102740mm0.0000000
Adelieavg. body mass3.706164kg0.0000000
\n", " \n", " \n", " " ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "val df = getData()\n", "df.head(4)" ] }, { "cell_type": "code", "execution_count": 5, "id": "cef2ba80-6b5f-4ef2-b40d-8a003d02bec0", "metadata": { "execution": { "iopub.execute_input": "2025-12-03T16:14:01.541296Z", "iopub.status.busy": "2025-12-03T16:14:01.540700Z", "iopub.status.idle": "2025-12-03T16:14:01.681467Z", "shell.execute_reply": "2025-12-03T16:14:01.681204Z" } }, "outputs": [], "source": [ "val fontFamily = \"roboto\"\n", "val axisColor = \"lightgray\"\n", "val axisTextData = mapOf(\n", " \"x\" to List(3) { \"avg. bill length\" },\n", " \"y\" to listOf(0, 50, 100),\n", " \"text\" to listOf(\"0%\", \"50%\", \"100%\")\n", ")\n", "val penguinsColors = mapOf(\n", " \"Adelie\" to \"#ff5a5f\",\n", " \"Chinstrap\" to \"#ffb400\",\n", " \"Gentoo\" to \"#007a87\"\n", ")\n", "val penguinsTooltips = layerTooltips().title(\"@species\").line(\"@variable (@units): @value\").format(\"@value\", \".2~f\")\n", "val penguinsTheme = theme(\n", " text = elementText(family = fontFamily, size = 18),\n", " plotTitle = elementText(size = 28, hjust = .5, face = \"bold\"),\n", " axisTitle = \"blank\", axisTextY = \"blank\", axisLineX = \"blank\",\n", " axisTicks = elementLine(color = axisColor),\n", " panelGrid = elementLine(color = axisColor),\n", " panelInset = Pair(0, 100),\n", " tooltip = elementRect(),\n", " axisTooltip = \"blank\",\n", ").legendPosition(1, 0).legendJustification(1, 0)" ] }, { "cell_type": "code", "execution_count": 6, "id": "07a3e4b7-55ee-47e0-aa88-9d850340c571", "metadata": { "execution": { "iopub.execute_input": "2025-12-03T16:14:01.683334Z", "iopub.status.busy": "2025-12-03T16:14:01.682877Z", "iopub.status.idle": "2025-12-03T16:14:02.029722Z", "shell.execute_reply": "2025-12-03T16:14:02.029545Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/plot+json": { "apply_color_scheme": true, "output": { "coord": { "name": "polar", "ylim": [ -15.0, 100.0 ] }, "data": { "rescaled_value": [ 0.0, 0.9785838080813327, 0.0, 0.0, 1.0, 1.0, 0.21084596765810767, 0.019421758680678157, 0.8735489357640369, 0.0, 1.0, 1.0 ], "rescaled_value_pct": [ 0.0, 97.0, 0.0, 0.0, 100.0, 100.0, 21.0, 1.0, 87.0, 0.0, 100.0, 100.0 ], "species": [ "Adelie", "Adelie", "Adelie", "Adelie", "Chinstrap", "Chinstrap", "Chinstrap", "Chinstrap", "Gentoo", "Gentoo", "Gentoo", "Gentoo" ], "units": [ "mm", "mm", "mm", "kg", "mm", "mm", "mm", "kg", "mm", "mm", "mm", "kg" ], "value": [ 38.82397260273974, 18.347260273972594, 190.1027397260274, 3.7061643835616436, 48.83382352941177, 18.420588235294115, 195.8235294117647, 3.7330882352941175, 47.56806722689075, 14.99663865546218, 217.23529411764707, 5.0924369747899165 ], "variable": [ "avg. bill length", "avg. bill depth", "avg. flipper length", "avg. body mass", "avg. bill length", "avg. bill depth", "avg. flipper length", "avg. body mass", "avg. bill length", "avg. bill depth", "avg. flipper length", "avg. body mass" ] }, "data_meta": { "series_annotations": [ { "column": "species", "type": "str" }, { "column": "variable", "type": "str" }, { "column": "value", "type": "float" }, { "column": "units", "type": "str" }, { "column": "rescaled_value", "type": "float" }, { "column": "rescaled_value_pct", "type": "int" } ] }, "ggsize": { "height": 600.0, "width": 800.0 }, "ggtitle": { "text": "Penguins species" }, "kind": "plot", "layers": [ { "alpha": 0.2, "color_by": "paint_a", "fill_by": "paint_a", "flat": true, "geom": "area", "mapping": { "paint_a": "species", "x": "variable", "y": "rescaled_value_pct" }, "position": "identity", "size": 2.5, "stat": "identity" }, { "color_by": "paint_a", "geom": "point", "mapping": { "paint_a": "species", "x": "variable", "y": "rescaled_value_pct" }, "position": "identity", "size": 6.0, "stat": "identity", "tooltips": { "formats": [ { "field": "@value", "format": ".2~f" } ], "lines": [ "@variable (@units): @value" ], "title": "@species" } }, { "data": { "text": [ "0%", "50%", "100%" ], "x": [ "avg. bill length", "avg. bill length", "avg. bill length" ], "y": [ 0.0, 50.0, 100.0 ] }, "data_meta": { "series_annotations": [ { "column": "x", "type": "str" }, { "column": "y", "type": "int" }, { "column": "text", "type": "str" } ] }, "family": "roboto", "fontface": "bold", "geom": "text", "hjust": 1.0, "mapping": { "label": "text", "x": "x", "y": "y" }, "position": "identity", "size": 10.0, "stat": "identity" } ], "mapping": {}, "scales": [ { "aesthetic": "x", "discrete": true }, { "aesthetic": "paint_a", "breaks": [ "Adelie", "Chinstrap", "Gentoo" ], "name": "", "values": [ "#ff5a5f", "#ffb400", "#007a87" ] } ], "theme": { "axis_line_x": "blank", "axis_text_y": "blank", "axis_ticks": { "blank": false, "color": "lightgray" }, "axis_title": "blank", "axis_tooltip": "blank", "flavor": "solarized_light", "legend_justification": [ 1.0, 0.0 ], "legend_position": [ 1.0, 0.0 ], "panel_grid": { "blank": false, "color": "lightgray" }, "panel_inset": [ 0.0, 100.0 ], "plot_title": { "blank": false, "face": "bold", "hjust": 0.5, "size": 28.0 }, "text": { "blank": false, "family": "roboto", "size": 18.0 }, "tooltip": { "blank": false } } }, "output_type": "lets_plot_spec", "swing_enabled": true }, "text/html": [ "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " 0%\n", " \n", " \n", " \n", " \n", " \n", " \n", " 50%\n", " \n", " \n", " \n", " \n", " \n", " \n", " 100%\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " avg. bill length\n", " \n", " \n", " \n", " \n", " \n", " \n", " avg. bill depth\n", " \n", " \n", " \n", " \n", " \n", " \n", " avg. flipper length\n", " \n", " \n", " \n", " \n", " \n", " \n", " avg. body mass\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Penguins species\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Adelie\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Chinstrap\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Gentoo\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", " " ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "letsPlot(df.toMap()) +\n", " geomArea(position = positionIdentity, flat = true,\n", " size = 2.5, colorBy = \"paint_a\", fillBy = \"paint_a\", alpha = .2)\n", " { x = \"variable\"; y = \"rescaled_value_pct\"; paint_a = \"species\" } +\n", " geomPoint(size = 6, colorBy = \"paint_a\", tooltips = penguinsTooltips)\n", " { x = \"variable\"; y = \"rescaled_value_pct\"; paint_a = \"species\" } +\n", " geomText(data = axisTextData, hjust = 1, fontface = \"bold\", family = fontFamily, size = 10)\n", " { x = \"x\"; y = \"y\"; label = \"text\" } +\n", " scaleXDiscrete() +\n", " scaleManual(\"paint_a\", name = \"\", values = penguinsColors) +\n", " coordPolar(ylim = Pair(-15, 100)) +\n", " ggsize(800, 600) +\n", " ggtitle(\"Penguins species\") +\n", " penguinsTheme + flavorSolarizedLight()" ] } ], "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 }