{ "cells": [ { "cell_type": "markdown", "id": "d888acdc-7426-48f2-8de0-c45c19896ff7", "metadata": {}, "source": [ "# Plotting\n", "\n", "The plotting functionality of `xyzpy` is oriented towards quickly getting an\n", "overview of high-dimensional gridded data. This is provided by a simple single\n", "method interface (with autocorrected kwargs), that allows the\n", "dimensions/coordinates to be encoded to the various visual properties in either\n", "a ***line-plot*** (the main focus), ***scatter-plot***, ***histogram***, or\n", "***heatmap***. The method is accessed (once `xyzpy` is imported) with the\n", "[`dataset.xyz.plot()`](xyzpy.plot.infiniplot.infiniplot) method. For this\n", "example we'll first generate a basic example dataset to plot, with 5 dimensions\n", "and 2 data variables:" ] }, { "cell_type": "code", "execution_count": 1, "id": "fa675011", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "100%|##########| 1836/1836 [00:00<00:00, 1544472.95it/s]\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
<xarray.Dataset> Size: 30kB\n",
       "Dimensions:  (x: 17, p: 3, delta: 6, C: 3, amp: 2)\n",
       "Coordinates:\n",
       "  * x        (x) float64 136B -2.0 -1.75 -1.5 -1.25 -1.0 ... 1.25 1.5 1.75 2.0\n",
       "  * p        (p) int64 24B 1 2 3\n",
       "  * delta    (delta) float64 48B 0.0 0.2 0.4 0.6 0.8 1.0\n",
       "  * C        (C) float64 24B -2.0 1.0 4.0\n",
       "  * amp      (amp) float64 16B -1.0 1.0\n",
       "Data variables:\n",
       "    fx       (x, p, delta, C, amp) float64 15kB 0.0 -4.0 3.0 ... 2.0 3.0 5.0\n",
       "    dfx      (x, p, delta, C, amp) float64 15kB -1.0 1.0 -1.0 ... 3.0 -3.0 3.0
" ], "text/plain": [ " Size: 30kB\n", "Dimensions: (x: 17, p: 3, delta: 6, C: 3, amp: 2)\n", "Coordinates:\n", " * x (x) float64 136B -2.0 -1.75 -1.5 -1.25 -1.0 ... 1.25 1.5 1.75 2.0\n", " * p (p) int64 24B 1 2 3\n", " * delta (delta) float64 48B 0.0 0.2 0.4 0.6 0.8 1.0\n", " * C (C) float64 24B -2.0 1.0 4.0\n", " * amp (amp) float64 16B -1.0 1.0\n", "Data variables:\n", " fx (x, p, delta, C, amp) float64 15kB 0.0 -4.0 3.0 ... 2.0 3.0 5.0\n", " dfx (x, p, delta, C, amp) float64 15kB -1.0 1.0 -1.0 ... 3.0 -3.0 3.0" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%config InlineBackend.figure_formats = ['svg']\n", "import xyzpy as xyz\n", "\n", "\n", "@xyz.label([\"fx\", \"dfx\"])\n", "def foo(x, delta, p, amp=1.0, C=0.0):\n", " # return two data variables: the function value and its derivative\n", " return (\n", " amp * (x - delta) ** p + C,\n", " amp * p * (x - delta) ** (p - 1),\n", " )\n", "\n", "\n", "ds = foo.run_combos(\n", " combos=dict(\n", " x=[-2 + i * 0.25 for i in range(17)],\n", " p=[1, 2, 3],\n", " delta=[0.0, 0.2, 0.4, 0.6, 0.8, 1.0],\n", " C=[-2.0, 1.0, 4.0],\n", " amp=[-1.0, 1.0],\n", " ),\n", ")\n", "ds" ] }, { "cell_type": "markdown", "id": "82ab54f6", "metadata": {}, "source": [ "## Plot types\n", "\n", "What options are supplied to the `x`, `y` and `z` kwargs controls what type\n", "of plot is produced:\n", "\n", "- `x` coordinate and `y` data variable: **line-plot**\n", "- `x` data variable only: **histogram**\n", "- `x` data variable and `y` data variable: **scatter-plot** (or line-plot if `xlink` is supplied)\n", "- `x` coordinate and `y` coordinate and `z` data variable: **heatmap**\n", "\n", "### Line-plots\n", "\n", "Line plots are the main focus of plotting functionality. By default every slice of data\n", "is shown as a separate line with no particular visual differentiation:" ] }, { "cell_type": "code", "execution_count": 2, "id": "e33e4623", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(x=\"x\", y=\"dfx\")" ] }, { "cell_type": "markdown", "id": "a847a80a", "metadata": {}, "source": [ "Line properties can either be set directly or mapped to a particular dimension/coordinate by supplying its name (note multiple properties can be mapped to the same dimension):" ] }, { "cell_type": "code", "execution_count": 3, "id": "6b7ab152", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(\n", " x=\"x\",\n", " y=\"dfx\",\n", " # mapped:\n", " color=\"amp\",\n", " # double mapped:\n", " marker=\"p\",\n", " linestyle=\"p\",\n", " # static:\n", " markersize=6,\n", ")" ] }, { "cell_type": "markdown", "id": "bfb62952", "metadata": {}, "source": [ "Supplying a tuple of dimension/coordinate names to a mapped property wil create\n", "a combined / fused dimension, allowing essentially an arbitrary number of\n", "dimensions to be mapped:" ] }, { "cell_type": "code", "execution_count": 4, "id": "33273c93", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(\n", " x=\"x\",\n", " y=\"dfx\",\n", " color=(\"amp\", \"p\"),\n", ")" ] }, { "cell_type": "markdown", "id": "be2bb03a", "metadata": {}, "source": [ "The kwarg `join_across_missing` controls, if data is missing, whether to skip\n", "that line section (the default) or to join across it.\n", "\n", "### Histograms\n", "\n", "Histograms simply bin a single data variable, then use the frequency /\n", "probability density as the variable supplied to a line plot (as such they\n", "support mostly the same set of options for mapping visual properties):" ] }, { "cell_type": "code", "execution_count": 5, "id": "45134bab", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(\n", " x=\"fx\",\n", " yscale=\"log\",\n", " ybase=2,\n", " color=\"green\",\n", " markeredgecolor=\"amp\",\n", " marker=\"amp\",\n", ")" ] }, { "cell_type": "markdown", "id": "1dcc5961", "metadata": {}, "source": [ "The number of bins is calculated automatically, or you can specify the number of bins (as a int) or the actual bin boundaries (as a sequence) with the `bins` kwarg. By default bin counts (frequency) are shown, but you can show probability density instead with the `bins_density: bool` kwarg:" ] }, { "cell_type": "code", "execution_count": 6, "id": "320287a8", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(\n", " x=\"fx\",\n", " bins=101,\n", " bins_density=False,\n", " color=\"p\",\n", " col=\"p\",\n", " marker=\"\",\n", " linewidth=0.5,\n", ")" ] }, { "cell_type": "markdown", "id": "892014db", "metadata": {}, "source": [ "### Scatter plots\n", "\n", "Scatter plots are triggered when you plot one data variable against another:" ] }, { "cell_type": "code", "execution_count": 7, "id": "bb92b4c6", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(\n", " x=\"fx\",\n", " y=\"dfx\",\n", " xscale=\"symlog\",\n", " yscale=\"symlog\",\n", " color=\"#FF7700\",\n", " markersize=\"delta\",\n", " markeredgecolor=\"none\",\n", ")" ] }, { "cell_type": "markdown", "id": "d0e79d8c", "metadata": {}, "source": [ "Line plots can be made for *two* data variables by using `xlink`.\n", "For example, in the following code, a sweep across `x` is connected into a\n", "line, but the actual locations are given by `fx`." ] }, { "cell_type": "code", "execution_count": 8, "id": "91ecabe3", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(\n", " x=\"fx\",\n", " xscale=\"symlog\",\n", " xlink=\"x\",\n", " y=\"dfx\",\n", " yscale=\"symlog\",\n", " marker=\"\",\n", " alpha=0.5,\n", " color=(\"amp\", \"p\"),\n", ")" ] }, { "cell_type": "markdown", "id": "33c807f4", "metadata": {}, "source": [ "```{hint}\n", "This can be very useful if plotting for example error vs computational time\n", "'xlinked' to some kind of 'effort' control knob. See also `text` which you can\n", "then use to annotate each point with the `xlink` dimension value.\n", "```" ] }, { "cell_type": "markdown", "id": "bacb3258", "metadata": {}, "source": [ "### Heatmaps\n", "\n", "Heatmaps can be draw by specifying a `z` data variable in addition to `x` and\n", "`y` coordinates. Since only a single data trace can be shown in a heatmap, most\n", "visual properties are not supported (just ``row`` and ``col`` for faceting).\n", "Instead, unused dimensions must be aggregated over - this will happen\n", "automatically (with a warning if you don't explicitly set ``aggregate``)." ] }, { "cell_type": "code", "execution_count": 9, "id": "cc2b4f6f", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(\n", " x=\"x\",\n", " y=\"delta\",\n", " z=\"fx\",\n", " zscale=\"symlog\",\n", " palette=\"Spectral\",\n", " col=\"p\",\n", " row=\"amp\",\n", " aggregate=[\"C\"],\n", ")" ] }, { "cell_type": "markdown", "id": "f049d747", "metadata": {}, "source": [ "## Aggregation & Errors\n", "\n", "By default (apart from heatmaps), data is not aggregated and is simply all\n", "shown. You can use the ``aggregate=(dima, dimb, ...)`` option to reduce the\n", "data over those dimensions, which also produces bands or error bars (see\n", "`aggregate_method`, `aggregate_err_range`, `err`, `err_style`, `err_kws`\n", "options)." ] }, { "cell_type": "code", "execution_count": 10, "id": "cc01c99f", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(\n", " x=\"x\",\n", " y=\"dfx\",\n", " # specify a single dimension to aggregate over\n", " aggregate=\"delta\",\n", ")" ] }, { "cell_type": "code", "execution_count": 11, "id": "26af4495", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(\n", " x=\"x\",\n", " y=\"dfx\",\n", " # combine with property mapping\n", " color=(\"amp\", \"p\"),\n", " # aggregate over all remaining dimensions\n", " aggregate=True,\n", ")" ] }, { "cell_type": "markdown", "id": "41384d57", "metadata": {}, "source": [ "The default aggregation and error calculation method (since it is robust to\n", "exponentially distributed data etc.) is the median and interquartile range, but you can specify other methods with the `aggregate_method` and `aggregate_err_range` options." ] }, { "cell_type": "code", "execution_count": 12, "id": "52edf066", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(\n", " x=\"x\",\n", " y=\"dfx\",\n", " # aggregate over all unused dimensions\n", " aggregate=True,\n", " # show mean and standard deviation\n", " aggregate_method=\"mean\",\n", " aggregate_err_range=\"std\",\n", " err_style=\"bars\",\n", ")" ] }, { "cell_type": "markdown", "id": "e7771de3", "metadata": {}, "source": [ "You can also supply the error values directly with the `err` kwarg, and control the style of error bars with `err_style` and `err_kws`." ] }, { "cell_type": "markdown", "id": "c551386d", "metadata": {}, "source": [ "## List of mappable visual properties\n", "\n", "Depending on the type of plot, the following visual properties can be mapped\n", "to dimensions/coordinates (or possibly other data variables) of the dataset:\n", "\n", "*Main variables:*\n", "\n", "- ``x``: x-axis\n", "- ``y``: y-axis - the target quantity, if not supplied bin the data over x\n", "- ``z``: z-axis (for heatmaps only)\n", "- ``err``: explicit error values\n", "\n", "*Style:*\n", "\n", "- ``color``: color of the line\n", "- ``hue`` : if supplied as well as ``color``, this controls hue (palette), and `color` intensity (if ``color`` is not supplied then ``hue`` is equivalent to ``color``)\n", "- ``marker``: marker type\n", "- ``markersize``: marker size\n", "- ``markeredgecolor``: color of the marker edge\n", "- ``linestyle``: line style\n", "- ``linewidth``: line width\n", "\n", "*Subplot:*\n", "\n", "- ``col``: subplot column\n", "- ``row``: subplot row\n", "\n", "*Other:*\n", "\n", "- ``text``: text label next to each point (useful combined with ``xlink``), see\n", " also ``text_formatter`` and ``text_opts``.\n", "- ``hspans``: horizontal spans (per row or column if mapped)\n", "- ``vspans``: vertical spans (per row or column if mapped)\n", "\n", "\n", "```{hint}\n", "As mentioned before multiple dimensions can also be 'fused' (stacked) and\n", "mapped to the same property using a tuple or list. Or if the supplied option is\n", "not a coordinate of the dataset, it is assumed to be global/static value for\n", "that property. To supply arbitrary options to the underyling matplotlib plot\n", "function, use `kwargs=dict(...)`.\n", "```" ] }, { "cell_type": "code", "execution_count": 13, "id": "dd4d3174", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(\n", " x=\"x\",\n", " y=\"fx\",\n", " yscale=\"symlog\",\n", " ylabel=\"$f(x)$\",\n", " col=\"p\",\n", " row=\"amp\",\n", " hue=\"C\",\n", " markeredgecolor=\"C\",\n", " linestyle=\"C\",\n", " color=\"delta\",\n", " marker=\"delta\",\n", " linewidth=\"delta\",\n", " markersize=\"delta\",\n", ")" ] }, { "cell_type": "markdown", "id": "5818f642", "metadata": {}, "source": [ "### Manual values, orders and labels\n", "\n", "Each mappable property can be manually controlled with extra kwargs (here `{style}` is a placeholder for `color`, `marker`, `linestyle` etc.):\n", "\n", "- `{style}_order`: list of specific dimension values in the order they should be plotted (this is equivalent to `ds.sel(dim=style_order).xyz.plot(...)`).\n", "- `{style}s`: list of specific styles to use for each value.\n", "- `{style}_label`: a custom label for this dimension in the legend.\n", "- `{style}_ticklabels`: a list of specific tick labels to use for this dimension.\n", "\n", "Here's an example of specfically for the `color` property:" ] }, { "cell_type": "code", "execution_count": 14, "id": "5a51ff07", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(\n", " x=\"x\",\n", " y=\"fx\",\n", " color=(\"amp\", \"p\"),\n", " color_order=[(1.0, 1), (-1.0, 2)],\n", " colors=(\"pink\", \"purple\"),\n", " color_label=\"$A \\\\otimes p$\",\n", " color_ticklabels=[\"$+^1$\", \"$-^2$\"],\n", ")" ] }, { "cell_type": "markdown", "id": "4d5ef042", "metadata": {}, "source": [ "## Colors and palettes\n", "\n", "`xyz.plot` separates \"which palette?\" from \"where inside that palette?\". If you\n", "only supply `color` or `hue`, then these act the same way: that dimension is\n", "mapped to a sequence of colors or to a single palette.\n", "\n", "- you can specify the sequence of colors as `colors` (or `hues`)\n", "- you can specify a palette using `palette=`, which can be:\n", " - a string name of a palette family (e.g. \"viridis\", \"turbo\", etc.)\n", " - an explicit matplotlib colormap object\n", " - a number in [0.0, 1.0] to generate an automatic palette from." ] }, { "cell_type": "code", "execution_count": 15, "id": "b18e9f35", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(\n", " x=\"x\",\n", " y=\"fx\",\n", " hue=(\"amp\", \"delta\"),\n", " palette=\"turbo\",\n", " marker=\"\",\n", ")" ] }, { "cell_type": "markdown", "id": "d306781a", "metadata": {}, "source": [ "Automatic palettes are generate in the OKLCH color space so as to be\n", "perceptually uniform. You can generate and preview them directly with\n", "{func}`xyzpy.cmoke`." ] }, { "cell_type": "code", "execution_count": 16, "id": "2f805d4f", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAgAAAABACAYAAABsv8+/AAAAFHRFWHRUaXRsZQBjbW9rZSBjb2xvcm1hcJXPlx4AAAAadEVYdERlc2NyaXB0aW9uAGNtb2tlIGNvbG9ybWFwa5A++AAAADF0RVh0QXV0aG9yAE1hdHBsb3RsaWIgdjMuMTAuOCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZ5+cXbEAAAAzdEVYdFNvZnR3YXJlAE1hdHBsb3RsaWIgdjMuMTAuOCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZzq4TkUAAAHgSURBVHic7dZRTuNAFADBMQfZa+7xQSuxjmJ42ITw1VUfoDgv47GjWL39/bNe11pr2/79Xev93/56Dcf/v97f/+HcPjbMjfu4Ovfk/V7d14frGue2Ye79+GFDx+O3z53NDesd13l47n4f+/v73P0NmPZ/+9zx/tyv83tz034/X++47/W0uel7/Xru9vsd9j18jx/2c3Jfvn0dhwfL2dyj93/+XX19nnF/w3WOD4LpATI9MNbJ6++ue/U8l893tu7V852t++h1DOtcPf/2pPszfp8/vI5n3Y/D8Zf7TwMABQIAAIIEAAAECQAACBIAABAkAAAgSAAAQJAAAIAgAQAAQQIAAIIEAAAECQAACBIAABAkAAAgSAAAQJAAAIAgAQAAQQIAAIIEAAAECQAACBIAABAkAAAgSAAAQJAAAIAgAQAAQQIAAIIEAAAECQAACBIAABAkAAAgSAAAQJAAAIAgAQAAQQIAAIIEAAAECQAACBIAABAkAAAgSAAAQJAAAIAgAQAAQQIAAIIEAAAECQAACBIAABAkAAAgSAAAQJAAAIAgAQAAQQIAAIIEAAAECQAACBIAABAkAAAgSAAAQJAAAIAgAQAAQQIAAIIEAAAECQAACBIAABAkAAAgSAAAQNAbIyMDs0jscGkAAAAASUVORK5CYII=", "text/html": [ "
cmoke
\"cmoke
under
bad
over
" ], "text/plain": [ "" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "xyz.cmoke(0.12)" ] }, { "cell_type": "code", "execution_count": 17, "id": "825ace20", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAgAAAABACAYAAABsv8+/AAAAFHRFWHRUaXRsZQBjbW9rZSBjb2xvcm1hcJXPlx4AAAAadEVYdERlc2NyaXB0aW9uAGNtb2tlIGNvbG9ybWFwa5A++AAAADF0RVh0QXV0aG9yAE1hdHBsb3RsaWIgdjMuMTAuOCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZ5+cXbEAAAAzdEVYdFNvZnR3YXJlAE1hdHBsb3RsaWIgdjMuMTAuOCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZzq4TkUAAAHhSURBVHic7dZbToNAAIbRGcSluQX3vxOMhpJ0YBxoa3z4z3khc6VNo/lq+fxYyrdafx6lTOVuXNdxGYx757v3XTz3V/d0xye/d3nxe8++7+z7X3b+wX2j+d19dfA5R/PH75nX5/u6Pq/rc3e9nb/f/9Y853o8P93GtTPf2ddbnzr3tOv78+XXfVO7b7S+u6dcvK+9pz3fGW/7jp/15L7RfY/eUy++b7d/9P3qk5/jn9a3f9vN997+XHvq2fmlmV+a/YNxWQbzg33beHnuXD17/jX7b78PABBEAABAIAEAAIEEAAAEEgAAEEgAAEAgAQAAgQQAAAQSAAAQSAAAQCABAACBBAAABBIAABBIAABAIAEAAIEEAAAEEgAAEEgAAEAgAQAAgQQAAAQSAAAQSAAAQCABAACBBAAABBIAABBIAABAIAEAAIEEAAAEEgAAEEgAAEAgAQAAgQQAAAQSAAAQSAAAQCABAACBBAAABBIAABBIAABAIAEAAIEEAAAEEgAAEEgAAEAgAQAAgQQAAAQSAAAQSAAAQCABAACBBAAABBIAABBIAABAIAEAAIEEAAAEEgAAEEgAAEAgAQAAgQQAAAQSAAAQSAAAQCABAACBBAAABBIAABBIAABAIAEAAIG+AMB0IA0jyAQ/AAAAAElFTkSuQmCC", "text/html": [ "
cmoke
\"cmoke
under
bad
over
" ], "text/plain": [ "" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# vary hue as well as lightness\n", "xyz.cmoke(0.75, hue_shift=0.5)" ] }, { "cell_type": "markdown", "id": "3ac9be96", "metadata": {}, "source": [ "If both `hue` and `color` are supplied, then `hue` controls *which palette* and\n", "`color` controls *where in that palette* (i.e. the intensity).\n", "\n", "- in this case the `hues` kwarg can manually specify a sequence of palettes,\n", " each of which can be str, float or colormap (the same options as `palette`)." ] }, { "cell_type": "code", "execution_count": 18, "id": "019f0ef4", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(\n", " x=\"x\",\n", " y=\"fx\",\n", " hue=\"amp\",\n", " hues=(\n", " # numeric value is interpreted as a hue in [0, 1]\n", " 0.12,\n", " # or explicitly supply a full palette\n", " xyz.cmoke(0.75, hue_shift=0.5),\n", " ),\n", " color=\"delta\",\n", " marker=\"\",\n", " # these can be convenient for using only a subrange of a palette\n", " colormap_start=0.1,\n", " colormap_stop=0.9,\n", ")" ] }, { "cell_type": "markdown", "id": "16cbce79", "metadata": {}, "source": [ "## Legend control\n", "\n", "By default the legend is 'split' (`legend_merge=False`), which creates separate\n", "legend blocks for each each mappend dimension:" ] }, { "cell_type": "code", "execution_count": 19, "id": "25517e84", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(\n", " x=\"x\",\n", " y=\"dfx\",\n", " color=\"p\",\n", " linestyle=\"amp\",\n", " linewidth=\"C\",\n", " # the default:\n", " legend_merge=False,\n", ")" ] }, { "cell_type": "markdown", "id": "6c9098e8", "metadata": {}, "source": [ "If you specify `legend_merge=True`, then instead a legend will be produced with\n", "one entry for every unique combination of styles." ] }, { "cell_type": "code", "execution_count": 20, "id": "7df2068b", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(\n", " x=\"x\",\n", " y=\"dfx\",\n", " color=\"p\",\n", " linestyle=\"amp\",\n", " linewidth=\"C\",\n", " legend_merge=True,\n", " # manually specify number of columns\n", " legend_ncol=2,\n", ")" ] }, { "cell_type": "markdown", "id": "3aa615f8", "metadata": {}, "source": [ "If you are fusing various dimensions, or using `legend_merge=True`, then the\n", "number of entries can quite quickly become large. `legend_entries: dict[dim, values]`\n", "lets you explicitly specify which values for each dimension to show." ] }, { "cell_type": "code", "execution_count": 21, "id": "9bf48dc7", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(\n", " x=\"x\",\n", " y=\"dfx\",\n", " # fuse and map 4 dimensions\n", " color=(\"p\", \"amp\", \"C\", \"delta\"),\n", " marker=(\"p\", \"amp\", \"C\", \"delta\"),\n", " linestyle=(\"p\", \"amp\", \"C\", \"delta\"),\n", " palette=\"inferno\",\n", " # only show 3 example entries in the legend\n", " legend_entries={\n", " # note we need to specify the fused dimension name\n", " \"p, amp, C, delta\": [\n", " (1, -1.0, -2.0, 0.0),\n", " (2, -1.0, 1.0, 0.6),\n", " (3, 1.0, 4.0, 1.0),\n", " ]\n", " },\n", " markeredgecolor=\"none\",\n", " markersize=4,\n", ")" ] }, { "cell_type": "markdown", "id": "f67d81d9", "metadata": {}, "source": [ "`legend_reverse`, `legend_labels`, `legend_extras`, and `legend_opts` let you tune ordering, layout, and manual additions." ] }, { "cell_type": "markdown", "id": "961bfa05", "metadata": {}, "source": [ "## Figure and axis customization\n", "\n", "Most figure options intentionally follow matplotlib naming.\n", "[`ds.xyz.plot()`](xyzpy.plot.infiniplot.infiniplot) always returns `(fig, axs)`,\n", "so the built-in options are a starting point rather than a limit.\n", "\n", "Useful controls include:\n", "\n", "- `title`, `height`, `width`, `hspace`, `wspace`, `sharex`, `sharey`\n", "- `xlabel`, `ylabel`, `xlim`, `ylim`, `xscale`, `yscale`, `xbase`, `ybase`\n", "- `xticks`, `yticks`, `xticklabels`, `yticklabels`\n", "- `hspans` and `vspans`, either as plain sequences or as `{label: value}` dictionaries for annotated reference lines\n", "- `background_color` for a solid figure background\n", "- `zscale` and `zlim` for heatmap color normalization" ] }, { "cell_type": "code", "execution_count": 22, "id": "8975ba5a", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig, axs = ds.xyz.plot(\n", " x=\"x\",\n", " y=\"fx\",\n", " color=\"delta\",\n", " col=\"p\",\n", " row=\"amp\",\n", " marker=\"\",\n", " title=\"Custom subplot layout and reference lines\",\n", " height=2.0,\n", " width=3.2,\n", " hspace=0.25,\n", " wspace=0.03,\n", " xlim=(-2, 2),\n", " ylim=(-8, 8),\n", " xticks=[-1, 0, 1],\n", " # map horizontal span location to 'amp' values\n", " hspans=\"amp\",\n", " # map vertical span location to specific values with labels\n", " vspans={\"$x=\\\\frac{1}{\\\\pi}$\": 0.318309886},\n", " span_color=(0.0, 0.0, 1.0),\n", " background_color=(0.9, 0.9, 0.9),\n", " draw_color=(0, 0, 0),\n", ")" ] }, { "cell_type": "markdown", "id": "78cd92cc", "metadata": {}, "source": [ "You can also pass in `axs` or `ax` to plot on existing axes, with `format_axs`\n", "controlling whether `xyzpy` should modify these at all, including applying its\n", "'neutral style' to these (which works on both light and dark backgrounds, but\n", "may not be desired for producing figures - see also `use_neutral_style`)." ] }, { "cell_type": "markdown", "id": "ab9a78f6", "metadata": {}, "source": [ "## Alternative plotting libraries\n", "\n", "There are many other libraries for plotting self-labelled data, especially\n", "for {class}`pandas.DataFrame` objects, which can easily be generated from a\n", "{class}`xarray.Dataset` using e.g.:\n", "\n", "```python\n", "ds = harvester.full_ds\n", "df = ds.to_dataframe().reset_index()\n", "```\n", "Notably:\n", "\n", "- [xarray](http://xarray.pydata.org/en/stable/plotting.html) itself has plotting functionality\n", "- [pandas](https://pandas.pydata.org/pandas-docs/stable/user_guide/visualization.html) itself has plotting functionality\n", "- [seaborn](https://seaborn.pydata.org/) uses `matplotlib` for plotting dataframes\n", "- [holoviews](https://holoviews.org/) uses `bokeh` for plotting dataframes\n", "- [hvplot](https://hvplot.holoviz.org/) builds on `holoviews` for plotting datasets\n", "- [altair](https://altair-viz.github.io/) for dataframes" ] } ], "metadata": { "kernelspec": { "display_name": "py314", "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.14.4" } }, "nbformat": 4, "nbformat_minor": 5 }