{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n# Colormap normalizations\n\nDemonstration of using norm to map colormaps onto data in non-linear ways.\n\n.. redirect-from:: /gallery/userdemo/colormap_normalizations\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\nimport numpy as np\n\nimport matplotlib.colors as colors\n\nN = 100" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## LogNorm\nThis example data has a low hump with a spike coming out of its center. If plotted\nusing a linear colour scale, then only the spike will be visible. To see both hump and\nspike, this requires the z/colour axis on a log scale.\n\nInstead of transforming the data with ``pcolor(log10(Z))``, the color mapping can be\nmade logarithmic using a `.LogNorm`.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)]\nZ1 = np.exp(-X**2 - Y**2)\nZ2 = np.exp(-(X * 10)**2 - (Y * 10)**2)\nZ = Z1 + 50 * Z2\n\nfig, ax = plt.subplots(2, 1)\n\npcm = ax[0].pcolor(X, Y, Z, cmap='PuBu_r', shading='nearest')\nfig.colorbar(pcm, ax=ax[0], extend='max', label='linear scaling')\n\npcm = ax[1].pcolor(X, Y, Z, cmap='PuBu_r', shading='nearest',\n norm=colors.LogNorm(vmin=Z.min(), vmax=Z.max()))\nfig.colorbar(pcm, ax=ax[1], extend='max', label='LogNorm')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## PowerNorm\nThis example data mixes a power-law trend in X with a rectified sine wave in Y. If\nplotted using a linear colour scale, then the power-law trend in X partially obscures\nthe sine wave in Y.\n\nThe power law can be removed using a `.PowerNorm`.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "X, Y = np.mgrid[0:3:complex(0, N), 0:2:complex(0, N)]\nZ = (1 + np.sin(Y * 10)) * X**2\n\nfig, ax = plt.subplots(2, 1)\n\npcm = ax[0].pcolormesh(X, Y, Z, cmap='PuBu_r', shading='nearest')\nfig.colorbar(pcm, ax=ax[0], extend='max', label='linear scaling')\n\npcm = ax[1].pcolormesh(X, Y, Z, cmap='PuBu_r', shading='nearest',\n norm=colors.PowerNorm(gamma=0.5))\nfig.colorbar(pcm, ax=ax[1], extend='max', label='PowerNorm')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## SymLogNorm\nThis example data has two humps, one negative and one positive, The positive hump has\n5 times the amplitude of the negative. If plotted with a linear colour scale, then\nthe detail in the negative hump is obscured.\n\nHere we logarithmically scale the positive and negative data separately with\n`.SymLogNorm`.\n\nNote that colorbar labels do not come out looking very good.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)]\nZ1 = np.exp(-X**2 - Y**2)\nZ2 = np.exp(-(X - 1)**2 - (Y - 1)**2)\nZ = (5 * Z1 - Z2) * 2\n\nfig, ax = plt.subplots(2, 1)\n\npcm = ax[0].pcolormesh(X, Y, Z, cmap='RdBu_r', shading='nearest',\n vmin=-np.max(Z))\nfig.colorbar(pcm, ax=ax[0], extend='both', label='linear scaling')\n\npcm = ax[1].pcolormesh(X, Y, Z, cmap='RdBu_r', shading='nearest',\n norm=colors.SymLogNorm(linthresh=0.015,\n vmin=-10.0, vmax=10.0, base=10))\nfig.colorbar(pcm, ax=ax[1], extend='both', label='SymLogNorm')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Custom Norm\nAlternatively, the above example data can be scaled with a customized normalization.\nThis one normalizes the negative data differently from the positive.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Example of making your own norm. Also see matplotlib.colors.\n# From Joe Kington: This one gives two different linear ramps:\nclass MidpointNormalize(colors.Normalize):\n def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):\n self.midpoint = midpoint\n super().__init__(vmin, vmax, clip)\n\n def __call__(self, value, clip=None):\n # I'm ignoring masked values and all kinds of edge cases to make a\n # simple example...\n x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1]\n return np.ma.masked_array(np.interp(value, x, y))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, ax = plt.subplots(2, 1)\n\npcm = ax[0].pcolormesh(X, Y, Z, cmap='RdBu_r', shading='nearest',\n vmin=-np.max(Z))\nfig.colorbar(pcm, ax=ax[0], extend='both', label='linear scaling')\n\npcm = ax[1].pcolormesh(X, Y, Z, cmap='RdBu_r', shading='nearest',\n norm=MidpointNormalize(midpoint=0))\nfig.colorbar(pcm, ax=ax[1], extend='both', label='Custom norm')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## BoundaryNorm\nFor arbitrarily dividing the color scale, the `.BoundaryNorm` may be used; by\nproviding the boundaries for colors, this norm puts the first color in between the\nfirst pair, the second color between the second pair, etc.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "fig, ax = plt.subplots(3, 1, layout='constrained')\n\npcm = ax[0].pcolormesh(X, Y, Z, cmap='RdBu_r', shading='nearest',\n vmin=-np.max(Z))\nfig.colorbar(pcm, ax=ax[0], extend='both', orientation='vertical',\n label='linear scaling')\n\n# Evenly-spaced bounds gives a contour-like effect.\nbounds = np.linspace(-2, 2, 11)\nnorm = colors.BoundaryNorm(boundaries=bounds, ncolors=256)\npcm = ax[1].pcolormesh(X, Y, Z, cmap='RdBu_r', shading='nearest',\n norm=norm)\nfig.colorbar(pcm, ax=ax[1], extend='both', orientation='vertical',\n label='BoundaryNorm\\nlinspace(-2, 2, 11)')\n\n# Unevenly-spaced bounds changes the colormapping.\nbounds = np.array([-1, -0.5, 0, 2.5, 5])\nnorm = colors.BoundaryNorm(boundaries=bounds, ncolors=256)\npcm = ax[2].pcolormesh(X, Y, Z, cmap='RdBu_r', shading='nearest',\n norm=norm)\nfig.colorbar(pcm, ax=ax[2], extend='both', orientation='vertical',\n label='BoundaryNorm\\n[-1, -0.5, 0, 2.5, 5]')\n\nplt.show()" ] } ], "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.5" } }, "nbformat": 4, "nbformat_minor": 0 }