[PYTHON] Erstellen Sie einen Axtgenerator und zeichnen Sie unendlich viele Diagramme

Einführung

Wenn Sie mit jupyter Bilder erkennen, möchten Sie möglicherweise viele Bilder und Grafiken anordnen. Alle MNIST-Lehrerbilder anzeigen. (Wenn du es wirklich tust, wirst du nicht zurückkommen und ich denke, es wird fallen)

show_mnist_NG.py


import matplotlib.cm as cm
import matplotlib.pyplot as plt
import keras

mnist = keras.datasets.mnist.load_data()
(X_train, t_train), (X_test, t_test) = mnist

f, ax = plt.subplots(3000,20, figsize=(20,3000))
axes = ax.reshape((-1,))
for x, ax in zip(X_train, axes):
    ax.imshow(x, cmap=cm.gray)
    ax.axis('equal')
    ax.axis('off')
plt.show()

Es wurde jedoch ärgerlich, jedes Mal matplotlib aufzurufen, wenn ich eine Grafik oder ein Bild zeichnete. Daher habe ich einen Mechanismus erstellt, um es ohne Erlaubnis anzuzeigen.

matplotlib.pyplot.subplots()

Verwenden Sie subplots (), um Bilder und Grafiken anzuordnen.

subplots_rowcol.py


import matplotlib.pyplot as plt

nrows = 3
ncols = 5
f, axes = plt.subplots(nrows, ncols, squeeze=False, figsize=(ncols*2.0, nrows*2.0))
for i in range(13):
    r = i // ncols
    c = i % ncols
    axes[r,c].plot(range(10), range(r+c,10+r+c))  #Entsprechende Grafik
plt.show()

Aber zu Nebenhandlungen (),

Es hat den Nachteil, dass es nicht einfach zu bedienen ist. Insbesondere ist es schwierig zu verwenden, wenn Sie das Bild einfach auf jupyter anzeigen möchten.

Sollten wir nicht einfach Zeile für Zeile plt.show ()?

Die erste Idee, die ich hatte, war, subplots () und show () Zeile für Zeile aufzurufen.

subplots_1row.py


import matplotlib.pyplot as plt

ncols = 5
f, axes = plt.subplots(1, ncols, figsize=(ncols*2.0, 2.0))
for i in range(13):
    axes[i % 5].plot(range(10), range(i,10+i))  #Entsprechende Grafik
    if i % 5 == 4:
        plt.show()
        f, axes = plt.subplots(1, ncols, figsize=(ncols*2.0, 2.0))
plt.show()

Wenn eine große Anzahl von Bildern angezeigt wird, werden sie nach und nach angezeigt, sodass das Gefühl des Wartens erheblich reduziert wird. Sie müssen nicht über das Layout nachdenken, da Sie nur die Anzahl der Diagramme für eine Linie sowie die vertikalen und horizontalen Größen benötigen.

Dies ist in Ordnung, wenn Sie es in eine einfache Schleife integrieren möchten. Das Überprüfen der Achsen ist jedoch umständlich.

Wäre es nicht schön, einen Generator zu haben?

Ich möchte den mühsamen Prozess nicht oft schreiben, also habe ich ihn zu einem Generator gemacht.

axes_generator.py


import matplotlib.pyplot as plt

def axes_generator(ncols):
    while True:
        f, axes = plt.subplots(1, ncols, figsize=(ncols*2.0, 2.0))
        for c in range(ncols):
            yield axes[c]
        plt.show()

ag = axes_generator(5)
for i, ax in zip(range(13), ag):
    ax.plot(range(10), range(i,10+i))  #Entsprechende Grafik
plt.show()

Dank des Generators kann der Prozess des Zeichnens des Diagramms diesem gewidmet werden. Das Innere der Schleife ist erfrischend und leicht zu lesen.

Wenn Sie ein Diagramm hinzufügen möchten, rufen Sie __next__ () auf, und der Iterator gibt die folgenden Achsen zurück.

ag = axes_generator(5)
for i, ax in zip(range(13), ag):
    ax.plot(range(10), range(i,10+i))  #Entsprechende Grafik
    if i % 3 == 2:
        ax = ag.__next__()
        ax.bar(range(5), range(i,i+5))  #Entsprechende Grafik
plt.show()

Aber es ist unangenehm, die zusätzlichen Achsen zu sehen.

Wäre es nicht schön, eine Generatorklasse zu haben?

Ich wollte den Überschuss verbergen, also beschloss ich, ihn zu klassifizieren.

AxesGenerator.py


import matplotlib.pyplot as plt

class AxesGenerator:
    def __init__(self, ncols:int=6, figsize:tuple=None, *args, **kwargs):
        self._ncols = ncols
        self._figsize = figsize
        self._axes = []

    def __iter__(self):
        while True:
            yield self.get()

    def get(self):
        if len(self._axes) == 0:
            plt.show()
            f, axes = plt.subplots(nrows=1, ncols=self._ncols, figsize=self._figsize)
            self._axes = list(axes) if self._ncols > 1 else [axes,]
        ax = self._axes.pop(0)
        return ax

    def flush(self):
        for ax in self._axes:
            ax.axis('off')
        plt.show()
        self._axes = []

ncols = 5
ag = AxesGenerator(ncols, figsize=(ncols*2.0, 2.0))
for i, ax in zip(range(13), ag):
    ax.plot(range(10), range(i,10+i))  #Entsprechende Grafik
    if i % 3 == 2:
        ax = ag.get()
        ax.bar(range(5), range(i,i+5))  #Entsprechende Grafik
ag.flush()

Es wird ziemlich gut. Ich rufe jedoch flush () auf, um aufzuräumen, aber ich verwende fälschlicherweise plt.show (), vergesse, es zu schreiben, oder etwas anderes.

Wenn das Aufräumen mühsam ist, warum nicht dem Satz mit überlassen?

Sie sollten in der Lage sein, die with-Anweisung zum Bereinigen zu verwenden. Für mit wurden \ _ \ _ enter \ _ \ _ () und \ _ \ _ exit \ _ \ _ () hinzugefügt.

Übrigens akzeptiert der Konstruktor jetzt das Argument von subplots ().

AxesGenerator.py


import matplotlib.pyplot as plt

class AxesGenerator:
    def __init__(self, ncols:int=6, sharey=False, subplot_kw=None, gridspec_kw=None, **fig_kw):
        self._ncols = ncols
        self._sharey = sharey
        self._subplot_kw = subplot_kw
        self._gridspec_kw = gridspec_kw
        self._fig_kw = fig_kw
        self._axes = []

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.flush()
        return True  #Ausnahmebehandlung entfällt

    def __iter__(self):
        while True:
            yield self.get()

    def get(self):
        if len(self._axes) == 0:
            plt.show()
            f, axes = plt.subplots(nrows=1, ncols=self._ncols, sharey=self._sharey, subplot_kw=self._subplot_kw, gridspec_kw=self._gridspec_kw, **self._fig_kw)
            self._axes = list(axes) if self._ncols > 1 else [axes,]
        ax = self._axes.pop(0)
        return ax

    def flush(self):
        for ax in self._axes:
            ax.axis('off')
        plt.show()
        self._axes = []

ncols = 5
with AxesGenerator(ncols, figsize=(ncols*2.0, 2.0)) as ag:
    for i, ax in zip(range(13), ag):
        ax.plot(range(10), range(i,10+i))  #Entsprechende Grafik
        if i % 3 == 2:
            ax = ag.get()
            ax.bar(range(5), range(i,i+5))  #Entsprechende Grafik

abschließend

Ich konnte das Ziel erreichen, schnell eine große Anzahl von Grafiken und Bildern anzuzeigen. Jetzt können Sie sogar alle 60.000 MNIST-Lehrerbilder anzeigen. (Ich denke, wenn du es wirklich tust, wird es auf den Weg fallen)

show_mnist_OK.py


import matplotlib.cm as cm
import matplotlib.pyplot as plt
import keras

mnist = keras.datasets.mnist.load_data()
(X_train, t_train), (X_test, t_test) = mnist

with AxesGenerator(ncols=20, figsize=(20,1)) as ag:
    for x, ax in zip(X_train, ag):
        ax.imshow(x, cmap=cm.gray)
        ax.axis('equal')
        ax.axis('off')

Ich habe das Gefühl, dass ich den Code ein bisschen schlauer machen kann, aber eines Tages.

Recommended Posts

Erstellen Sie einen Axtgenerator und zeichnen Sie unendlich viele Diagramme
Erstellen Sie eine partielle Korrelationsmatrix und zeichnen Sie ein unabhängiges Diagramm
Zeichnen Sie eine erdähnliche Flussanimation mit Matplotlib und Cartopy