{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# Topographic hillshading\n\nDemonstrates the visual effect of varying blend mode and vertical exaggeration\non \"hillshaded\" plots.\n\nNote that the \"overlay\" and \"soft\" blend modes work well for complex surfaces\nsuch as this example, while the default \"hsv\" blend mode works best for smooth\nsurfaces such as many mathematical functions.\n\nIn most cases, hillshading is used purely for visual purposes, and *dx*/*dy*\ncan be safely ignored. In that case, you can tweak *vert_exag* (vertical\nexaggeration) by trial and error to give the desired visual effect. However,\nthis example demonstrates how to use the *dx* and *dy* keyword arguments to\nensure that the *vert_exag* parameter is the true vertical exaggeration.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\nimport numpy as np\n\nfrom matplotlib.cbook import get_sample_data\nfrom matplotlib.colors import LightSource\n\ndem = get_sample_data('jacksboro_fault_dem.npz')\nz = dem['elevation']\n# -- Optional dx and dy for accurate vertical exaggeration --------------------\n# If you need topographically accurate vertical exaggeration, or you don't want\n# to guess at what *vert_exag* should be, you'll need to specify the cellsize\n# of the grid (i.e. the *dx* and *dy* parameters).  Otherwise, any *vert_exag*\n# value you specify will be relative to the grid spacing of your input data\n# (in other words, *dx* and *dy* default to 1.0, and *vert_exag* is calculated\n# relative to those parameters).  Similarly, *dx* and *dy* are assumed to be in\n# the same units as your input z-values.  Therefore, we'll need to convert the\n# given dx and dy from decimal degrees to meters.\ndx, dy = dem['dx'], dem['dy']\ndy = 111200 * dy\ndx = 111200 * dx * np.cos(np.radians(dem['ymin']))\n# -----------------------------------------------------------------------------\n\n# Shade from the northwest, with the sun 45 degrees from horizontal\nls = LightSource(azdeg=315, altdeg=45)\ncmap = plt.colormaps[\"gist_earth\"]\n\nfig, axs = plt.subplots(nrows=4, ncols=3, figsize=(8, 9))\nplt.setp(axs.flat, xticks=[], yticks=[])\n\n# Vary vertical exaggeration and blend mode and plot all combinations\nfor col, ve in zip(axs.T, [0.1, 1, 10]):\n    # Show the hillshade intensity image in the first row\n    col[0].imshow(ls.hillshade(z, vert_exag=ve, dx=dx, dy=dy), cmap='gray')\n\n    # Place hillshaded plots with different blend modes in the rest of the rows\n    for ax, mode in zip(col[1:], ['hsv', 'overlay', 'soft']):\n        rgb = ls.shade(z, cmap=cmap, blend_mode=mode,\n                       vert_exag=ve, dx=dx, dy=dy)\n        ax.imshow(rgb)\n\n# Label rows and columns\nfor ax, ve in zip(axs[0], [0.1, 1, 10]):\n    ax.set_title(f'{ve}', size=18)\nfor ax, mode in zip(axs[:, 0], ['Hillshade', 'hsv', 'overlay', 'soft']):\n    ax.set_ylabel(mode, size=18)\n\n# Group labels...\naxs[0, 1].annotate('Vertical Exaggeration', (0.5, 1), xytext=(0, 30),\n                   textcoords='offset points', xycoords='axes fraction',\n                   ha='center', va='bottom', size=20)\naxs[2, 0].annotate('Blend Mode', (0, 0.5), xytext=(-30, 0),\n                   textcoords='offset points', xycoords='axes fraction',\n                   ha='right', va='center', size=20, rotation=90)\nfig.subplots_adjust(bottom=0.05, right=0.95)\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
}