{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "52924083-876e-4fe1-874a-4da53b819c39", "metadata": {}, "outputs": [], "source": [ "import kotlin.random.Random" ] }, { "cell_type": "code", "execution_count": 2, "id": "f3f5cd41", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ " " ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%useLatestDescriptors\n", "%use lets-plot\n", "%use dataframe" ] }, { "cell_type": "code", "execution_count": 3, "id": "06df3cb5-087d-4741-9670-c65e49ec9bee", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Lets-Plot Kotlin API v.0.0.0-SNAPSHOT. Frontend: Notebook with dynamically loaded JS. Lets-Plot JS v.4.4.0." ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "LetsPlot.getInfo()" ] }, { "cell_type": "markdown", "id": "15508d12-1922-4c06-b9c4-6643387922a8", "metadata": {}, "source": [ "# Overriding aesthetics in guideLegend()ΒΆ\n", "You can set specific aesthetic values for legend keys." ] }, { "cell_type": "markdown", "id": "a3031c6a-3ef7-4ca2-bd5c-912c9ac4dfe3", "metadata": {}, "source": [ "## Demo" ] }, { "cell_type": "code", "execution_count": 4, "id": "b0516089-88bf-4a33-acfb-fab6ecefee14", "metadata": {}, "outputs": [ { "data": { "application/kotlindataframe+json": "{\"nrow\":3,\"ncol\":12,\"columns\":[\"untitled\",\"manufacturer\",\"model\",\"displ\",\"year\",\"cyl\",\"trans\",\"drv\",\"cty\",\"hwy\",\"fl\",\"class\"],\"kotlin_dataframe\":[{\"untitled\":1,\"manufacturer\":\"audi\",\"model\":\"a4\",\"displ\":1.8,\"year\":1999,\"cyl\":4,\"trans\":\"auto(l5)\",\"drv\":\"f\",\"cty\":18,\"hwy\":29,\"fl\":\"p\",\"class\":\"compact\"},{\"untitled\":2,\"manufacturer\":\"audi\",\"model\":\"a4\",\"displ\":1.8,\"year\":1999,\"cyl\":4,\"trans\":\"manual(m5)\",\"drv\":\"f\",\"cty\":21,\"hwy\":29,\"fl\":\"p\",\"class\":\"compact\"},{\"untitled\":3,\"manufacturer\":\"audi\",\"model\":\"a4\",\"displ\":2.0,\"year\":2008,\"cyl\":4,\"trans\":\"manual(m6)\",\"drv\":\"f\",\"cty\":20,\"hwy\":31,\"fl\":\"p\",\"class\":\"compact\"}]}", "text/html": [ " \n", " \n", " \n", " \n", " \n", "
\n", "\n", "

DataFrame: rowsCount = 3, columnsCount = 12

\n", "
untitledmanufacturermodeldisplyearcyltransdrvctyhwyflclass
1audia41,80000019994auto(l5)f1829pcompact
2audia41,80000019994manual(m5)f2129pcompact
3audia42,00000020084manual(m6)f2031pcompact
\n", " \n", " \n", " " ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "val mpgDf = DataFrame.readCSV(\"https://raw.githubusercontent.com/JetBrains/lets-plot-docs/master/data/mpg.csv\")\n", "val mpgData = mpgDf.toMap()\n", "mpgDf.head(3)" ] }, { "cell_type": "code", "execution_count": 5, "id": "24bcdf82-a6a8-4327-97a5-470d32b2e741", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// By default alpha is not applied to the legend.\n", "\n", "val baseMpgPlot = letsPlot(mpgData) { x = \"displ\"; y = \"hwy\"; color = \"drv\" } +\n", " geomPoint(size = 4, alpha = 0.2, stroke = 0)\n", "\n", "baseMpgPlot" ] }, { "cell_type": "code", "execution_count": 6, "id": "e8dd95ce-d2f5-4663-8e76-0d51f0a203dd", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// Applying alpha and size for better look.\n", "\n", "baseMpgPlot + guides(color = guideLegend(alpha = 0.4, size = 8.0))\n" ] }, { "cell_type": "markdown", "id": "f5b38a9a-5835-4030-85ce-0fcc9c8602c9", "metadata": {}, "source": [ "## Experiments with parameters" ] }, { "cell_type": "code", "execution_count": 7, "id": "f8b4c449", "metadata": {}, "outputs": [], "source": [ "Random(1)\n", "val n = 4\n", "val x = List(n) { it }\n", "val y = List(n) { Random.nextDouble() }\n", "val v = List(n) { Random.nextDouble() }\n", "val data = mapOf(\"x\" to x, \"y\" to y, \"v\" to v)" ] }, { "cell_type": "code", "execution_count": 8, "id": "4e04a12d", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// Base plot\n", "val p = letsPlot(data) { x = \"x\"; y = \"y\" } +\n", " geomPoint { color = asDiscrete(\"x\") } +\n", " ggsize(400, 200)\n", "p" ] }, { "cell_type": "code", "execution_count": 9, "id": "04c6a892", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// Specifying common aesthetics for all the legend labels.\n", "\n", "p + guides(color = guideLegend(shape = 22, size = 8.0, stroke = 1.8, fill = \"light-grey\", alpha = 0.6))" ] }, { "cell_type": "code", "execution_count": 10, "id": "98097225", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// Using a list of values.\n", "\n", "p + guides(color = guideLegend(color = listOf(\"red\", \"blue\", \"green\", \"pink\")))" ] }, { "cell_type": "code", "execution_count": 11, "id": "89ef8a97-02cc-4d23-9b84-fccb493628a4", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// Use `null` to keep the original value.\n", "\n", "p + guides(color = guideLegend(color = listOf(\"red\", null, \"green\", null)))" ] }, { "cell_type": "code", "execution_count": 12, "id": "6e9cb997", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// Using a list that is smaller than the number of legend keys.\n", "// The last value spreads to the rest of the keys.\n", "\n", "p + guides(color = guideLegend(color = listOf(\"grey\"), size = listOf(10.0, 8.0)))" ] }, { "cell_type": "code", "execution_count": 13, "id": "fa2b1a19-995c-4596-8dfc-d6831b46b646", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// Using a list that is smaller than the number of legend keys.\n", "// `null` can be used to stop value propagation; the rest keys will get their original values.\n", "\n", "p + guides(color = guideLegend(color = listOf(\"grey\", null), size = listOf(10.0, null, 8.0)))" ] }, { "cell_type": "markdown", "id": "ccebef12-d878-48aa-a497-627d284d2fbc", "metadata": {}, "source": [ "## Reproduced an example from [rbind.io](https://aosmith.rbind.io/2020/07/09/ggplot2-override-aes/)\n" ] }, { "cell_type": "code", "execution_count": 14, "id": "612092f4-190b-411c-bda3-6f5e57d8ef2f", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "val dat = mapOf(\n", " \"g1\" to listOf(\"High\", \"Low\", \"High\", \"Low\", \"High\", \"Low\", \"High\", \"Low\", \"High\", \"Low\", \"High\", \"Low\", \"High\", \"Low\", \"High\", \"Low\"),\n", " \"g2\" to listOf(\"Control\", \"Control\", \"Treatment\", \"Treatment\", \"Control\", \"Control\", \"Treatment\", \"Treatment\", \"Control\", \"Control\", \"Treatment\", \"Treatment\", \"Control\", \"Control\", \"Treatment\", \"Treatment\"),\n", " \"x\" to listOf(0.42, 0.39, 0.56, 0.59, 0.17, 0.95, 0.85, 0.25, 0.31, 0.75, 0.58, 0.9, 0.6, 0.86, 0.61, 0.61),\n", " \"y\" to listOf(-1.4, 3.6, 1.1, -0.1, 0.5, 0.0, -1.8, 0.8, -1.1, -0.6, 0.2, 0.3, 1.1, 1.6, 0.9, -0.6)\n", " )\n", "\n", "val bp = letsPlot(dat) { x = \"x\"; y = \"y\"; color = \"g1\"; shape = \"g2\" } +\n", " geomPoint(size = 5.0, alpha = 0.6)\n", "bp" ] }, { "cell_type": "code", "execution_count": 15, "id": "16324c8c-df68-4159-b4d0-9eb50790bf8a", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// Customized scales and default legend do not correspond well.\n", "\n", "val cp = letsPlot(dat) { x = \"x\"; y = \"y\"; fill = \"g1\"; shape = \"g2\" } +\n", " geomPoint(size = 5.0, color = \"black\") +\n", " scaleFillManual(values = listOf(\"#002F70\", \"#EDB4B5\")) +\n", " scaleShapeManual(values = listOf(21, 24))\n", "\n", "cp" ] }, { "cell_type": "code", "execution_count": 16, "id": "f4f54d77-5bd3-4477-83c2-8998da6fdab2", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// This can be fixed by overriding aesthetics.\n", "\n", "cp + guides(\n", " fill = guideLegend(shape = 21),\n", " shape = guideLegend(fill = \"black\")\n", ")" ] }, { "cell_type": "markdown", "id": "dd3315a9-2a01-43e8-bf3e-749283bd94c8", "metadata": {}, "source": [ "## Testing" ] }, { "cell_type": "code", "execution_count": 17, "id": "f2889194", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// `fill` and `size` are mapped to the same variable.\n", "// The result is not defined if the same legend is set via different aesthetics.\n", "\n", "val piePlot = letsPlot(mapOf(\"n\" to listOf(\"a\", \"b\", \"c\"))) + \n", " geomPie(stat = Stat.identity) {fill = \"n\"; size = \"n\"}\n", "\n", "gggrid(listOf(\n", " piePlot,\n", " piePlot + guides(\n", " fill = guideLegend(color = \"blue\"),\n", " size = guideLegend(stroke = 4.0, color = \"black\")\n", " )\n", ")) + ggsize(800, 300)" ] }, { "cell_type": "code", "execution_count": 18, "id": "12cd9926-b947-407d-8106-294b02c2a062", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// Verifying different aesthetics\n", "\n", "p + guides(\n", " color = guideLegend(\n", " color = listOf(\"red\", \"blue\", \"green\", \"pink\"),\n", " shape = 22,\n", " size = 8.0,\n", " stroke = 1.8,\n", " fill = \"white\",\n", " alpha = 0.4\n", " )\n", ")" ] }, { "cell_type": "code", "execution_count": 19, "id": "7c7db11a-ad6d-44a4-aa2f-e6143c5aab1a", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// Invalid or null values\n", "\n", "p + guides(color=guideLegend(color = null, shape = -11, size = 0, stroke = -2))" ] }, { "cell_type": "code", "execution_count": 20, "id": "7b57d837-9a59-431b-83f7-5e041032e200", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// An empty list of values\n", "\n", "p + guides(color=guideLegend(color=listOf()))" ] }, { "cell_type": "code", "execution_count": 21, "id": "7a5ca960-6362-4317-9eb5-f0d99ea776da", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// `override_aes` in the case when some legend labels are combined into one;\n", "// see issue https://github.com/JetBrains/lets-plot/issues/1129 for details.\n", "\n", "val df = mapOf(\n", " \"category\" to listOf(\"A\", \"B\", \"C\", \"D\"),\n", " \"value\" to listOf(10, 15, 20, 25)\n", ")\n", "\n", "letsPlot(df) + ggsize(400, 200) +\n", " geomPoint { x = \"category\"; y = \"value\"; color = \"category\" } +\n", " scaleColorManual(\n", " values = listOf(\"red\", \"blue\", \"green\", \"black\"),\n", " labels = listOf(\"Label A\", \"Label B\", \"Label C\", \"Label C\")\n", " ) +\n", " guides(color = guideLegend(color = listOf(\"pink\", \"gray\", \"green\", \"orange\")))" ] }, { "cell_type": "markdown", "id": "4f4a7d72-7dd4-4ee8-965d-bff65fa2eb74", "metadata": {}, "source": [ "## Custom legend" ] }, { "cell_type": "code", "execution_count": 22, "id": "a113117f-67db-48e6-9cc2-9e443c5252a3", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "val data = mapOf(\n", " \"x\" to listOf(1, 2, 3, 4, 5),\n", " \"y\" to listOf(2, 3, 5, 7, 11)\n", ")\n", "\n", "// Verifying how `override_aes` works for custom legends.\n", "// Note that the same effect can be achieved easier by using direct parameters.\n", "\n", "val mPlot = letsPlot(data) { x = \"x\"; y = \"y\" } +\n", " geomPoint(manualKey = \"Point\") +\n", " geomLine(manualKey = \"Line\")\n", "\n", "gggrid(\n", " listOf(\n", " mPlot,\n", " mPlot + guides(manual = guideLegend(size = 6.0)),\n", " mPlot + guides(manual = guideLegend(size = listOf(6.0, 2.0), color = listOf(\"red\", \"blue\")))\n", " )\n", ") + ggsize(900, 200)" ] }, { "cell_type": "code", "execution_count": 23, "id": "f274f43f-231e-4d78-a382-6c6b91bfeb6c", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "// Changing the order in the legend via `index` in `layer_key`\n", "\n", "val mPlot2 = letsPlot(data) { x = \"x\"; y = \"y\" } +\n", " geomPoint(manualKey = layerKey(\"Point\", index = 1)) +\n", " geomLine(manualKey = layerKey(\"Line\", index = 0))\n", "\n", "gggrid(\n", " listOf(\n", " mPlot2,\n", " mPlot2 + guides(manual = guideLegend(size = listOf(2.0), color = listOf(\"red\", \"blue\")))\n", " )\n", ") + ggsize(600, 200)" ] }, { "cell_type": "code", "execution_count": null, "id": "4ab8d56a-eedc-4e80-b710-b31a9e0eddc2", "metadata": {}, "outputs": [], "source": [] } ], "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": 5 }