{ "cells": [ { "cell_type": "markdown", "id": "b2140b01-8d31-42a4-8e24-55554e7e8330", "metadata": {}, "source": [ "# Dynamic Text Positioning with Repel Geometries\n", "\n", "- `geom_text_repel()`\n", "- `geom_label_repel()`\n", "\n", "These functions use a force-based layout algorithm to automatically reposition text labels and resolve overlaps. \n", "\n", "Labels repel each other and their associated data points while staying within the plot boundaries." ] }, { "cell_type": "code", "execution_count": 1, "id": "34f575a0-f8e0-429c-8294-6bd2a4a30e00", "metadata": {}, "outputs": [], "source": [ "import random\n", "\n", "import pandas as pd\n", "\n", "from lets_plot import *" ] }, { "cell_type": "code", "execution_count": 2, "id": "b9b2146f-bc73-4bab-ae23-225c68729760", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "LetsPlot.setup_html()" ] }, { "cell_type": "code", "execution_count": 3, "id": "50f4ffd6-e3d4-4c21-ae02-f396cba7ada1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(32, 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", " \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", "
modelmpgcyldisphpdratwtqsecvsamgearcarb
0Mazda RX421.06160.01103.902.62016.460144
1Mazda RX4 Wag21.06160.01103.902.87517.020144
2Datsun 71022.84108.0933.852.32018.611141
3Hornet 4 Drive21.46258.01103.083.21519.441031
4Hornet Sportabout18.78360.01753.153.44017.020032
\n", "
" ], "text/plain": [ " model mpg cyl disp hp drat wt qsec vs am gear \\\n", "0 Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 \n", "1 Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 \n", "2 Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 \n", "3 Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 \n", "4 Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 \n", "\n", " carb \n", "0 4 \n", "1 4 \n", "2 1 \n", "3 1 \n", "4 2 " ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df = pd.read_csv(\"https://gist.githubusercontent.com/seankross/a412dfbd88b3db70b74b/raw/5f23f993cd87c283ce766e7ac6b329ee7cc2e1d1/mtcars.csv\")\n", "print(df.shape)\n", "df.head()" ] }, { "cell_type": "code", "execution_count": 4, "id": "6638e58c-dcae-436f-abba-422178bdf1a9", "metadata": {}, "outputs": [], "source": [ "df1 = df[(2.0 < df[\"wt\"])&(df[\"wt\"] < 3.65)]\n", "df2 = df[(2.0 < df[\"wt\"])&(df[\"wt\"] < 3)]\n", "df2 = df2.assign(shape=df2[\"am\"].map({0: 16, 1: 21}))" ] }, { "cell_type": "code", "execution_count": 5, "id": "acb7916c-7095-439e-a6dc-dfcac077fc58", "metadata": {}, "outputs": [], "source": [ "plot = ggplot(df1, aes(\"wt\", \"mpg\", label=\"model\")) + geom_point(color=\"red\")\n", "plot2 = ggplot(df2, aes(\"wt\", \"mpg\", label=\"model\")) + geom_point(color=\"red\")" ] }, { "cell_type": "markdown", "id": "97356a4c-dde7-4525-a556-ad5f7192afd0", "metadata": {}, "source": [ "### Comparison of geom_text() and geom_text_repel()" ] }, { "cell_type": "code", "execution_count": 6, "id": "0da4f37a-74b6-446e-9eaa-ecc7e9046641", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gggrid([\n", " plot2 + geom_text() + ggtitle(\"geom_text()\"),\n", " plot2 + geom_text_repel() + ggtitle(\"geom_text_repel()\"),\n", "])" ] }, { "cell_type": "markdown", "id": "30d0b785-0163-4821-80c1-684b2e7a7a1f", "metadata": {}, "source": [ "### geom_label_repel()\n", "All of the parameters discussed below apply equally to both `geom_text_repel()` and `geom_label_repel()`. For simplicity, we will use `geom_text_repel()` in the examples." ] }, { "cell_type": "code", "execution_count": 7, "id": "2627852d-8284-4519-9502-de96ef857bfb", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gggrid([\n", " plot2 + geom_label() + ggtitle(\"geom_label()\"),\n", " plot2 + geom_label_repel() + ggtitle(\"geom_label_repel()\"),\n", "])" ] }, { "cell_type": "markdown", "id": "b83eca55-966b-4d05-8477-b91bff16d837", "metadata": {}, "source": [ "### `seed` parameter\n", "\n", "Controls the randomization to produce the same label layout each time the plot is generated." ] }, { "cell_type": "code", "execution_count": 8, "id": "aa5200af-0a78-43d2-bb9b-f1b548abb70a", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gggrid([\n", " plot2 + geom_text_repel() + ggtitle(\"Without seed\"),\n", " plot2 + geom_text_repel() + ggtitle(\"Without seed\"),\n", " plot2 + geom_text_repel(seed=4) + ggtitle(\"With seed\"),\n", " plot2 + geom_text_repel(seed=4) + ggtitle(\"With seed\"),\n", "], ncol=2)" ] }, { "cell_type": "markdown", "id": "908712ac-dc44-4eaa-bfc7-1beb9d0bb0f5", "metadata": {}, "source": [ "In some cases, it may be necessary to find a seed value that produces a more optimal label arrangement. A simple approach is to re-render the plot multiple times until you're satisfied with the result, then use the corresponding seed to reproduce it." ] }, { "cell_type": "code", "execution_count": 9, "id": "874c8830-5655-44b0-8276-bdb2712e1240", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "seed = 96\n" ] }, { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rand_int = random.randint(1, 1000)\n", "print(\"seed = {0}\".format(rand_int))\n", "plot2 + geom_text_repel(seed=rand_int)" ] }, { "cell_type": "markdown", "id": "a35f377a-7d23-4b98-afa1-d2578dde1482", "metadata": {}, "source": [ "### `max_iter` parameter\n", "Controls the maximum number of iterations used by the layout algorithm, helping to reduce notebook rendering time. More iterations generally lead to better label placement, but at the cost of increased computation time. For plots with a small number of labels, 200–300 iterations are often sufficient.\n", "The default value is 2000." ] }, { "cell_type": "code", "execution_count": 10, "id": "0ee3828f-6593-47be-a071-e5fca226211e", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "seed = 530\n", "gggrid([\n", " plot2 + geom_text_repel(seed=seed, max_iter=2) + ggtitle(\"max_iter=2\"),\n", " plot2 + geom_text_repel(seed=seed, max_iter=20) + ggtitle(\"max_iter=20\"),\n", " plot2 + geom_text_repel(seed=seed, max_iter=200) + ggtitle(\"max_iter=200\"),\n", "])" ] }, { "cell_type": "markdown", "id": "bd59ec93-6f1e-4448-812b-f90aea28a038", "metadata": {}, "source": [ "### `max_time` parameter\n", "Another way to limit plot rendering time is by using the `max_time` parameter. This primarily serves as a safeguard against excessive computation when a large number of text labels are involved. Time is specified in seconds. The default value is `5` seconds, but you can disable the time limit by setting it to `-1` if needed." ] }, { "cell_type": "code", "execution_count": 11, "id": "dcfd9714-c1c2-458c-a89d-71329b5b7b4b", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gggrid([\n", " plot2 + geom_text_repel(seed=seed, max_time=0.001) + ggtitle(\"max_time=0.001\"),\n", " plot2 + geom_text_repel(seed=seed, max_time=0.01) + ggtitle(\"max_time=0.01\"),\n", " plot2 + geom_text_repel(seed=seed, max_time=-1) + ggtitle(\"max_time=-1\"),\n", "])" ] }, { "cell_type": "markdown", "id": "49079841-b0f0-4df4-8a1f-b3aba4a234e7", "metadata": {}, "source": [ "### `direction` parameter\n", "Restricts the movement of a text label relative to its anchor point to a specific direction. The default value is `both`." ] }, { "cell_type": "code", "execution_count": 12, "id": "589f1340-4ba2-40f1-a9aa-147cbbdb7ee1", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gggrid([\n", " plot2 + geom_text_repel(seed=seed, direction=\"x\") + ggtitle(\"direction = 'x'\"),\n", " plot2 + geom_text_repel(seed=seed, direction=\"y\") + ggtitle(\"direction = 'y'\"),\n", " plot2 + geom_text_repel(seed=seed, direction=\"both\") + ggtitle(\"direction = 'both'\"),\n", "])" ] }, { "cell_type": "markdown", "id": "a37b70bf-1170-48b3-8374-e6ad1363b1e9", "metadata": {}, "source": [ "As we can see, this option is of limited use for randomly scattered points, but in certain cases it can be extremely helpful:" ] }, { "cell_type": "code", "execution_count": 13, "id": "8fef4a4f-6b1b-4d81-bb61-d508d51991c9", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "plotX = ggplot(df2, aes(x=\"wt\", label=\"model\")) + \\\n", " geom_point(y=1, color=\"red\") + xlim(2, 3) + ylim(1, 1.3) + \\\n", " geom_text_repel(\n", " y=1,\n", " nudge_y=0.05,\n", " direction=\"x\",\n", " angle=90,\n", " hjust=0.0,\n", " seed=seed\n", " )\n", "\n", "plotY = ggplot(df2, aes(y=\"mpg\", label=\"model\")) + \\\n", " geom_point(x=1, color=\"red\") + xlim(0.9, 1.3) + ylim(19, 35) + \\\n", " geom_text_repel(\n", " x=1,\n", " nudge_x=0.05,\n", " direction=\"y\",\n", " hjust=0.0,\n", " seed=seed\n", " )\n", "\n", "gggrid([\n", " plotX + ggtitle(\"direction = x\"),\n", " plotY + ggtitle(\"direction = y\"),\n", "])" ] }, { "cell_type": "markdown", "id": "8ec061ed-2cef-4cf9-943b-559d75331cef", "metadata": {}, "source": [ "### `point_padding` and `box_padding` parameters\n", "These parameters control the amount of spacing around text labels.\n", "\n", "- `point_padding` adds space between the label and all nearby points, but does not affect spacing between labels.\n", "\n", "- `box_padding` adds space between labels, but does not affect spacing between the label and the data point." ] }, { "cell_type": "code", "execution_count": 14, "id": "ce03a3bc-bd16-41ac-afbb-a9829e6b8edc", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gggrid([\n", " plot2 + geom_text_repel(seed=seed, max_time=-1, point_padding=10) + ggtitle(\"point_padding\"),\n", " plot2 + geom_text_repel(seed=seed, max_time=-1, box_padding=10) + ggtitle(\"box_padding\"),\n", "])" ] }, { "cell_type": "markdown", "id": "eaf3c33e-69d8-4fc1-8a67-ec58a7446db7", "metadata": {}, "source": [ "### `max_overlaps` parameter\n", "Specifies the maximum allowed number of overlaps with other labels. Labels that exceed this threshold will be omitted from the plot. The default value is `10`. You can disable overlap filtering entirely by setting this parameter to `-1`." ] }, { "cell_type": "code", "execution_count": 15, "id": "f1d9ba30-017d-461d-aa20-8494d79d295c", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gggrid([\n", " plot + geom_text_repel(seed=seed, max_time=-1, max_overlaps=5) + ggtitle(\"max_overlaps=5\"),\n", " plot + geom_text_repel(seed=seed, max_time=-1, max_overlaps=-1) + ggtitle(\"max_overlaps=-1\"),\n", "])" ] }, { "cell_type": "markdown", "id": "47324195-4a22-45f7-9d21-361513c17f52", "metadata": {}, "source": [ "### `min_segment_length` parameter\n", "Sets the minimum length for the line connecting a label to its associated point. Lines shorter than this length will not be drawn. To display all lines, use the default value of `0`. To hide all lines, set the value to something very large. \n", "`min_segment_length` uses the same units as `point_size`, so be careful when using `min_segment_length` together with `size_unit` (see below)." ] }, { "cell_type": "code", "execution_count": 16, "id": "5fff83c2-2fa4-4ae4-a339-cb70cc63789f", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gggrid([\n", " plot + geom_text_repel(seed=seed, max_time=-1, min_segment_length=0) + ggtitle(\"min_segment_length=0\"),\n", " plot + geom_text_repel(seed=seed, max_time=-1, min_segment_length=9999) + ggtitle(\"min_segment_length=9999\"),\n", "])" ] }, { "cell_type": "markdown", "id": "ecca61f5-a3d3-4089-b7ee-01386958859c", "metadata": {}, "source": [ "## Point settings\n", "geom_text_repel() does not draw points itself, but for it to work correctly, the values of parameters and aesthetics that control point size must match those used in the associated geom_point() layer." ] }, { "cell_type": "code", "execution_count": 17, "id": "bfd8bdbf-ca61-4eb7-872a-419fd27209a1", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ggplot(df2, aes(\"wt\", \"mpg\", label=\"model\")) + theme(legend_position=\"none\") + \\\n", " scale_size(range=[0.5,1], guide=\"none\") + \\\n", " scale_stroke(range=[1,4], guide=\"none\") + \\\n", " scale_shape_identity() + \\\n", " geom_point(aes(size=\"gear\", stroke=\"vs\", shape=\"shape\"), size_unit=\"y\") + \\\n", " geom_text_repel(aes(point_size=\"gear\", point_stroke=\"vs\", shape=\"shape\"), size_unit=\"y\")" ] }, { "cell_type": "markdown", "id": "3f709351-1504-4032-8ef2-faf64e2d56c1", "metadata": {}, "source": [ "### `point_size` aesthetic\n", "Allows you to pass to geom_text_repel() the data used to determine point sizes in a geom_point() layer. This helps accurately detect overlaps between labels and points when point sizes vary." ] }, { "cell_type": "code", "execution_count": 18, "id": "1367ee72-0292-44e3-8dcd-4067d599183f", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "plot31 = ggplot(df2, aes(\"wt\", \"mpg\", label=\"model\")) + \\\n", " geom_point(aes(size=\"gear\"), color=\"red\") + \\\n", " theme(legend_position=\"none\")\n", "\n", "gggrid([\n", " plot31 + geom_text_repel(seed=seed, max_time=-1) + ggtitle(\"without point_size\"),\n", " plot31 + geom_text_repel(aes(point_size=\"gear\"), seed=seed, max_time=-1) + ggtitle(\"with point_size\"),\n", "])" ] }, { "cell_type": "markdown", "id": "f8ec34b0-55d0-4b66-ac69-63472876b8a3", "metadata": {}, "source": [ "You can also provide a constant value instead." ] }, { "cell_type": "code", "execution_count": 19, "id": "b05d47af-2143-4180-9b91-443eb99c7532", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "plot32 = ggplot(df2, aes(\"wt\", \"mpg\", label=\"model\")) + \\\n", " geom_point(size=10, color=\"red\") + \\\n", " theme(legend_position=\"none\")\n", "\n", "gggrid([\n", " plot32 + geom_text_repel(seed=seed, max_time=-1) + ggtitle(\"without point_size\"),\n", " plot32 + geom_text_repel(seed=seed, max_time=-1, point_size=10) + ggtitle(\"with point_size\"),\n", "])" ] }, { "cell_type": "markdown", "id": "9c1876f6-58c8-47b3-b0cf-497d4cbcd3fd", "metadata": {}, "source": [ "### `point_stroke` and `shape` aesthetics\n", "Allow you to pass to geom_text_repel() the data used to determine point stroke width and shape in a geom_point() layer. This ensures accurate collision detection between labels and points." ] }, { "cell_type": "code", "execution_count": 20, "id": "d24823db-4c33-4038-bac6-18d19a5cae76", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "plot33 = ggplot(df2, aes(\"wt\", \"mpg\", label=\"model\")) + \\\n", " geom_point(aes(stroke=\"gear\"), shape=21, size=10, color=\"red\") + \\\n", " theme(legend_position=\"none\")\n", "\n", "gggrid([\n", " plot33 + geom_text_repel(seed=seed, max_time=-1, point_size=10) + ggtitle(\"without point_stroke\"),\n", " plot33 + geom_text_repel(aes(point_stroke=\"gear\"), shape=21, point_size=10, seed=seed, max_time=-1) + ggtitle(\"with point_stroke\"),\n", "])" ] }, { "cell_type": "markdown", "id": "09607d66-dc01-45a6-95f5-4025c90cf3db", "metadata": {}, "source": [ "### `size_unit` parameter\n", "The `size_unit` parameter can be used in `geom_point()` to define the unit of measurement for the `size` aesthetic. In this case, it is recommended to also use `size_unit` in `geom_text_repel()` to ensure that point sizes are calculated correctly." ] }, { "cell_type": "code", "execution_count": 21, "id": "2583f8f2-0863-4096-9fdd-6b5905b3ccb4", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "plot4 = ggplot(df2, aes(\"wt\", \"mpg\", label=\"model\")) + \\\n", " geom_point(size=1, size_unit=\"y\", color=\"red\") + \\\n", " theme(legend_position=\"none\")\n", "\n", "gggrid([\n", " plot4 + geom_text_repel(seed=seed, max_time=-1, point_size=1) + ggtitle(\"without size_unit\"),\n", " plot4 + geom_text_repel(seed=seed, max_time=-1, point_size=1, size_unit=\"y\") + ggtitle(\"with size_unit\"),\n", "]) + ggtb()" ] }, { "cell_type": "markdown", "id": "aa3c5afa-4c9e-494e-876e-a452bbade1f2", "metadata": {}, "source": [ "##### `size_unit` applies to all size-related parameters: `point_size`, `min_segment_length`, `point_padding`, and `box_padding`.\n", "As an example, consider how it affects `min_segment_length`.\n", "As mentioned earlier, `min_segment_length` uses the same units as `point_size`. Therefore, in the following example, with the same `min_segment_length` value, some lines are not drawn in the second case because their length is less than one unit along the y-axis. " ] }, { "cell_type": "code", "execution_count": 22, "id": "5d6e94db-aaeb-433a-9d0c-588b20df2b7c", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "plot5 = ggplot(df2, aes(\"wt\", \"mpg\", label=\"model\")) + \\\n", " theme(legend_position=\"none\")\n", "\n", "gggrid([\n", " plot5 + geom_point(size=10, color=\"red\") + \\\n", " geom_text_repel(seed=seed, max_time=-1, point_size=10, min_segment_length=1) + ggtitle(\"without size_unit\"),\n", " plot5 + geom_point(size=1, size_unit=\"y\", color=\"red\") + \\\n", " geom_text_repel(seed=seed, max_time=-1, point_size=1, min_segment_length=1, size_unit=\"y\") + ggtitle(\"with size_unit\"),\n", "]) + ggtb()" ] }, { "cell_type": "markdown", "id": "1a690ee7-f3c6-40b5-9ba8-c2cca1071d12", "metadata": {}, "source": [ "### `segment_color` aesthetic\n", "Allows you to specify the color of the line connecting the label to the point. By default, the line color matches the text color and follows the `color` aesthetic. In the example below, the `color` aesthetic is defined globally for all layers, so the colors of the points, text, and lines are the same." ] }, { "cell_type": "code", "execution_count": 23, "id": "5f0c68b0-9fe3-4b05-a38a-97e72f3a6982", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ggplot(df2, aes(\"wt\", \"mpg\", label=\"model\", color=\"wt\")) + geom_point() + geom_text_repel(seed=seed, max_time=-1)" ] }, { "cell_type": "markdown", "id": "7f754541-b3f3-40eb-8c98-8b47d36a52b4", "metadata": {}, "source": [ "By using the `color` and `segment_color` aesthetics together, you can assign different colors to the points, labels, and connecting lines." ] }, { "cell_type": "code", "execution_count": 24, "id": "fb63f805-e8f7-4659-9e63-58204e6687fe", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "plot6 = ggplot(df2, aes(\"wt\", \"mpg\", label=\"model\")) + theme(legend_position=\"none\")\n", "\n", "gggrid([\n", " plot6 + geom_point(aes(color=\"wt\")) + \\\n", " geom_text_repel(aes(segment_color=\"wt\"), seed=seed, max_time=-1) + \\\n", " ggtitle(\"Same color for points and lines\"),\n", " plot6 + geom_point(color=\"red\") + \\\n", " geom_text_repel(aes(color=\"wt\"), seed=seed, max_time=-1) + \\\n", " ggtitle(\"Same color for text and line\"),\n", " plot6 + geom_point(color=\"red\") + \\\n", " geom_text_repel(color=\"green\", segment_color=\"blue\", seed=seed, max_time=-1) + \\\n", " ggtitle(\"Different colors\"),\n", "])" ] }, { "cell_type": "markdown", "id": "ffb9a3a3-9b7d-4992-8b92-19110dbec779", "metadata": {}, "source": [ "### `segment_alpha` aesthetic\n", "\n", "Specifies the transparency level of the connecting lines between labels and points. By default, the segment transparency inherits from the text and is governed by the `alpha` aesthetic." ] }, { "cell_type": "code", "execution_count": 25, "id": "2cb10f04-5bef-48bd-a372-b42f3c2886da", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ggplot(df2, aes(\"wt\", \"mpg\", label=\"model\")) + \\\n", " geom_point(color=\"red\") + \\\n", " geom_text_repel(point_padding=20, color=\"red\", segment_alpha=0.1, seed=seed, max_time=-1)" ] }, { "cell_type": "markdown", "id": "2cd0c4ae-be63-4c33-a737-31f4de949fc7", "metadata": {}, "source": [ "### `segment_size` aesthetic\n", "Specifies the width of the line connecting the label to the point." ] }, { "cell_type": "code", "execution_count": 26, "id": "2f162719-ee63-424e-aaf8-c9ac6f5f16fa", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "plot2 + geom_text_repel(segment_size=2, seed=seed, max_time=-1)" ] }, { "cell_type": "markdown", "id": "23c9c90b-33b1-4bab-891d-fef1d7939864", "metadata": {}, "source": [ "### `linetype` aesthetic" ] }, { "cell_type": "code", "execution_count": 27, "id": "d65b9302-fd71-4dbf-b1e1-bf4b9e8e5eb9", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ggplot(df2, aes(y=\"mpg\", label=\"model\")) + geom_point(x=1, color=\"red\") + xlim(0.9, 1.3) + ylim(19, 35) + \\\n", " geom_text_repel(\n", " aes(linetype=\"disp\"),\n", " x=1,\n", " nudge_x=0.2,\n", " direction=\"y\",\n", " hjust=0.0,\n", " seed=seed\n", " )" ] }, { "cell_type": "markdown", "id": "8bb05dcb-f739-4fa6-8757-5cd392980e2b", "metadata": {}, "source": [ "### `arrow` parameter" ] }, { "cell_type": "code", "execution_count": 28, "id": "3efa1905-e56b-4ed6-9bc5-4b4caa43e7dc", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ggplot(df2, aes(y=\"mpg\", label=\"model\")) + geom_point(x=1, color=\"red\") + xlim(0.9, 1.3) + ylim(19, 35) + \\\n", " geom_text_repel(\n", " x=1,\n", " nudge_x=0.2,\n", " direction=\"y\",\n", " hjust=0.0,\n", " arrow=arrow(type=\"closed\", angle=10, ends=\"both\"),\n", " seed=seed\n", " )" ] } ], "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.9.23" } }, "nbformat": 4, "nbformat_minor": 5 }