{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# Colouring Anomaly Data With Logarithmic Scaling\n\nIn this example, we need to plot anomaly data where the values have a\n\"logarithmic\" significance  -- i.e. we want to give approximately equal ranges\nof colour between data values of, say, 1 and 10 as between 10 and 100.\n\nAs the data range also contains zero, that obviously does not suit a simple\nlogarithmic interpretation.  However, values of less than a certain absolute\nmagnitude may be considered \"not significant\", so we put these into a separate\n\"zero band\" which is plotted in white.\n\nTo do this, we create a custom value mapping function (normalization) using\nthe matplotlib Norm class :obj:`matplotlib.colors.SymLogNorm`.\nWe use this to make a cell-filled pseudocolor plot with a colorbar.\n\nNOTE: By \"pseudocolour\", we mean that each data point is drawn as a \"cell\"\nregion on the plot, coloured according to its data value.\nThis is provided in Iris by the functions :meth:`iris.plot.pcolor` and\n:meth:`iris.plot.pcolormesh`, which call the underlying matplotlib\nfunctions of the same names (i.e., :obj:`matplotlib.pyplot.pcolor`\nand :obj:`matplotlib.pyplot.pcolormesh`).\nSee also: http://en.wikipedia.org/wiki/False_color#Pseudocolor.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import cartopy.crs as ccrs\nimport matplotlib.colors as mcols\nimport matplotlib.pyplot as plt\n\nimport iris\nimport iris.coord_categorisation\nimport iris.plot as iplt\n\n\ndef main():\n    # Load a sample air temperatures sequence.\n    file_path = iris.sample_data_path(\"E1_north_america.nc\")\n    temperatures = iris.load_cube(file_path)\n\n    # Create a year-number coordinate from the time information.\n    iris.coord_categorisation.add_year(temperatures, \"time\")\n\n    # Create a sample anomaly field for one chosen year, by extracting that\n    # year and subtracting the time mean.\n    sample_year = 1982\n    year_temperature = temperatures.extract(iris.Constraint(year=sample_year))\n    time_mean = temperatures.collapsed(\"time\", iris.analysis.MEAN)\n    anomaly = year_temperature - time_mean\n\n    # Construct a plot title string explaining which years are involved.\n    years = temperatures.coord(\"year\").points\n    plot_title = \"Temperature anomaly\"\n    plot_title += \"\\n{} differences from {}-{} average.\".format(\n        sample_year, years[0], years[-1]\n    )\n\n    # Define scaling levels for the logarithmic colouring.\n    minimum_log_level = 0.1\n    maximum_scale_level = 3.0\n\n    # Use a standard colour map which varies blue-white-red.\n    # For suitable options, see the 'Diverging colormaps' section in:\n    # http://matplotlib.org/stable/gallery/color/colormap_reference.html\n    anom_cmap = \"bwr\"\n\n    # Create a 'logarithmic' data normalization.\n    anom_norm = mcols.SymLogNorm(\n        linthresh=minimum_log_level,\n        linscale=0.01,\n        vmin=-maximum_scale_level,\n        vmax=maximum_scale_level,\n    )\n    # Setting \"linthresh=minimum_log_level\" makes its non-logarithmic\n    # data range equal to our 'zero band'.\n    # Setting \"linscale=0.01\" maps the whole zero band to the middle colour value\n    # (i.e., 0.5), which is the neutral point of a \"diverging\" style colormap.\n\n    # Create an Axes, specifying the map projection.\n    plt.axes(projection=ccrs.LambertConformal())\n\n    # Make a pseudocolour plot using this colour scheme.\n    mesh = iplt.pcolormesh(anomaly, cmap=anom_cmap, norm=anom_norm)\n\n    # Add a colourbar, with extensions to show handling of out-of-range values.\n    bar = plt.colorbar(mesh, orientation=\"horizontal\", extend=\"both\")\n\n    # Set some suitable fixed \"logarithmic\" colourbar tick positions.\n    tick_levels = [-3, -1, -0.3, 0.0, 0.3, 1, 3]\n    bar.set_ticks(tick_levels)\n\n    # Modify the tick labels so that the centre one shows \"+/-<minumum-level>\".\n    tick_levels[3] = r\"$\\pm${:g}\".format(minimum_log_level)\n    bar.set_ticklabels(tick_levels)\n\n    # Label the colourbar to show the units.\n    bar.set_label(\"[{}, log scale]\".format(anomaly.units))\n\n    # Add coastlines and a title.\n    plt.gca().coastlines()\n    plt.title(plot_title)\n\n    # Display the result.\n    iplt.show()\n\n\nif __name__ == \"__main__\":\n    main()"
      ]
    }
  ],
  "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.10.6"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}