{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n\n# Axis scales\n\nBy default Matplotlib displays data on the axis using a linear scale.\nMatplotlib also supports [logarithmic scales](https://en.wikipedia.org/wiki/Logarithmic_scale), and other less common\nscales as well. Usually this can be done directly by using the\n`~.axes.Axes.set_xscale` or `~.axes.Axes.set_yscale` methods.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\nimport numpy as np\n\nimport matplotlib.scale as mscale\nfrom matplotlib.ticker import FixedLocator, NullFormatter\n\nfig, axs = plt.subplot_mosaic([['linear', 'linear-log'],\n ['log-linear', 'log-log']], layout='constrained')\n\nx = np.arange(0, 3*np.pi, 0.1)\ny = 2 * np.sin(x) + 3\n\nax = axs['linear']\nax.plot(x, y)\nax.set_xlabel('linear')\nax.set_ylabel('linear')\n\nax = axs['linear-log']\nax.plot(x, y)\nax.set_yscale('log')\nax.set_xlabel('linear')\nax.set_ylabel('log')\n\nax = axs['log-linear']\nax.plot(x, y)\nax.set_xscale('log')\nax.set_xlabel('log')\nax.set_ylabel('linear')\n\nax = axs['log-log']\nax.plot(x, y)\nax.set_xscale('log')\nax.set_yscale('log')\nax.set_xlabel('log')\nax.set_ylabel('log')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## loglog and semilogx/y\n\nThe logarithmic axis is used so often that there are a set\nhelper functions, that do the same thing: `~.axes.Axes.semilogy`,\n`~.axes.Axes.semilogx`, and `~.axes.Axes.loglog`.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, axs = plt.subplot_mosaic([['linear', 'linear-log'],\n ['log-linear', 'log-log']], layout='constrained')\n\nx = np.arange(0, 3*np.pi, 0.1)\ny = 2 * np.sin(x) + 3\n\nax = axs['linear']\nax.plot(x, y)\nax.set_xlabel('linear')\nax.set_ylabel('linear')\nax.set_title('plot(x, y)')\n\nax = axs['linear-log']\nax.semilogy(x, y)\nax.set_xlabel('linear')\nax.set_ylabel('log')\nax.set_title('semilogy(x, y)')\n\nax = axs['log-linear']\nax.semilogx(x, y)\nax.set_xlabel('log')\nax.set_ylabel('linear')\nax.set_title('semilogx(x, y)')\n\nax = axs['log-log']\nax.loglog(x, y)\nax.set_xlabel('log')\nax.set_ylabel('log')\nax.set_title('loglog(x, y)')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Other built-in scales\n\nThere are other scales that can be used. The list of registered\nscales can be returned from `.scale.get_scale_names`:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "print(mscale.get_scale_names())" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, axs = plt.subplot_mosaic([['asinh', 'symlog'],\n ['log', 'logit']], layout='constrained')\n\nx = np.arange(0, 1000)\n\nfor name, ax in axs.items():\n if name in ['asinh', 'symlog']:\n yy = x - np.mean(x)\n elif name in ['logit']:\n yy = (x-np.min(x))\n yy = yy / np.max(np.abs(yy))\n else:\n yy = x\n\n ax.plot(yy, yy)\n ax.set_yscale(name)\n ax.set_title(name)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Optional arguments for scales\n\nSome of the default scales have optional arguments. These are\ndocumented in the API reference for the respective scales at\n`~.matplotlib.scale`. One can change the base of the logarithm\nbeing plotted (eg 2 below) or the linear threshold range\nfor ``'symlog'``.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, axs = plt.subplot_mosaic([['log', 'symlog']], layout='constrained',\n figsize=(6.4, 3))\n\nfor name, ax in axs.items():\n if name in ['log']:\n ax.plot(x, x)\n ax.set_yscale('log', base=2)\n ax.set_title('log base=2')\n else:\n ax.plot(x - np.mean(x), x - np.mean(x))\n ax.set_yscale('symlog', linthresh=100)\n ax.set_title('symlog linthresh=100')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Arbitrary function scales\n\nUsers can define a full scale class and pass that to `~.axes.Axes.set_xscale`\nand `~.axes.Axes.set_yscale` (see `custom_scale`). A short cut for this\nis to use the 'function' scale, and pass as extra arguments a ``forward`` and\nan ``inverse`` function. The following performs a [Mercator transform](https://en.wikipedia.org/wiki/Mercator_projection) to the y-axis.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Function Mercator transform\ndef forward(a):\n a = np.deg2rad(a)\n return np.rad2deg(np.log(np.abs(np.tan(a) + 1.0 / np.cos(a))))\n\n\ndef inverse(a):\n a = np.deg2rad(a)\n return np.rad2deg(np.arctan(np.sinh(a)))\n\n\nt = np.arange(0, 170.0, 0.1)\ns = t / 2.\n\nfig, ax = plt.subplots(layout='constrained')\nax.plot(t, s, '-', lw=2)\n\nax.set_yscale('function', functions=(forward, inverse))\nax.set_title('function: Mercator')\nax.grid(True)\nax.set_xlim([0, 180])\nax.yaxis.set_minor_formatter(NullFormatter())\nax.yaxis.set_major_locator(FixedLocator(np.arange(0, 90, 10)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## What is a \"scale\"?\n\nA scale is an object that gets attached to an axis. The class documentation\nis at `~matplotlib.scale`. `~.axes.Axes.set_xscale` and `~.axes.Axes.set_yscale`\nset the scale on the respective Axis objects. You can determine the scale\non an axis with `~.axis.Axis.get_scale`:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, ax = plt.subplots(layout='constrained',\n figsize=(3.2, 3))\nax.semilogy(x, x)\n\nprint(ax.xaxis.get_scale())\nprint(ax.yaxis.get_scale())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Setting a scale does three things. First it defines a transform on the axis\nthat maps between data values to position along the axis. This transform can\nbe accessed via ``get_transform``:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "print(ax.yaxis.get_transform())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Transforms on the axis are a relatively low-level concept, but is one of the\nimportant roles played by ``set_scale``.\n\nSetting the scale also sets default tick locators (`~.ticker`) and tick\nformatters appropriate for the scale. An axis with a 'log' scale has a\n`~.ticker.LogLocator` to pick ticks at decade intervals, and a\n`~.ticker.LogFormatter` to use scientific notation on the decades.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "print('X axis')\nprint(ax.xaxis.get_major_locator())\nprint(ax.xaxis.get_major_formatter())\n\nprint('Y axis')\nprint(ax.yaxis.get_major_locator())\nprint(ax.yaxis.get_major_formatter())" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.13.2" } }, "nbformat": 4, "nbformat_minor": 0 }