
.. DO NOT EDIT.
.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY.
.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE:
.. "tutorial/03_figures/c_geological-map.py"
.. LINE NUMBERS ARE GIVEN BELOW.

.. only:: html

    .. note::
        :class: sphx-glr-download-link-note

        :ref:`Go to the end <sphx_glr_download_tutorial_03_figures_c_geological-map.py>`
        to download the full example code. or to run this example in your browser via Binder

.. rst-class:: sphx-glr-example-title

.. _sphx_glr_tutorial_03_figures_c_geological-map.py:


Geological Map on Topography
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Texture mapping for a GeoTIFF on a topography surface.

To overlay an image/map from a GeoTIFF on to a topography surface, it's necessary to have texture coordinates ("texture mapping") matching the proper extends of the mesh/surface you'd like to drape the texture (GeoTIFF) on.

We can do this by using the spatial reference of the GeoTIFF itself, as this allows you to preserve the entire mesh that the texture is being draped on without having to clip out the parts where you don't have imagery. In this example, we explicitly set the texture extents onto a topography surface where the texture/GeoTIFF has a much larger extent than the topography surface.

Originally posted here: https://github.com/pyvista/pyvista-support/issues/14

.. GENERATED FROM PYTHON SOURCE LINES 13-27

.. code-block:: Python


    import os
    import tempfile

    import numpy as np
    import pyvista as pv
    import requests
    from pyvista import examples

    try:
        import rasterio
    except ImportError:
        rasterio = None








.. GENERATED FROM PYTHON SOURCE LINES 29-33

.. code-block:: Python

    path = examples.download_file("topo_clean.vtk")
    topo = pv.read(path)
    topo






.. raw:: html

    <div class="output_subarea output_html rendered_html output_result">
    <div><style>/* PyVista HTML repr stylesheet.
     * Uses pv- prefix to avoid conflicts with other libraries.
     */

    :root {
      --pv-font-color0: var(--jp-content-font-color0, rgba(0, 0, 0, 1));
      --pv-font-color2: var(--jp-content-font-color2, rgba(0, 0, 0, 0.54));
      --pv-font-color3: var(--jp-content-font-color3, rgba(0, 0, 0, 0.38));
      --pv-border-color: var(--jp-border-color2, #e0e0e0);
      --pv-disabled-color: var(--jp-layout-color3, #bdbdbd);
      --pv-background-color-row-even: var(--jp-layout-color1, #f5f5f5);
      --pv-background-color-row-odd: var(--jp-layout-color2, #eeeeee);
      --pv-badge-active: #1b5e20;
      --pv-badge-normals: #0d47a1;
      --pv-badge-vectors: #00695c;
      --pv-badge-tcoords: #4527a0;
    }

    body[data-jp-theme-light="false"] {
      --pv-font-color0: var(--jp-content-font-color0, rgba(255, 255, 255, 1));
      --pv-font-color2: var(--jp-content-font-color2, rgba(255, 255, 255, 0.54));
      --pv-font-color3: var(--jp-content-font-color3, rgba(255, 255, 255, 0.38));
      --pv-border-color: var(--jp-border-color2, #424242);
      --pv-disabled-color: var(--jp-layout-color3, #616161);
      --pv-background-color-row-even: var(--jp-layout-color1, #1a1a1a);
      --pv-background-color-row-odd: var(--jp-layout-color2, #252525);
      --pv-badge-active: #66bb6a;
      --pv-badge-normals: #64b5f6;
      --pv-badge-vectors: #4db6ac;
      --pv-badge-tcoords: #b39ddb;
    }

    html[theme="dark"],
    html[data-theme="dark"],
    body[data-theme="dark"],
    body.vscode-dark {
      --pv-font-color0: rgba(255, 255, 255, 1);
      --pv-font-color2: rgba(255, 255, 255, 0.54);
      --pv-font-color3: rgba(255, 255, 255, 0.38);
      --pv-border-color: #424242;
      --pv-disabled-color: #616161;
      --pv-background-color-row-even: #1a1a1a;
      --pv-background-color-row-odd: #252525;
      --pv-badge-active: #66bb6a;
      --pv-badge-normals: #64b5f6;
      --pv-badge-vectors: #4db6ac;
      --pv-badge-tcoords: #b39ddb;
    }

    /* OS-level dark mode fallback: applies when no explicit data-theme is set */
    @media (prefers-color-scheme: dark) {
      html:not([data-theme="light"]) {
        --pv-font-color0: rgba(255, 255, 255, 1);
        --pv-font-color2: rgba(255, 255, 255, 0.54);
        --pv-font-color3: rgba(255, 255, 255, 0.38);
        --pv-border-color: #424242;
        --pv-disabled-color: #616161;
        --pv-background-color-row-even: #1a1a1a;
        --pv-background-color-row-odd: #252525;
        --pv-badge-active: #66bb6a;
        --pv-badge-normals: #64b5f6;
        --pv-badge-vectors: #4db6ac;
        --pv-badge-tcoords: #b39ddb;
      }
    }

    .pv-wrap {
      display: block !important;
      min-width: 300px;
      max-width: 700px;
      line-height: 1.6;
      padding-bottom: 4px;
      font-family: var(--jp-ui-font-family, sans-serif);
      font-size: var(--jp-ui-font-size1, 13px);
      color: var(--pv-font-color0);
    }

    .pv-text-repr-fallback {
      display: none;
    }

    /* Header */
    .pv-header {
      display: flex;
      align-items: center;
      gap: 8px;
      padding-top: 6px;
      padding-bottom: 6px;
      border-bottom: solid 1px var(--pv-border-color);
      margin-bottom: 4px;
    }

    .pv-header-text {
      display: flex;
      flex-direction: column;
      gap: 1px;
      min-width: 0;
      flex: 1;
    }

    .pv-obj-type {
      font-weight: 600;
      color: var(--pv-font-color0);
    }

    .pv-header-badge {
      display: inline-block;
      font-size: 0.75em;
      font-weight: 600;
      padding: 2px 7px;
      border-radius: 3px;
      color: var(--pv-font-color2);
      border: 1px solid var(--pv-border-color);
      white-space: nowrap;
    }

    /* Metadata (always-visible key-value rows) */
    .pv-metadata {
      margin: 4px 0 6px 0;
      font-size: 0.92em;
      line-height: 1.5;
    }

    .pv-meta-row {
      display: flex;
      flex-wrap: wrap;
      gap: 1px 14px;
      padding: 1px 0;
    }

    .pv-meta-row-label {
      color: var(--pv-font-color2);
      font-weight: 500;
      white-space: nowrap;
      min-width: 60px;
    }

    .pv-meta-entry {
      white-space: nowrap;
    }

    /* Copy-to-clipboard button */
    .pv-copy-btn {
      display: inline-block;
      cursor: pointer;
      opacity: 0.5;
      font-size: 0.85em;
      padding: 0 3px;
      vertical-align: middle;
      transition: opacity 0.15s;
      user-select: none;
      border: none;
      background: none;
      color: var(--pv-font-color3);
    }

    .pv-copy-btn:hover {
      opacity: 1;
      color: var(--pv-font-color0);
    }

    .pv-meta-label {
      color: var(--pv-font-color3);
      font-weight: 400;
      padding-right: 2px;
    }

    /* Sections grid */
    .pv-sections {
      padding-left: 0 !important;
      display: grid;
      grid-template-columns: 150px auto auto auto 1fr 20px 20px;
      margin-block-start: 0;
      margin-block-end: 0;
      list-style: none;
    }

    .pv-section-item {
      display: contents;
    }

    /* Hidden checkbox for expand/collapse */
    .pv-section-item > input {
      display: block;
      opacity: 0;
      height: 0;
      margin: 0;
    }

    .pv-section-item > input + label {
      color: var(--pv-disabled-color);
    }

    .pv-section-item > input:enabled + label {
      cursor: pointer;
      color: var(--pv-font-color2);
    }

    .pv-section-item > input:enabled + label:hover {
      color: var(--pv-font-color0);
    }

    /* Section summary (left column label) */
    .pv-section-summary {
      grid-column: 1;
      color: var(--pv-font-color2);
      font-weight: 500;
      white-space: nowrap;
    }

    .pv-section-summary > span {
      display: inline-block;
      padding-left: 0.3em;
    }

    .pv-section-summary-in:disabled + label {
      color: var(--pv-font-color2);
    }

    /* Expand/collapse arrows */
    .pv-section-summary-in + label:before {
      display: inline-block;
      content: "\25b6";
      font-size: 11px;
      width: 15px;
      text-align: center;
    }

    .pv-section-summary-in:disabled + label:before {
      color: var(--pv-disabled-color);
    }

    .pv-section-summary-in:checked + label:before {
      content: "\25bc";
    }

    .pv-section-summary-in:checked + label > span {
      display: none;
    }

    .pv-section-summary,
    .pv-section-inline-details {
      padding-top: 4px;
    }

    .pv-section-inline-details {
      grid-column: 2 / -1;
    }

    .pv-section-details {
      grid-column: 1 / -1;
      margin-top: 4px;
      margin-bottom: 5px;
    }

    .pv-section-summary-in ~ .pv-section-details {
      display: none;
    }

    .pv-section-summary-in:checked ~ .pv-section-inline-details {
      display: none;
    }

    .pv-section-summary-in:checked ~ .pv-section-details {
      display: block;
    }

    .pv-section-summary-in:checked ~ .pv-section-details:has(.pv-var-list) {
      display: contents;
    }

    /* Variable (array) list */
    .pv-var-list,
    .pv-var-item {
      display: contents;
    }

    .pv-var-item > div,
    .pv-var-item label,
    .pv-var-item > .pv-var-name span {
      background-color: var(--pv-background-color-row-even);
      border-color: var(--pv-background-color-row-odd);
      margin-bottom: 0;
      padding-top: 2px;
    }

    .pv-var-list > li:nth-child(odd) > div,
    .pv-var-list > li:nth-child(odd) > label,
    .pv-var-list > li:nth-child(odd) > .pv-var-name span {
      background-color: var(--pv-background-color-row-odd);
      border-color: var(--pv-background-color-row-even);
    }

    .pv-var-name {
      grid-column: 1;
    }

    .pv-var-dims {
      grid-column: 2;
    }

    .pv-var-dtype {
      grid-column: 3;
      text-align: right;
      color: var(--pv-font-color2);
    }

    .pv-var-range {
      grid-column: 4;
      color: var(--pv-font-color3);
      font-size: 0.92em;
    }

    .pv-var-badges {
      grid-column: 5;
      padding-left: 8px;
    }

    .pv-var-name,
    .pv-var-dims,
    .pv-var-dtype,
    .pv-var-range {
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      padding-right: 10px;
    }

    .pv-var-name:hover,
    .pv-var-dims:hover,
    .pv-var-dtype:hover,
    .pv-var-range:hover {
      overflow: visible;
      width: auto;
      z-index: 1;
    }

    .pv-var-name span {
      padding-left: 25px !important;
    }

    .pv-var-name-active span {
      font-weight: 600;
    }

    /* Badges */
    .pv-badge {
      display: inline-block;
      font-size: 0.75em;
      font-weight: 600;
      padding: 1px 5px;
      border-radius: 3px;
      vertical-align: middle;
      line-height: 1.4;
    }

    .pv-badge-active {
      color: var(--pv-badge-active);
      border: 1px solid var(--pv-badge-active);
    }

    .pv-badge-normals {
      color: var(--pv-badge-normals);
      border: 1px solid var(--pv-badge-normals);
    }

    .pv-badge-vectors {
      color: var(--pv-badge-vectors);
      border: 1px solid var(--pv-badge-vectors);
    }

    .pv-badge-tcoords {
      color: var(--pv-badge-tcoords);
      border: 1px solid var(--pv-badge-tcoords);
    }

    /* Logo and Icons */
    .pv-logo {
      display: flex;
      align-items: center;
      flex-shrink: 0;
    }

    .pv-logo svg {
      width: 28px;
      height: 28px;
    }

    .pv-brand-logo {
      display: flex;
      align-items: center;
      flex-shrink: 0;
    }

    .pv-brand-logo svg {
      height: 20px;
      width: auto;
    }

    /* Children list (MultiBlock / PartitionedDataSet) */
    .pv-children-list {
      padding-left: 25px !important;
      list-style: none;
    }

    .pv-children-list li {
      padding: 1px 0;
    }

    .pv-child-name {
      font-weight: 500;
    }

    .pv-child-type {
      color: var(--pv-font-color2);
      font-style: italic;
    }

    .pv-child-type:before {
      content: "\00b7";
      padding: 0 6px;
      font-style: normal;
    }

    .pv-child-detail {
      color: var(--pv-font-color3);
      font-size: 0.9em;
    }

    .pv-child-detail:not(:empty):before {
      content: "\00b7";
      padding: 0 6px;
    }
    </style><pre class='pv-text-repr-fallback'>UnstructuredGrid (0x7ff58c0c2f20)
      N Cells:    824278
      N Points:   413250
      X Bounds:   3.299e+05, 3.442e+05
      Y Bounds:   4.253e+06, 4.271e+06
      Z Bounds:   1.494e+03, 2.723e+03
      N Arrays:   0</pre><div class='pv-wrap' style='display:none'><div class='pv-header'><span class='pv-logo'><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
      <defs>
        <linearGradient id="pv-ug-g1" x1="0" y1="0" x2="1" y2="1">
          <stop offset="0%" stop-color="#ffd040"/>
          <stop offset="100%" stop-color="#376fa0"/>
        </linearGradient>
      </defs>
      <polygon points="3,10 8,5 14,7 13,13 6,14" fill="#376fa0" opacity="0.9"/>
      <polygon points="14,7 22,4 20,12" fill="url(#pv-ug-g1)" opacity="0.85"/>
      <polygon points="22,4 29,9 27,17 20,12" fill="#1a4a70" opacity="0.85"/>
      <polygon points="13,13 20,12 16,20" fill="#ffd040" opacity="0.8"/>
      <polygon points="6,14 13,13 16,20 10,24 4,20" fill="#376fa0" opacity="0.8"/>
      <polygon points="16,20 10,24 18,28" fill="#1a4a70" opacity="0.85"/>
      <polygon points="20,12 27,17 26,25 18,28 16,20" fill="url(#pv-ug-g1)" opacity="0.8"/>
      <g stroke="rgba(255,255,255,0.6)" stroke-width="0.5" fill="none">
        <polygon points="3,10 8,5 14,7 13,13 6,14"/>
        <polygon points="14,7 22,4 20,12"/>
        <polygon points="22,4 29,9 27,17 20,12"/>
        <line x1="13" y1="13" x2="20" y2="12"/>
        <line x1="13" y1="13" x2="16" y2="20"/>
        <line x1="20" y1="12" x2="16" y2="20"/>
        <polygon points="6,14 13,13 16,20 10,24 4,20"/>
        <line x1="16" y1="20" x2="10" y2="24"/>
        <line x1="10" y1="24" x2="18" y2="28"/>
        <line x1="16" y1="20" x2="18" y2="28"/>
        <polygon points="20,12 27,17 26,25 18,28 16,20"/>
      </g>
      <g fill="rgba(255,255,255,0.8)">
        <circle cx="3" cy="10" r="0.9"/>
        <circle cx="8" cy="5" r="0.9"/>
        <circle cx="14" cy="7" r="0.9"/>
        <circle cx="22" cy="4" r="0.9"/>
        <circle cx="29" cy="9" r="0.9"/>
        <circle cx="13" cy="13" r="0.9"/>
        <circle cx="20" cy="12" r="0.9"/>
        <circle cx="6" cy="14" r="0.9"/>
        <circle cx="27" cy="17" r="0.9"/>
        <circle cx="16" cy="20" r="0.9"/>
        <circle cx="4" cy="20" r="0.9"/>
        <circle cx="10" cy="24" r="0.9"/>
        <circle cx="26" cy="25" r="0.9"/>
        <circle cx="18" cy="28" r="0.9"/>
      </g>
    </svg>
    </span><div class='pv-header-text'><div class='pv-obj-type'>UnstructuredGrid <span class='pv-header-badge'>413,250 points</span> <span class='pv-header-badge'>824,278 cells</span> <span class='pv-header-badge'>50.2 MiB</span></div></div><span class='pv-brand-logo'><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 90 24">
      <text x="0" y="18" font-family="system-ui,-apple-system,sans-serif" font-size="18" font-weight="700" font-style="italic" letter-spacing="-0.5">
        <tspan fill="#3776AB" opacity="0.7">P</tspan><tspan fill="#FFD43B" opacity="0.7">y</tspan><tspan fill="#008c9e">Vista</tspan>
      </text>
    </svg>
    </span></div><div class='pv-metadata'><div class='pv-meta-row pv-copyable'><span class='pv-meta-row-label'>Bounds</span><button class='pv-copy-btn' title='Copy to clipboard' data-copy='(329924.98816, 344152.930125, 4252833.48213, 4270951.09811, 1493.69165039, 2722.76904297)' onclick="navigator.clipboard.writeText(this.dataset.copy)">⧉</button><span class='pv-meta-entry'><span class='pv-meta-label'>X</span> [3.299e+05, 3.442e+05]</span><span class='pv-meta-entry'><span class='pv-meta-label'>Y</span> [4.253e+06, 4.271e+06]</span><span class='pv-meta-entry'><span class='pv-meta-label'>Z</span> [1.494e+03, 2.723e+03]</span></div></div><ul class='pv-sections'></ul></div></div>
    </div>
    <br />
    <br />

.. GENERATED FROM PYTHON SOURCE LINES 34-36

Load the GeoTIFF/texture (this could take a minute to download)
https://dl.dropbox.com/s/bp9j3fl3wbi0fld/downsampled_Geologic_map_on_air_photo.tif?dl=0

.. GENERATED FROM PYTHON SOURCE LINES 36-43

.. code-block:: Python

    url = "https://dl.dropbox.com/s/bp9j3fl3wbi0fld/downsampled_Geologic_map_on_air_photo.tif?dl=0"

    response = requests.get(url)  # noqa: S113
    filename = os.path.join(tempfile.gettempdir(), "downsampled_Geologic_map_on_air_photo.tif")  # noqa: PTH118
    open(filename, "wb").write(response.content)  # noqa: SIM115, PTH123






.. rst-class:: sphx-glr-script-out

 .. code-block:: none


    8175934



.. GENERATED FROM PYTHON SOURCE LINES 44-48

In the block below, we can use the ``get_gcps`` function to get the
Ground Control Points of the raster, however this depends on GDAL. For this
tutorial, we are going to hard code the GCPs to avoid having users install
GDAL.

.. GENERATED FROM PYTHON SOURCE LINES 48-75

.. code-block:: Python



    def get_gcps(filename):
        """
        Helper function retrieves the Ground Control
        Points of a GeoTIFF. Note that this requires gdal.
        """
        if rasterio is None:
            msg = "rasterio is required for this function"
            raise ImportError(msg)

        def get_point(gcp):
            return np.array([gcp.x, gcp.y, gcp.z])

        # Load a raster
        src = rasterio.open(filename)
        # Grab the Groung Control Points
        points = np.array([get_point(gcp) for gcp in src.gcps[0]])
        # Now Grab the three corners of their bounding box
        # -- This guarantees we grab the right points
        bounds = pv.PolyData(points).bounds
        origin = [bounds[0], bounds[2], bounds[4]]  # BOTTOM LEFT CORNER
        point_u = [bounds[1], bounds[2], bounds[4]]  # BOTTOM RIGHT CORNER
        point_v = [bounds[0], bounds[3], bounds[4]]  # TOP LEFT CORNER
        return origin, point_u, point_v









.. GENERATED FROM PYTHON SOURCE LINES 76-85

.. code-block:: Python


    # Fetch the GCPs
    # origin, point_u, point_v = get_gcps(filename)

    # Hard code GCPs
    origin = [310967.75148705335, 4238841.045453942, 0.0]
    point_u = [358682.9364281533, 4238841.045453942, 0.0]
    point_v = [310967.75148705335, 4276281.98755258, 0.0]








.. GENERATED FROM PYTHON SOURCE LINES 86-90

.. code-block:: Python


    # Use the GCPs to map the texture coordinates onto the topography surface
    topo.texture_map_to_plane(origin, point_u, point_v, inplace=True)





.. rst-class:: sphx-glr-script-out

 .. code-block:: none

    /home/runner/work/pyvista-tutorial/pyvista-tutorial/tutorial/03_figures/c_geological-map.py:88: PyVistaDeprecationWarning: 
    /home/runner/work/pyvista-tutorial/pyvista-tutorial/tutorial/03_figures/c_geological-map.py:88: Arguments 'origin', 'point_u', 'point_v' must be passed as keyword arguments to function 'DataSetFilters.texture_map_to_plane'.
    From version 0.50, passing these as positional arguments will result in a TypeError.
      topo.texture_map_to_plane(origin, point_u, point_v, inplace=True)


.. raw:: html

    <div class="output_subarea output_html rendered_html output_result">
    <div><style>/* PyVista HTML repr stylesheet.
     * Uses pv- prefix to avoid conflicts with other libraries.
     */

    :root {
      --pv-font-color0: var(--jp-content-font-color0, rgba(0, 0, 0, 1));
      --pv-font-color2: var(--jp-content-font-color2, rgba(0, 0, 0, 0.54));
      --pv-font-color3: var(--jp-content-font-color3, rgba(0, 0, 0, 0.38));
      --pv-border-color: var(--jp-border-color2, #e0e0e0);
      --pv-disabled-color: var(--jp-layout-color3, #bdbdbd);
      --pv-background-color-row-even: var(--jp-layout-color1, #f5f5f5);
      --pv-background-color-row-odd: var(--jp-layout-color2, #eeeeee);
      --pv-badge-active: #1b5e20;
      --pv-badge-normals: #0d47a1;
      --pv-badge-vectors: #00695c;
      --pv-badge-tcoords: #4527a0;
    }

    body[data-jp-theme-light="false"] {
      --pv-font-color0: var(--jp-content-font-color0, rgba(255, 255, 255, 1));
      --pv-font-color2: var(--jp-content-font-color2, rgba(255, 255, 255, 0.54));
      --pv-font-color3: var(--jp-content-font-color3, rgba(255, 255, 255, 0.38));
      --pv-border-color: var(--jp-border-color2, #424242);
      --pv-disabled-color: var(--jp-layout-color3, #616161);
      --pv-background-color-row-even: var(--jp-layout-color1, #1a1a1a);
      --pv-background-color-row-odd: var(--jp-layout-color2, #252525);
      --pv-badge-active: #66bb6a;
      --pv-badge-normals: #64b5f6;
      --pv-badge-vectors: #4db6ac;
      --pv-badge-tcoords: #b39ddb;
    }

    html[theme="dark"],
    html[data-theme="dark"],
    body[data-theme="dark"],
    body.vscode-dark {
      --pv-font-color0: rgba(255, 255, 255, 1);
      --pv-font-color2: rgba(255, 255, 255, 0.54);
      --pv-font-color3: rgba(255, 255, 255, 0.38);
      --pv-border-color: #424242;
      --pv-disabled-color: #616161;
      --pv-background-color-row-even: #1a1a1a;
      --pv-background-color-row-odd: #252525;
      --pv-badge-active: #66bb6a;
      --pv-badge-normals: #64b5f6;
      --pv-badge-vectors: #4db6ac;
      --pv-badge-tcoords: #b39ddb;
    }

    /* OS-level dark mode fallback: applies when no explicit data-theme is set */
    @media (prefers-color-scheme: dark) {
      html:not([data-theme="light"]) {
        --pv-font-color0: rgba(255, 255, 255, 1);
        --pv-font-color2: rgba(255, 255, 255, 0.54);
        --pv-font-color3: rgba(255, 255, 255, 0.38);
        --pv-border-color: #424242;
        --pv-disabled-color: #616161;
        --pv-background-color-row-even: #1a1a1a;
        --pv-background-color-row-odd: #252525;
        --pv-badge-active: #66bb6a;
        --pv-badge-normals: #64b5f6;
        --pv-badge-vectors: #4db6ac;
        --pv-badge-tcoords: #b39ddb;
      }
    }

    .pv-wrap {
      display: block !important;
      min-width: 300px;
      max-width: 700px;
      line-height: 1.6;
      padding-bottom: 4px;
      font-family: var(--jp-ui-font-family, sans-serif);
      font-size: var(--jp-ui-font-size1, 13px);
      color: var(--pv-font-color0);
    }

    .pv-text-repr-fallback {
      display: none;
    }

    /* Header */
    .pv-header {
      display: flex;
      align-items: center;
      gap: 8px;
      padding-top: 6px;
      padding-bottom: 6px;
      border-bottom: solid 1px var(--pv-border-color);
      margin-bottom: 4px;
    }

    .pv-header-text {
      display: flex;
      flex-direction: column;
      gap: 1px;
      min-width: 0;
      flex: 1;
    }

    .pv-obj-type {
      font-weight: 600;
      color: var(--pv-font-color0);
    }

    .pv-header-badge {
      display: inline-block;
      font-size: 0.75em;
      font-weight: 600;
      padding: 2px 7px;
      border-radius: 3px;
      color: var(--pv-font-color2);
      border: 1px solid var(--pv-border-color);
      white-space: nowrap;
    }

    /* Metadata (always-visible key-value rows) */
    .pv-metadata {
      margin: 4px 0 6px 0;
      font-size: 0.92em;
      line-height: 1.5;
    }

    .pv-meta-row {
      display: flex;
      flex-wrap: wrap;
      gap: 1px 14px;
      padding: 1px 0;
    }

    .pv-meta-row-label {
      color: var(--pv-font-color2);
      font-weight: 500;
      white-space: nowrap;
      min-width: 60px;
    }

    .pv-meta-entry {
      white-space: nowrap;
    }

    /* Copy-to-clipboard button */
    .pv-copy-btn {
      display: inline-block;
      cursor: pointer;
      opacity: 0.5;
      font-size: 0.85em;
      padding: 0 3px;
      vertical-align: middle;
      transition: opacity 0.15s;
      user-select: none;
      border: none;
      background: none;
      color: var(--pv-font-color3);
    }

    .pv-copy-btn:hover {
      opacity: 1;
      color: var(--pv-font-color0);
    }

    .pv-meta-label {
      color: var(--pv-font-color3);
      font-weight: 400;
      padding-right: 2px;
    }

    /* Sections grid */
    .pv-sections {
      padding-left: 0 !important;
      display: grid;
      grid-template-columns: 150px auto auto auto 1fr 20px 20px;
      margin-block-start: 0;
      margin-block-end: 0;
      list-style: none;
    }

    .pv-section-item {
      display: contents;
    }

    /* Hidden checkbox for expand/collapse */
    .pv-section-item > input {
      display: block;
      opacity: 0;
      height: 0;
      margin: 0;
    }

    .pv-section-item > input + label {
      color: var(--pv-disabled-color);
    }

    .pv-section-item > input:enabled + label {
      cursor: pointer;
      color: var(--pv-font-color2);
    }

    .pv-section-item > input:enabled + label:hover {
      color: var(--pv-font-color0);
    }

    /* Section summary (left column label) */
    .pv-section-summary {
      grid-column: 1;
      color: var(--pv-font-color2);
      font-weight: 500;
      white-space: nowrap;
    }

    .pv-section-summary > span {
      display: inline-block;
      padding-left: 0.3em;
    }

    .pv-section-summary-in:disabled + label {
      color: var(--pv-font-color2);
    }

    /* Expand/collapse arrows */
    .pv-section-summary-in + label:before {
      display: inline-block;
      content: "\25b6";
      font-size: 11px;
      width: 15px;
      text-align: center;
    }

    .pv-section-summary-in:disabled + label:before {
      color: var(--pv-disabled-color);
    }

    .pv-section-summary-in:checked + label:before {
      content: "\25bc";
    }

    .pv-section-summary-in:checked + label > span {
      display: none;
    }

    .pv-section-summary,
    .pv-section-inline-details {
      padding-top: 4px;
    }

    .pv-section-inline-details {
      grid-column: 2 / -1;
    }

    .pv-section-details {
      grid-column: 1 / -1;
      margin-top: 4px;
      margin-bottom: 5px;
    }

    .pv-section-summary-in ~ .pv-section-details {
      display: none;
    }

    .pv-section-summary-in:checked ~ .pv-section-inline-details {
      display: none;
    }

    .pv-section-summary-in:checked ~ .pv-section-details {
      display: block;
    }

    .pv-section-summary-in:checked ~ .pv-section-details:has(.pv-var-list) {
      display: contents;
    }

    /* Variable (array) list */
    .pv-var-list,
    .pv-var-item {
      display: contents;
    }

    .pv-var-item > div,
    .pv-var-item label,
    .pv-var-item > .pv-var-name span {
      background-color: var(--pv-background-color-row-even);
      border-color: var(--pv-background-color-row-odd);
      margin-bottom: 0;
      padding-top: 2px;
    }

    .pv-var-list > li:nth-child(odd) > div,
    .pv-var-list > li:nth-child(odd) > label,
    .pv-var-list > li:nth-child(odd) > .pv-var-name span {
      background-color: var(--pv-background-color-row-odd);
      border-color: var(--pv-background-color-row-even);
    }

    .pv-var-name {
      grid-column: 1;
    }

    .pv-var-dims {
      grid-column: 2;
    }

    .pv-var-dtype {
      grid-column: 3;
      text-align: right;
      color: var(--pv-font-color2);
    }

    .pv-var-range {
      grid-column: 4;
      color: var(--pv-font-color3);
      font-size: 0.92em;
    }

    .pv-var-badges {
      grid-column: 5;
      padding-left: 8px;
    }

    .pv-var-name,
    .pv-var-dims,
    .pv-var-dtype,
    .pv-var-range {
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      padding-right: 10px;
    }

    .pv-var-name:hover,
    .pv-var-dims:hover,
    .pv-var-dtype:hover,
    .pv-var-range:hover {
      overflow: visible;
      width: auto;
      z-index: 1;
    }

    .pv-var-name span {
      padding-left: 25px !important;
    }

    .pv-var-name-active span {
      font-weight: 600;
    }

    /* Badges */
    .pv-badge {
      display: inline-block;
      font-size: 0.75em;
      font-weight: 600;
      padding: 1px 5px;
      border-radius: 3px;
      vertical-align: middle;
      line-height: 1.4;
    }

    .pv-badge-active {
      color: var(--pv-badge-active);
      border: 1px solid var(--pv-badge-active);
    }

    .pv-badge-normals {
      color: var(--pv-badge-normals);
      border: 1px solid var(--pv-badge-normals);
    }

    .pv-badge-vectors {
      color: var(--pv-badge-vectors);
      border: 1px solid var(--pv-badge-vectors);
    }

    .pv-badge-tcoords {
      color: var(--pv-badge-tcoords);
      border: 1px solid var(--pv-badge-tcoords);
    }

    /* Logo and Icons */
    .pv-logo {
      display: flex;
      align-items: center;
      flex-shrink: 0;
    }

    .pv-logo svg {
      width: 28px;
      height: 28px;
    }

    .pv-brand-logo {
      display: flex;
      align-items: center;
      flex-shrink: 0;
    }

    .pv-brand-logo svg {
      height: 20px;
      width: auto;
    }

    /* Children list (MultiBlock / PartitionedDataSet) */
    .pv-children-list {
      padding-left: 25px !important;
      list-style: none;
    }

    .pv-children-list li {
      padding: 1px 0;
    }

    .pv-child-name {
      font-weight: 500;
    }

    .pv-child-type {
      color: var(--pv-font-color2);
      font-style: italic;
    }

    .pv-child-type:before {
      content: "\00b7";
      padding: 0 6px;
      font-style: normal;
    }

    .pv-child-detail {
      color: var(--pv-font-color3);
      font-size: 0.9em;
    }

    .pv-child-detail:not(:empty):before {
      content: "\00b7";
      padding: 0 6px;
    }
    </style><pre class='pv-text-repr-fallback'>UnstructuredGrid (0x7ff58c0c2f20)
      N Cells:    824278
      N Points:   413250
      X Bounds:   3.299e+05, 3.442e+05
      Y Bounds:   4.253e+06, 4.271e+06
      Z Bounds:   1.494e+03, 2.723e+03
      N Arrays:   1</pre><div class='pv-wrap' style='display:none'><div class='pv-header'><span class='pv-logo'><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
      <defs>
        <linearGradient id="pv-ug-g1" x1="0" y1="0" x2="1" y2="1">
          <stop offset="0%" stop-color="#ffd040"/>
          <stop offset="100%" stop-color="#376fa0"/>
        </linearGradient>
      </defs>
      <polygon points="3,10 8,5 14,7 13,13 6,14" fill="#376fa0" opacity="0.9"/>
      <polygon points="14,7 22,4 20,12" fill="url(#pv-ug-g1)" opacity="0.85"/>
      <polygon points="22,4 29,9 27,17 20,12" fill="#1a4a70" opacity="0.85"/>
      <polygon points="13,13 20,12 16,20" fill="#ffd040" opacity="0.8"/>
      <polygon points="6,14 13,13 16,20 10,24 4,20" fill="#376fa0" opacity="0.8"/>
      <polygon points="16,20 10,24 18,28" fill="#1a4a70" opacity="0.85"/>
      <polygon points="20,12 27,17 26,25 18,28 16,20" fill="url(#pv-ug-g1)" opacity="0.8"/>
      <g stroke="rgba(255,255,255,0.6)" stroke-width="0.5" fill="none">
        <polygon points="3,10 8,5 14,7 13,13 6,14"/>
        <polygon points="14,7 22,4 20,12"/>
        <polygon points="22,4 29,9 27,17 20,12"/>
        <line x1="13" y1="13" x2="20" y2="12"/>
        <line x1="13" y1="13" x2="16" y2="20"/>
        <line x1="20" y1="12" x2="16" y2="20"/>
        <polygon points="6,14 13,13 16,20 10,24 4,20"/>
        <line x1="16" y1="20" x2="10" y2="24"/>
        <line x1="10" y1="24" x2="18" y2="28"/>
        <line x1="16" y1="20" x2="18" y2="28"/>
        <polygon points="20,12 27,17 26,25 18,28 16,20"/>
      </g>
      <g fill="rgba(255,255,255,0.8)">
        <circle cx="3" cy="10" r="0.9"/>
        <circle cx="8" cy="5" r="0.9"/>
        <circle cx="14" cy="7" r="0.9"/>
        <circle cx="22" cy="4" r="0.9"/>
        <circle cx="29" cy="9" r="0.9"/>
        <circle cx="13" cy="13" r="0.9"/>
        <circle cx="20" cy="12" r="0.9"/>
        <circle cx="6" cy="14" r="0.9"/>
        <circle cx="27" cy="17" r="0.9"/>
        <circle cx="16" cy="20" r="0.9"/>
        <circle cx="4" cy="20" r="0.9"/>
        <circle cx="10" cy="24" r="0.9"/>
        <circle cx="26" cy="25" r="0.9"/>
        <circle cx="18" cy="28" r="0.9"/>
      </g>
    </svg>
    </span><div class='pv-header-text'><div class='pv-obj-type'>UnstructuredGrid <span class='pv-header-badge'>413,250 points</span> <span class='pv-header-badge'>824,278 cells</span> <span class='pv-header-badge'>53.4 MiB</span></div></div><span class='pv-brand-logo'><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 90 24">
      <text x="0" y="18" font-family="system-ui,-apple-system,sans-serif" font-size="18" font-weight="700" font-style="italic" letter-spacing="-0.5">
        <tspan fill="#3776AB" opacity="0.7">P</tspan><tspan fill="#FFD43B" opacity="0.7">y</tspan><tspan fill="#008c9e">Vista</tspan>
      </text>
    </svg>
    </span></div><div class='pv-metadata'><div class='pv-meta-row pv-copyable'><span class='pv-meta-row-label'>Bounds</span><button class='pv-copy-btn' title='Copy to clipboard' data-copy='(329924.98816, 344152.930125, 4252833.48213, 4270951.09811, 1493.69165039, 2722.76904297)' onclick="navigator.clipboard.writeText(this.dataset.copy)">⧉</button><span class='pv-meta-entry'><span class='pv-meta-label'>X</span> [3.299e+05, 3.442e+05]</span><span class='pv-meta-entry'><span class='pv-meta-label'>Y</span> [4.253e+06, 4.271e+06]</span><span class='pv-meta-entry'><span class='pv-meta-label'>Z</span> [1.494e+03, 2.723e+03]</span></div></div><ul class='pv-sections'><li class='pv-section-item'><input id='section-a7cc0036-efe9-4f6a-8067-0bb4a1fd0e93' class='pv-section-summary-in' type='checkbox' checked /><label for='section-a7cc0036-efe9-4f6a-8067-0bb4a1fd0e93' class='pv-section-summary' title='Expand/collapse section'>Point Data: <span>(1)</span></label><div class='pv-section-inline-details'></div><div class='pv-section-details'><ul class='pv-var-list'><li class='pv-var-item'><div class='pv-var-name'><span>Texture Coordinates</span><button class='pv-copy-btn' title='Copy to clipboard' data-copy='Texture Coordinates' onclick="navigator.clipboard.writeText(this.dataset.copy)">⧉</button></div><div class='pv-var-dims'>2 comp</div><div class='pv-var-dtype'>float32</div><div class='pv-var-range'>[3.737e-01, 8.576e-01]</div><div class='pv-var-badges'> <span class='pv-badge pv-badge-tcoords'>tcoords</span></div></li></ul></div></li></ul></div></div>
    </div>
    <br />
    <br />

.. GENERATED FROM PYTHON SOURCE LINES 91-92

Show GCPs in relation to topo surface with texture coordinates displayed

.. GENERATED FROM PYTHON SOURCE LINES 92-109

.. code-block:: Python

    pl = pv.Plotter()
    pl.add_point_labels(
        np.array(
            [
                origin,
                point_u,
                point_v,
            ]
        ),
        ["Origin", "Point U", "Point V"],
        point_size=5,
    )

    pl.add_mesh(topo)
    pl.show(cpos="xy")









.. tab-set::



   .. tab-item:: Static Scene



            
     .. image-sg:: /tutorial/03_figures/images/sphx_glr_c_geological-map_001.png
        :alt: c geological map
        :srcset: /tutorial/03_figures/images/sphx_glr_c_geological-map_001.png
        :class: sphx-glr-single-img
     


   .. tab-item:: Interactive Scene



       .. offlineviewer:: /home/runner/work/pyvista-tutorial/pyvista-tutorial/doc/source/tutorial/03_figures/images/sphx_glr_c_geological-map_001.vtksz






.. GENERATED FROM PYTHON SOURCE LINES 110-111

Read the GeoTIFF as a ``Texture`` in PyVista:

.. GENERATED FROM PYTHON SOURCE LINES 111-124

.. code-block:: Python

    texture = pv.read_texture(filename)

    # Now plot the topo surface with the texture draped over it
    # And make window size large for a high-res screenshot
    pl = pv.Plotter(window_size=np.array([1024, 768]) * 3)
    pl.add_mesh(topo, texture=texture)
    pl.camera_position = [
        (337461.4124956896, 4257141.430658634, 2738.4956020899253),
        (339000.40935731295, 4260394.940646875, 1724.0720826501868),
        (0.10526647627366331, 0.2502863297360612, 0.962432190920575),
    ]
    pl.show()








.. tab-set::



   .. tab-item:: Static Scene



            
     .. image-sg:: /tutorial/03_figures/images/sphx_glr_c_geological-map_002.png
        :alt: c geological map
        :srcset: /tutorial/03_figures/images/sphx_glr_c_geological-map_002.png
        :class: sphx-glr-single-img
     


   .. tab-item:: Interactive Scene



       .. offlineviewer:: /home/runner/work/pyvista-tutorial/pyvista-tutorial/doc/source/tutorial/03_figures/images/sphx_glr_c_geological-map_002.vtksz






.. GENERATED FROM PYTHON SOURCE LINES 125-132

.. raw:: html

    <center>
      <a target="_blank" href="https://colab.research.google.com/github/pyvista/pyvista-tutorial/blob/tutorial/notebooks/03_figures/c_geological-map.ipynb">
        <img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/ width="150px">
      </a>
    </center>


.. rst-class:: sphx-glr-timing

   **Total running time of the script:** (0 minutes 13.755 seconds)


.. _sphx_glr_download_tutorial_03_figures_c_geological-map.py:

.. only:: html

  .. container:: sphx-glr-footer sphx-glr-footer-example

    .. container:: binder-badge

      .. image:: images/binder_badge_logo.svg
        :target: https://mybinder.org/v2/gh/pyvista/pyvista-tutorial/tutorial?urlpath=lab/tree/notebooks/tutorial/03_figures/c_geological-map.ipynb
        :alt: Launch binder
        :width: 150 px

    .. container:: sphx-glr-download sphx-glr-download-jupyter

      :download:`Download Jupyter notebook: c_geological-map.ipynb <c_geological-map.ipynb>`

    .. container:: sphx-glr-download sphx-glr-download-python

      :download:`Download Python source code: c_geological-map.py <c_geological-map.py>`

    .. container:: sphx-glr-download sphx-glr-download-zip

      :download:`Download zipped: c_geological-map.zip <c_geological-map.zip>`


.. only:: html

 .. rst-class:: sphx-glr-signature

    `Gallery generated by Sphinx-Gallery <https://sphinx-gallery.github.io>`_
