Ursprung und Ausdehnung in imshow#

imshow() ermöglicht es Ihnen, ein Bild (entweder ein 2D-Array, das farblich abgebildet wird (basierend auf norm und cmap) oder ein 3D-RGB(A)-Array, das unverändert verwendet wird) in einem rechteckigen Bereich im Datenraum darzustellen. Die Ausrichtung des Bildes in der endgültigen Darstellung wird durch die Schlüsselwortargumente origin und extent (und Attribute der resultierenden AxesImage-Instanz) und die Datenlimits der Achsen gesteuert.

Das Schlüsselwortargument extent steuert die Bounding Box in Datenkoordinaten, die das Bild ausfüllen soll, spezifiziert als (links, rechts, unten, oben) in **Datenkoordinaten**. Das Schlüsselwortargument origin steuert, wie das Bild diese Bounding Box ausfüllt, und die Ausrichtung im endgültig gerenderten Bild wird auch von den Achsenlimits beeinflusst.

Hinweis

Ein Großteil des untenstehenden Codes dient dem Hinzufügen von Beschriftungen und informativen Texten zu den Plots. Die beschriebenen Effekte von origin und extent sind in den Plots sichtbar, ohne dass alle Code-Details verfolgt werden müssen.

Für ein schnelles Verständnis können Sie die untenstehenden Code-Details überspringen und direkt mit der Diskussion der Ergebnisse fortfahren.

import matplotlib.pyplot as plt
import numpy as np

from matplotlib.gridspec import GridSpec


def index_to_coordinate(index, extent, origin):
    """Return the pixel center of an index."""
    left, right, bottom, top = extent

    hshift = 0.5 * np.sign(right - left)
    left, right = left + hshift, right - hshift
    vshift = 0.5 * np.sign(top - bottom)
    bottom, top = bottom + vshift, top - vshift

    if origin == 'upper':
        bottom, top = top, bottom

    return {
        "[0, 0]": (left, bottom),
        "[M', 0]": (left, top),
        "[0, N']": (right, bottom),
        "[M', N']": (right, top),
    }[index]


def get_index_label_pos(index, extent, origin, inverted_xindex):
    """
    Return the desired position and horizontal alignment of an index label.
    """
    if extent is None:
        extent = lookup_extent(origin)
    left, right, bottom, top = extent
    x, y = index_to_coordinate(index, extent, origin)

    is_x0 = index[-2:] == "0]"
    halign = 'left' if is_x0 ^ inverted_xindex else 'right'
    hshift = 0.5 * np.sign(left - right)
    x += hshift * (1 if is_x0 else -1)
    return x, y, halign


def get_color(index, data, cmap):
    """Return the data color of an index."""
    val = {
        "[0, 0]": data[0, 0],
        "[0, N']": data[0, -1],
        "[M', 0]": data[-1, 0],
        "[M', N']": data[-1, -1],
    }[index]
    return cmap(val / data.max())


def lookup_extent(origin):
    """Return extent for label positioning when not given explicitly."""
    if origin == 'lower':
        return (-0.5, 6.5, -0.5, 5.5)
    else:
        return (-0.5, 6.5, 5.5, -0.5)


def set_extent_None_text(ax):
    ax.text(3, 2.5, 'equals\nextent=None', size='large',
            ha='center', va='center', color='w')


def plot_imshow_with_labels(ax, data, extent, origin, xlim, ylim):
    """Actually run ``imshow()`` and add extent and index labels."""
    im = ax.imshow(data, origin=origin, extent=extent)

    # extent labels (left, right, bottom, top)
    left, right, bottom, top = im.get_extent()
    if xlim is None or top > bottom:
        upper_string, lower_string = 'top', 'bottom'
    else:
        upper_string, lower_string = 'bottom', 'top'
    if ylim is None or left < right:
        port_string, starboard_string = 'left', 'right'
        inverted_xindex = False
    else:
        port_string, starboard_string = 'right', 'left'
        inverted_xindex = True
    bbox_kwargs = {'fc': 'w', 'alpha': .75, 'boxstyle': "round4"}
    ann_kwargs = {'xycoords': 'axes fraction',
                  'textcoords': 'offset points',
                  'bbox': bbox_kwargs}
    ax.annotate(upper_string, xy=(.5, 1), xytext=(0, -1),
                ha='center', va='top', **ann_kwargs)
    ax.annotate(lower_string, xy=(.5, 0), xytext=(0, 1),
                ha='center', va='bottom', **ann_kwargs)
    ax.annotate(port_string, xy=(0, .5), xytext=(1, 0),
                ha='left', va='center', rotation=90,
                **ann_kwargs)
    ax.annotate(starboard_string, xy=(1, .5), xytext=(-1, 0),
                ha='right', va='center', rotation=-90,
                **ann_kwargs)
    ax.set_title(f'origin: {origin}')

    # index labels
    for index in ["[0, 0]", "[0, N']", "[M', 0]", "[M', N']"]:
        tx, ty, halign = get_index_label_pos(index, extent, origin,
                                             inverted_xindex)
        facecolor = get_color(index, data, im.get_cmap())
        ax.text(tx, ty, index, color='white', ha=halign, va='center',
                bbox={'boxstyle': 'square', 'facecolor': facecolor})
    if xlim:
        ax.set_xlim(*xlim)
    if ylim:
        ax.set_ylim(*ylim)


def generate_imshow_demo_grid(extents, xlim=None, ylim=None):
    N = len(extents)
    fig = plt.figure(tight_layout=True)
    fig.set_size_inches(6, N * (11.25) / 5)
    gs = GridSpec(N, 5, figure=fig)

    columns = {'label': [fig.add_subplot(gs[j, 0]) for j in range(N)],
               'upper': [fig.add_subplot(gs[j, 1:3]) for j in range(N)],
               'lower': [fig.add_subplot(gs[j, 3:5]) for j in range(N)]}
    x, y = np.ogrid[0:6, 0:7]
    data = x + y

    for origin in ['upper', 'lower']:
        for ax, extent in zip(columns[origin], extents):
            plot_imshow_with_labels(ax, data, extent, origin, xlim, ylim)

    columns['label'][0].set_title('extent=')
    for ax, extent in zip(columns['label'], extents):
        if extent is None:
            text = 'None'
        else:
            left, right, bottom, top = extent
            text = (f'left: {left:0.1f}\nright: {right:0.1f}\n'
                    f'bottom: {bottom:0.1f}\ntop: {top:0.1f}\n')
        ax.text(1., .5, text, transform=ax.transAxes, ha='right', va='center')
        ax.axis('off')
    return columns

Standardausdehnung#

Zuerst werfen wir einen Blick auf die Standardeinstellung extent=None

generate_imshow_demo_grid(extents=[None])
extent=, origin: upper, origin: lower

Im Allgemeinen läuft bei einem Array der Form (M, N) der erste Index vertikal und der zweite Index horizontal. Die Pixelzentren liegen bei ganzzahligen Positionen von 0 bis N' = N - 1 horizontal und von 0 bis M' = M - 1 vertikal. origin bestimmt, wie die Daten in die Bounding Box gefüllt werden.

Für origin='lower'

  • [0, 0] ist bei (links, unten)

  • [M', 0] ist bei (links, oben)

  • [0, N'] ist bei (rechts, unten)

  • [M', N'] ist bei (rechts, oben)

origin='upper' kehrt die vertikale Achsenrichtung und Füllung um

  • [0, 0] ist bei (links, oben)

  • [M', 0] ist bei (links, unten)

  • [0, N'] ist bei (rechts, oben)

  • [M', N'] ist bei (rechts, unten)

Zusammenfassend lässt sich sagen, dass die Position des Index [0, 0] sowie die Ausdehnung von origin beeinflusst werden

Ursprung

Position von [0, 0]

Ausdehnung

oben

oben links

(-0.5, numcols-0.5, numrows-0.5, -0.5)

unten

unten links

(-0.5, numcols-0.5, -0.5, numrows-0.5)

Der Standardwert von origin wird durch rcParams["image.origin"] (Standard: 'upper') festgelegt, der standardmäßig auf 'upper' gesetzt ist, um den mathematischen Konventionen für Matrixindizes und den Bildindizierungskonventionen in der Computergrafik zu entsprechen.

Explizite Ausdehnung#

Durch Setzen von extent definieren wir die Koordinaten des Bildbereichs. Die zugrundeliegenden Bilddaten werden interpoliert/resampelt, um diesen Bereich auszufüllen.

Wenn die Achsen für autoskalieren eingestellt sind, werden die Ansichtslimits der Achsen an die extent angepasst, was sicherstellt, dass die durch (links, unten) festgelegten Koordinaten unten links auf der Achse liegen! Dies kann jedoch die Achsen umkehren, sodass sie nicht in der 'natürlichen' Richtung ansteigen.

extents = [(-0.5, 6.5, -0.5, 5.5),
           (-0.5, 6.5, 5.5, -0.5),
           (6.5, -0.5, -0.5, 5.5),
           (6.5, -0.5, 5.5, -0.5)]

columns = generate_imshow_demo_grid(extents)
set_extent_None_text(columns['upper'][1])
set_extent_None_text(columns['lower'][0])
extent=, origin: upper, origin: upper, origin: upper, origin: upper, origin: lower, origin: lower, origin: lower, origin: lower

Explizite Ausdehnung und Achsenlimits#

Wenn wir die Achsenlimits durch explizites Setzen von set_xlim / set_ylim festlegen, erzwingen wir eine bestimmte Größe und Ausrichtung der Achsen. Dies kann die 'links-rechts'- und 'oben-unten'-Richtung des Bildes von der Ausrichtung auf dem Bildschirm entkoppeln.

Im folgenden Beispiel haben wir die Limits etwas größer als die Ausdehnung gewählt (beachten Sie die weißen Bereiche innerhalb der Achsen).

Während wir die Ausdehnungen wie in den vorherigen Beispielen beibehalten, wird die Koordinate (0, 0) nun explizit unten links platziert und die Werte steigen nach oben und nach rechts (aus Sicht des Betrachters) an. Wir können sehen, dass

  • Die Koordinate (links, unten) verankert das Bild, das dann die Box in Richtung des Punktes (rechts, oben) im Datenraum ausfüllt.

  • Die erste Spalte liegt immer am nächsten zu 'links'.

  • origin steuert, ob sich die erste Zeile am nächsten zu 'oben' oder 'unten' befindet.

  • Das Bild kann in beiden Richtungen invertiert sein.

  • Die 'links-rechts'- und 'oben-unten'-Richtung des Bildes kann von der Ausrichtung auf dem Bildschirm entkoppelt sein.

generate_imshow_demo_grid(extents=[None] + extents,
                          xlim=(-2, 8), ylim=(-1, 6))

plt.show()
extent=, origin: upper, origin: upper, origin: upper, origin: upper, origin: upper, origin: lower, origin: lower, origin: lower, origin: lower, origin: lower

Gesamtlaufzeit des Skripts: (0 Minuten 4,521 Sekunden)

Galerie generiert von Sphinx-Gallery