{ "cells": [ { "cell_type": "markdown", "id": "6025439a", "metadata": {}, "source": [ "# Custom Legend with `manual_key` Option\n", "\n", "In Lets-Plot, as in ggplot2, legends are automatically generated based on the aesthetic mappings in the plot. \n", "\n", "Sometimes, however, this automatic generation doesn't provide the precise control needed for complex visualizations. \n", "\n", "The `manual_key` option allows you to create custom legend entries specific to individual plot layers.\n", "\n", "The `manual_key` option can be used in two ways:\n", "\n", "- Simple case: pass a string to serve as the label for the legend entry.\n", "\n", "- Advanced case: use the `layer_key()` function for more detailed customization:\n", "\n", " - `label` - text for the legend element\n", " - `group` - key used to group elements in the legend\n", " - `index` - position of the element within its legend group\n", " - `kwargs` - dictionary of aesthetic parameters to be applied in the legend" ] }, { "cell_type": "code", "execution_count": 1, "id": "a68e6d43-375d-40cb-9926-905fbca7c062", "metadata": { "execution": { "iopub.execute_input": "2024-11-01T20:18:28.467089Z", "iopub.status.busy": "2024-11-01T20:18:28.467014Z", "iopub.status.idle": "2024-11-01T20:18:28.816558Z", "shell.execute_reply": "2024-11-01T20:18:28.816117Z" } }, "outputs": [], "source": [ "import pandas as pd\n", "\n", "from lets_plot import *" ] }, { "cell_type": "code", "execution_count": 2, "id": "691ff64d-5dd3-4aad-8da9-d92a3f83eaa6", "metadata": { "execution": { "iopub.execute_input": "2024-11-01T20:18:28.818049Z", "iopub.status.busy": "2024-11-01T20:18:28.817929Z", "iopub.status.idle": "2024-11-01T20:18:28.820412Z", "shell.execute_reply": "2024-11-01T20:18:28.820153Z" } }, "outputs": [ { "data": { "text/html": [ "\n", "
\n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "LetsPlot.setup_html()" ] }, { "cell_type": "code", "execution_count": 3, "id": "aab8ca98-c81e-4d5a-b968-cb149f771a99", "metadata": { "execution": { "iopub.execute_input": "2024-11-01T20:18:28.821416Z", "iopub.status.busy": "2024-11-01T20:18:28.821345Z", "iopub.status.idle": "2024-11-01T20:18:28.969205Z", "shell.execute_reply": "2024-11-01T20:18:28.968930Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(234, 12)\n" ] }, { "data": { "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", "
Unnamed: 0manufacturermodeldisplyearcyltransdrvctyhwyflclass
01audia41.819994auto(l5)f1829pcompact
12audia41.819994manual(m5)f2129pcompact
23audia42.020084manual(m6)f2031pcompact
\n", "
" ], "text/plain": [ " Unnamed: 0 manufacturer model displ year cyl trans drv cty hwy \\\n", "0 1 audi a4 1.8 1999 4 auto(l5) f 18 29 \n", "1 2 audi a4 1.8 1999 4 manual(m5) f 21 29 \n", "2 3 audi a4 2.0 2008 4 manual(m6) f 20 31 \n", "\n", " fl class \n", "0 p compact \n", "1 p compact \n", "2 p compact " ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df = pd.read_csv(\"https://raw.githubusercontent.com/JetBrains/lets-plot-docs/master/data/mpg.csv\")\n", "print(df.shape)\n", "df.head(3)" ] }, { "cell_type": "code", "execution_count": 4, "id": "6846eed1-fd9b-412e-859f-27d3efcae9fa", "metadata": { "execution": { "iopub.execute_input": "2024-11-01T20:18:28.970293Z", "iopub.status.busy": "2024-11-01T20:18:28.970217Z", "iopub.status.idle": "2024-11-01T20:18:29.004708Z", "shell.execute_reply": "2024-11-01T20:18:29.004319Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Default plot\n", "ggplot(df, aes(\"displ\", \"hwy\")) + \\\n", " geom_point(color=\"#878787\") + \\\n", " geom_smooth(method='loess', se=False, color=\"#2166ac\") + \\\n", " geom_smooth(method='lm', se=False, color=\"#b2182b\")" ] }, { "cell_type": "markdown", "id": "2484e977", "metadata": {}, "source": [ "#### 1. Simple Custom Legend" ] }, { "cell_type": "code", "execution_count": 5, "id": "5d1579df-2a77-49d4-8ad5-c581adc69cde", "metadata": { "execution": { "iopub.execute_input": "2024-11-01T20:18:29.005774Z", "iopub.status.busy": "2024-11-01T20:18:29.005693Z", "iopub.status.idle": "2024-11-01T20:18:29.011582Z", "shell.execute_reply": "2024-11-01T20:18:29.011406Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ggplot(df, aes(\"displ\", \"hwy\")) + \\\n", " geom_point(color=\"#878787\",\n", " manual_key=\"Observed Data\" # label for the legend entry\n", " ) + \\\n", " geom_smooth(method='loess', se=False, color=\"#2166ac\",\n", " manual_key=\"LOESS Trend Line\") + \\\n", " geom_smooth(method='lm', se=False, color=\"#b2182b\",\n", " manual_key=\"Linear Model Trend Line\") + \\\n", " ggsize(800, 400)" ] }, { "cell_type": "markdown", "id": "c7ccb30b", "metadata": {}, "source": [ "#### 2. The `layer_key()` Function" ] }, { "cell_type": "markdown", "id": "d7fdc147", "metadata": {}, "source": [ "All constants for the visual representation of the legend key are inherited from the geometry. Use the `layer_key()` function to override these values. You can also specify the legend group in which the element is displayed and the position of the element within the legend group." ] }, { "cell_type": "code", "execution_count": 6, "id": "03ef5cac", "metadata": { "execution": { "iopub.execute_input": "2024-11-01T20:18:29.012533Z", "iopub.status.busy": "2024-11-01T20:18:29.012462Z", "iopub.status.idle": "2024-11-01T20:18:29.018640Z", "shell.execute_reply": "2024-11-01T20:18:29.018471Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p = ggplot(df, aes(\"displ\", \"hwy\")) + \\\n", " geom_point(color=\"#878787\",\n", " manual_key=layer_key(\"Observed Data\", # <-- label for the legend entry\n", " color='pen', size=8) # <-- override aesthetics\n", " ) + \\\n", " geom_smooth(method='loess', se=False, color=\"#2166ac\",\n", " manual_key=layer_key(\"LOESS\", \n", " group=\"Methods\", # <-- assign a group (note the same group in the layer below)\n", " index=1, # <-- position of the element\n", " size=4)) + \\\n", " geom_smooth(method='lm', se=False, color=\"#b2182b\",\n", " manual_key=layer_key(\"LM\", group=\"Methods\", index=0, size=4)) + \\\n", " ggsize(800, 400)\n", "p" ] }, { "cell_type": "markdown", "id": "f2033efb", "metadata": {}, "source": [ "#### 3. Change Title of Custom Legends" ] }, { "cell_type": "code", "execution_count": 7, "id": "7c1173c8", "metadata": { "execution": { "iopub.execute_input": "2024-11-01T20:18:29.019520Z", "iopub.status.busy": "2024-11-01T20:18:29.019451Z", "iopub.status.idle": "2024-11-01T20:18:29.024870Z", "shell.execute_reply": "2024-11-01T20:18:29.024693Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "p + labs(\n", " manual=\"Scatter Plot\", # <-- \"manual\" is a default 'key' referring to a custom legend\n", " Methods=\"Trend Lines\" # <-- \"Methods\" is the group name referring to the second custom legend\n", ")" ] }, { "cell_type": "markdown", "id": "5886f899-d8d7-4875-a638-890594cd5284", "metadata": {}, "source": [ "#### 4. Compound Legend Entries in Custom Legend" ] }, { "cell_type": "code", "execution_count": 8, "id": "05e5a0b8-1f11-484c-ac6a-f15e435d7a5a", "metadata": { "execution": { "iopub.execute_input": "2024-11-01T20:18:29.025773Z", "iopub.status.busy": "2024-11-01T20:18:29.025704Z", "iopub.status.idle": "2024-11-01T20:18:29.036489Z", "shell.execute_reply": "2024-11-01T20:18:29.036315Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ggplot(mapping=aes(as_discrete('class', order_by='..y..'), 'hwy')) + \\\n", " stat_summary(data=df[df.year == 1999], fun='mean', # <-- 1999\n", " geom='line', size=2, color='#D87093',\n", " manual_key=\"1999\" # <-- label for the legend entry\n", " ) + \\\n", " stat_summary(data=df[df.year == 1999], fun='mean',\n", " geom='point', size=5, shape=22,\n", " fill='#D87093', color='paper',\n", " manual_key=layer_key(\"1999\", # <-- Using the same label as above results in a composite entry in the legend\n", " size=3)) + \\\n", " stat_summary(data=df[df.year == 2008], fun='mean', # <-- 2008\n", " geom='line', size=2, color='#708090',\n", " manual_key=\"2008\") + \\\n", " stat_summary(data=df[df.year == 2008], fun='mean',\n", " geom='point', size=7, shape=23, fill='#708090', color='paper',\n", " manual_key=layer_key(\"2008\", size=5)) + \\\n", " guides(manual=guide_legend(\n", " override_aes=dict(stroke=0, # <-- remove `stroke` in the \"manual\" legend\n", " size=1) # <-- update `size` if not specified otherwise in the layer itself\n", " )) + \\\n", " ggsize(800, 400) + \\\n", " theme(legend_position=[0.9, 0.95], legend_justification=[1, 1],\n", " legend_direction='horizontal',\n", " legend_background=element_rect(size=1, linetype='dotted'))" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.13" } }, "nbformat": 4, "nbformat_minor": 5 }