{
  "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.14.6"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}