{ "cells": [ { "cell_type": "markdown", "id": "1d545ad9-74df-48f7-b01f-d64b190032d7", "metadata": {}, "source": [ "# Parameter `width_unit` (`height_unit`)" ] }, { "cell_type": "code", "execution_count": 1, "id": "4b338c6c-a670-4ecb-a5d1-efa684f99a64", "metadata": {}, "outputs": [], "source": [ "from math import sqrt\n", "\n", "import numpy as np\n", "import pandas as pd\n", "\n", "from lets_plot import *" ] }, { "cell_type": "code", "execution_count": 2, "id": "39f23513-c6f0-465b-b0ea-7b2bd7302a04", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", " \n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "LetsPlot.setup_html()" ] }, { "cell_type": "code", "execution_count": 3, "id": "9a6514a3-bdbb-4940-adb6-c8a54a527a2a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(234, 13)\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", " \n", " \n", " \n", " \n", " \n", " \n", "
Unnamed: 0manufacturermodeldisplyearcyltransdrvctyhwyflclasstrans_type
01audia41.819994auto(l5)f1829pcompactauto
12audia41.819994manual(m5)f2129pcompactmanual
23audia42.020084manual(m6)f2031pcompactmanual
34audia42.020084auto(av)f2130pcompactauto
45audia42.819996auto(l5)f1626pcompactauto
\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", "3 4 audi a4 2.0 2008 4 auto(av) f 21 30 \n", "4 5 audi a4 2.8 1999 6 auto(l5) f 16 26 \n", "\n", " fl class trans_type \n", "0 p compact auto \n", "1 p compact manual \n", "2 p compact manual \n", "3 p compact auto \n", "4 p compact auto " ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df = pd.read_csv(\"https://raw.githubusercontent.com/JetBrains/lets-plot-docs/refs/heads/master/data/mpg.csv\")\n", "df[\"trans_type\"] = df[\"trans\"].str.split(\"(\").str[0]\n", "print(df.shape)\n", "df.head()" ] }, { "cell_type": "markdown", "id": "9e024bce-3f52-4b0b-992f-0110bb1bbed7", "metadata": {}, "source": [ "## Case 1: Uniform Width" ] }, { "cell_type": "markdown", "id": "cd3aedc6-ce00-4daa-8263-67087dd7ad65", "metadata": {}, "source": [ "Suppose we have the following plot, but we are not satisfied that different facets have different whisker widths:" ] }, { "cell_type": "code", "execution_count": 4, "id": "cdb5b479-3226-4358-adce-5285f2101806", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ggplot(df) + \\\n", " geom_errorbar(aes(as_discrete(\"trans\", order=1), \"hwy\", color=\"trans_type\"),\n", " stat='summary', size=1, width=.5) + \\\n", " facet_grid(x=\"year\", scales=\"free_x\")" ] }, { "cell_type": "markdown", "id": "c6207b00-c441-40b2-9527-bfa668bb1a64", "metadata": {}, "source": [ "We can make the widths uniform by setting the absolute unit of measurement for them.\n", "For example, in pixels:" ] }, { "cell_type": "code", "execution_count": 5, "id": "6630f918-1b45-419c-a97a-9a1193093543", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Set width=30 and width_unit=\"px\"\n", "ggplot(df) + \\\n", " geom_errorbar(aes(as_discrete(\"trans\", order=1), \"hwy\", color=\"trans_type\"),\n", " stat='summary', size=1, width=30, width_unit=\"px\") + \\\n", " facet_grid(x=\"year\", scales=\"free_x\")" ] }, { "cell_type": "markdown", "id": "53584451-20be-4901-a132-78410442dc76", "metadata": {}, "source": [ "## Case 2: Matching the Grid" ] }, { "cell_type": "markdown", "id": "7d829c9f-f3f0-4af5-9957-887fe0364502", "metadata": {}, "source": [ "When using `geom_hex()` with the `'identity'` statistic, you must prepare the data yourself to fit into a hexagonal grid.\n", "\n", "Let's assume you have prepared the following dataset:" ] }, { "cell_type": "code", "execution_count": 6, "id": "6b46eb0b-5ac4-4e78-ac61-99a91b857b33", "metadata": {}, "outputs": [ { "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", "
xyvg
00.000.374540group 0
51.040.708073group 0
20.040.156019group 0
155.000.785176group 0
134.020.292145group 0
\n", "
" ], "text/plain": [ " x y v g\n", "0 0.0 0 0.374540 group 0\n", "5 1.0 4 0.708073 group 0\n", "2 0.0 4 0.156019 group 0\n", "15 5.0 0 0.785176 group 0\n", "13 4.0 2 0.292145 group 0" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def get_data(n, m, sizes, seed=42):\n", " np.random.seed(seed)\n", " def generate_full_dataset():\n", " return pd.DataFrame({\n", " 'x': np.repeat(np.arange(n), m) + np.tile(([0, .5] * m)[:m], n),\n", " 'y': np.tile(np.arange(m), n),\n", " 'v': np.random.uniform(size=m*n),\n", " })\n", " def get_random_sample(df, size, reg=False):\n", " if reg:\n", " df = df[df['y'] % 2 == 0].sort_values(by=['x', 'y']).reset_index(drop=True)\n", " return df.sample(min(df.shape[0], size))\n", " return pd.concat([\n", " get_random_sample(generate_full_dataset(), size, reg=i==0).assign(g=\"group {0}\".format(i))\n", " for i, size in enumerate(sizes)\n", " ])\n", "\n", "df = get_data(6, 5, [8, 9, 7])\n", "df.head()" ] }, { "cell_type": "markdown", "id": "c11f5d92-f7af-458f-b161-799a9f305ff5", "metadata": {}, "source": [ "The Lets-Plot tries to choose the sizes of the hexagons by itself, but in some situations the result may be unsatisfactory, as in the plot below. Namely in the facet with 'group 0', the hexagons are too large to fit into the grid:" ] }, { "cell_type": "code", "execution_count": 7, "id": "d2ae02bd-4bc1-494b-a4c9-da0b9d274889", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ggplot(df, aes('x', 'y', fill='v')) + \\\n", " geom_hex(stat='identity', size=.5) + \\\n", " facet_wrap(facets='g', nrow=1)" ] }, { "cell_type": "markdown", "id": "132da132-4286-4460-be7d-4fbb616ad403", "metadata": {}, "source": [ "In this case, simply resizing the hexagons is not enough. The default unit for width and height is `'res'`, and it depends on the resolution (minimum distance between hexagon centers) in a given facet:" ] }, { "cell_type": "code", "execution_count": 8, "id": "80c62628-e282-4dcb-9cac-78d7391e574d", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ggplot(df, aes('x', 'y', fill='v')) + \\\n", " geom_hex(stat='identity', size=.5,\n", " width=.5, height=.5) + \\\n", " facet_wrap(facets='g', nrow=1)" ] }, { "cell_type": "markdown", "id": "1447e335-7dc2-4afa-bc44-9795db9a728c", "metadata": {}, "source": [ "However, you can change the units of measurement. If `width_unit='identity'`, the width of the hexagons will be expressed in X-axis units, and similarly for the height:" ] }, { "cell_type": "code", "execution_count": 9, "id": "ce65d6e6-1582-4687-ac4a-1def2a519aca", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ggplot(df, aes('x', 'y', fill='v')) + \\\n", " geom_hex(stat='identity', size=.5,\n", " width_unit='identity', width=1,\n", " height_unit='identity', height=2/sqrt(3)) + \\\n", " facet_wrap(facets='g', nrow=1)" ] }, { "cell_type": "markdown", "id": "192805b9-42f3-4c7d-a97b-cc66d040f9fa", "metadata": {}, "source": [ "## Possible Values" ] }, { "cell_type": "markdown", "id": "0b47f418-4f00-43f0-bbb2-4bbef21344bc", "metadata": {}, "source": [ "The `width_unit` (or `height_unit`) parameter can take the following values:\n", "\n", "- `'res'`: value 1 corresponds to the resolution along the axis, i.e. the minimum distance between data points;\n", "\n", "- `'identity'`: value 1 corresponds to the distance from 0 to 1 on the axis;\n", "\n", "- `'size'`: value 1 corresponds to the diameter of a point of size 1;\n", "\n", "- `'px'`: value 1 corresponds to 1 pixel.\n", "\n", "Let's look at them using the example of the `geom_tile()` geometry:" ] }, { "cell_type": "code", "execution_count": 10, "id": "6dbedd33-4d89-44c9-afbf-02e03e27e455", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " " ], "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def get_plot(width, height, width_unit, height_unit):\n", " w, h = 7, 5\n", " data = {\n", " 'x': [-w, -w, w, w],\n", " 'y': [-h, h, -h, h],\n", " 'c': ['a', 'b', 'c', 'd'],\n", " }\n", " return ggplot(data, aes('x', 'y', fill='c')) + \\\n", " geom_tile(width=width, width_unit=width_unit,\n", " height=height, height_unit=height_unit,\n", " show_legend=False) + \\\n", " geom_point(shape=21, fill=\"white\") + \\\n", " coord_fixed() + \\\n", " ggtitle(\"width={w}, width_unit='{wu}'\\nheight={h}, height_unit='{hu}'\".format(\n", " w=width, wu=width_unit,\n", " h=height, hu=height_unit\n", " ))\n", "\n", "gggrid([\n", " get_plot(.9, .9, 'res', 'res'),\n", " get_plot(12, 8, 'identity', 'identity'),\n", " get_plot(100, 70, 'size', 'size'),\n", " get_plot(200, 150, 'px', 'px'),\n", "], ncol=2)" ] } ], "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.16" } }, "nbformat": 4, "nbformat_minor": 5 }