Verwenden Sie Matplotlib aus Java oder Scala mit Matplotlib4j

Beim Versuch, maschinelles Lernen mit Java oder Scala durchzuführen, haben viele Leute erfahren, dass es kein cooles Grafiktool gibt und dass Python Matplotlib hat.

Aus diesem Grund habe ich Matplotlib4j erstellt, eine Bibliothek, mit der Sie Matplotlib von Java aus aufrufen können. Daher möchte ich sie vorstellen.

Wie benutzt man

Bibliothek hinzufügen

Hier ist ein Beispiel für Java. Natürlich kann es auch aus anderen JVM-Sprachen wie Scala und Kotlin verwendet werden. Ein Beispiel wird später beschrieben.

Fügen Sie zunächst Matplotlib4j zu dem Java-Projekt hinzu, in dem Sie Matplotlib verwenden möchten.

Fügen Sie für Maven die folgende Abhängigkeit hinzu.

Maven


<dependency>
    <groupId>com.github.sh0nk</groupId>
    <artifactId>matplotlib4j</artifactId>
    <version>0.4.0</version>
</dependency>

In ähnlicher Weise sieht es für Gradle folgendermaßen aus:

Gradle


compile 'com.github.sh0nk:matplotlib4j:0.4.0'

Zeichnen eines Diagramms

Die Verwendung ähnelt der Matplotlib-API, sodass Sie sie intuitiv schreiben können. Erstellen Sie zuerst ein Plot-Objekt, fügen Sie ein beliebiges Diagramm hinzu, indem Sie die pyploy-Methode aufrufen, und rufen Sie schließlich die show () -Methode auf. Da es sich um ein Builder-Muster handelt, werden wir mithilfe der IDE-Vervollständigung Optionen dahinter hinzufügen.

Streudiagramm

Zeichnen wir als Ausgangspunkt ein Streudiagramm.

ScatterPlot


List<Double> x = NumpyUtils.linspace(-3, 3, 100);
List<Double> y = x.stream().map(xi -> Math.sin(xi) + Math.random()).collect(Collectors.toList());

Plot plt = Plot.create();
plt.plot().add(x, y, "o").label("sin");
plt.legend().loc("upper right");
plt.title("scatter");
plt.show();

Einige Numpy-Methoden, wie z. B. "linspace" und "meshgrid", werden als "NumpyUtils" -Klassen bereitgestellt, damit Sie Diagramme zeichnen können. Wir generieren x- und y-Daten für das Plotten im ersten Block. Hier wird der Sinuskurve ein zufälliger Wert gegeben. Erstellen Sie danach ein Plot-Objekt, fügen Sie das generierte x und y zur plot () -Methode hinzu und rufen Sie schließlichshow ()auf, um das Diagramm zu zeichnen.

Dies entspricht in etwa der folgenden Python-Implementierung (fast, weil der Datengenerierungsteil von numpy streng unterschiedlich ist). Die Methoden heißen ähnlich und sind für Pythonista einfacher zu verwenden.

PythonScatterPlot


import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-3, 3, 100)
y = np.sin(x) + np.random.rand(100)

plt.plot(x, y, "o", label="sin")
plt.legend(loc="upper right")
plt.title("scatter")
plt.show()

Mit dem obigen Java-Code können Sie das folgende Diagramm zeichnen.

scatter.png

Konturdiagramm

Als nächstes zeichnen wir ein Konturdiagramm (Konturlinie).

ContourPlot


List<Double> x = NumpyUtils.linspace(-1, 1, 100);
List<Double> y = NumpyUtils.linspace(-1, 1, 100);
NumpyUtils.Grid<Double> grid = NumpyUtils.meshgrid(x, y);

List<List<Double>> zCalced = grid.calcZ((xi, yj) -> Math.sqrt(xi * xi + yj * yj));

Plot plt = Plot.create();
ContourBuilder contour = plt.contour().add(x, y, zCalced);
plt.clabel(contour)
    .inline(true)
    .fontsize(10);
plt.title("contour");
plt.show();
contour.png

Histogramm

Sie können ein Histogramm auf die gleiche Weise zeichnen.

HistogramPlot


Random rand = new Random();
List<Double> x1 = IntStream.range(0, 1000).mapToObj(i -> rand.nextGaussian())
        .collect(Collectors.toList());
List<Double> x2 = IntStream.range(0, 1000).mapToObj(i -> 4.0 + rand.nextGaussian())
        .collect(Collectors.toList());

Plot plt = Plot.create();
plt.hist()
    .add(x1).add(x2)
    .bins(20)
    .stacked(true)
    .color("#66DD66", "#6688FF");
plt.xlim(-6, 10);
plt.title("histogram");
plt.show();
histogram.png

Bild in Datei speichern

Matplotlib4j unterstützt auch das Speichern in Dateien. Das Speichern von Bilddateien ist praktisch für Anwendungsfälle ohne GUI, z. B. für die regelmäßige Verarbeitung des maschinellen Lernens auf dem Server.

Ähnlich wie bei der ursprünglichen Matplotlib wird das Bild mithilfe der Methode ".savefig ()" anstelle von ".show ()" in einer Datei gespeichert, anstatt das Plotfenster aufzurufen. Der einzige Unterschied besteht darin, dass auf ".savefig ()" "plt.executeSilently ()" folgt. (Dies ist als Beendigungsverarbeitung erforderlich, da der Befehl savefig auch durch eine Methodenkette verbunden ist.)

Random rand = new Random();
List<Double> x = IntStream.range(0, 1000).mapToObj(i -> rand.nextGaussian())
        .collect(Collectors.toList());

Plot plt = Plot.create();
plt.hist().add(x).orientation(HistBuilder.Orientation.horizontal);
plt.ylim(-5, 5);
plt.title("histogram");
plt.savefig("/tmp/histogram.png ").dpi(200);

//Erforderlich, um die Datei auszugeben
plt.executeSilently();

Infolgedessen wird das folgende Bild ausgegeben.

histogram.png

Python mit pyenv, pyenv-virtualenv wechseln

Um Matplotlib4j verwenden zu können, müssen Sie Python mit installiertem Matplotlib verwenden. Standardmäßig verwendet Matplotlib4j Python, das sich im Pfad befindet, aber ich denke, es gibt viele Fälle, in denen Matplotlib nicht im Standard-Python des Systems installiert ist.

In diesem Fall können Sie mit pyenv oder pyenv-virtualenv zu einer Python-Umgebung mit installiertem Matplotlib wie Anaconda wechseln.

Um Python gemäß der Umgebung von Pyenv zu verwenden, geben Sie PythonConfig wie folgt an, wenn Sie ein Plot-Objekt erstellen.

pyenv


Plot plot = Plot.create(PythonConfig.pyenvConfig("Beliebiger pyenv-Umgebungsname"));

Ebenso können Sie den Umgebungsnamen von pyenv-virtualenv angeben.

pyenv-virtualenv


Plot plot = Plot.create(PythonConfig.pyenvVirtualenvConfig("Beliebiger pyenv-Umgebungsname", "Beliebiger Name der virtuellen Umgebung"));

Scala

Bei Verwendung von Scala kann das obige Beispiel des Streudiagramms wie folgt geschrieben werden. Beachten Sie zu diesem Zeitpunkt den Unterschied zwischen den Klassen Box / Unbox und List.

ScalaScatter


import scala.collection.JavaConverters._

val x = NumpyUtils.linspace(-3, 3, 100).asScala.toList
val y = x.map(xi => Math.sin(xi) + Math.random()).map(Double.box)

val plt = Plot.create()
plt.plot().add(x.asJava, y.asJava, "o")
plt.title("scatter")
plt.show()

Bonus

Auslösen

Vor kurzem habe ich angefangen zu lesen "Deep Learning von Grund auf neu - Die Theorie und Implementierung von Deep Learning, das mit Python gelernt wurde", aber mit Python wie es ist Es macht keinen Spaß, es zu kopieren, deshalb habe ich beschlossen, es mit Scala zu implementieren, was ich in letzter Zeit sehr berührt habe. Ich konnte es wie einen Funktionstyp in Scala schreiben und war sehr zufrieden damit, aber erst als ich mich der Ausbreitung mit der steilsten Abstiegsmethode näherte, ging der Verlust überhaupt nicht zurück, gibt es nicht irgendwo einen Fehler? Ich bin in die Situation geraten.

Natürlich denke ich, dass es in solchen Fällen eine gängige Praxis ist, die Sie durch Verdicken des Tests verstehen können, aber zuerst möchte ich die Grafik schnell wie im Buch anzeigen und sehen, was passiert. Aber mit Scala gibt es kein cooles Grafikwerkzeug ... Die Implementierung des Grafikwerkzeugs von Grund auf ist jedoch zu schrecklich ... Deshalb habe ich mich für Matplotlib entschieden, das mit Python vertraut ist, und das war der Grund für die Erstellung der Bibliothek.

Design

Matplotlib4j ruft Matplotlib in Form der Generierung von Python-Code ohne Verwendung von JNI oder Jython auf. Zuerst dachte ich, ich würde es mit Jython implementieren, aber in erster Linie unterstützt die Python-Version nur bis zu 2.7, und numpy kann nicht verwendet werden, daher hängt es davon ab. Ich habe beschlossen, diesen Weg aufzugeben, weil Matplotlib auch nicht funktioniert.

Es gibt auch eine Bibliothek, mit der CPython aus Java-Code verwendet werden kann. Dies ist ein Kandidat, da sowohl Python3 als auch Numpy verwendet werden können. Um JNI verwenden zu können, wird eine umgebungsabhängige Bibliothek separat installiert. Auf der Python-Seite muss die Bibliothek von pip aus installiert werden, sodass es zu lange dauert, sie nur zum Zeichnen eines Diagramms zu verwenden. Immerhin habe ich beschlossen, es unabhängig von diesen Bibliotheken zu implementieren.

Da es über eine Datei ausgeführt wird, muss natürlich festgelegt werden, wie Variablen übergeben und der Rückgabewert verwendet werden sollen. Ist die Leistung in Ordnung? Ich mache mir darüber Sorgen. Da der Zweck nur darin besteht, Diagramme zu zeichnen, können die Grundfunktionen glücklicherweise durch einseitige Ausgabe in eine Datei erfüllt werden, und ich denke, dass einige Wartezeiten für die Leistung innerhalb des zulässigen Bereichs liegen.

Recommended Posts

Verwenden Sie Matplotlib aus Java oder Scala mit Matplotlib4j
Verwenden Sie JDBC mit Java und Scala.
Verwenden Sie native Bibliotheken von Scala über Java CPP + Java
Verwenden Sie Lambda-Ebenen mit Java
Verwenden Sie SpatiaLite mit Java / JDBC
Verwenden Sie Java mit MSYS und Cygwin
Code Java von Emacs mit Eclim
Verwenden Sie Microsoft Graph mit Standard-Java
Verwenden Sie Azure Bing SpellCheck mit Java
Verwenden Sie Java 11 mit Google Cloud-Funktionen
Verwenden Sie Chrome Headless von Selenium / Java
Arbeiten Sie mit Google-Tabellen aus Java
Rufen Sie die Java-API von TensorFlow von Scala aus auf
Gibt an, ob Java Comparable oder Comparator verwendet werden soll
Rufen Sie die Java-Bibliothek von C mit JNI auf
API-Integration von Java mit Jersey Client
Einführung in Java ab 0 Teil 1
[JaCoCo (Java Code Coverage)] Verwendung mit NetBeans
Führen Sie Java-Code von cpp auf cocos2dx aus
Führen Sie Rust von Java mit JNA (Java Native Access) aus.
[Java] Stellen Sie die Zeit im Browser mit jsoup ein
Verwendung des Java-Frameworks mit AWS Lambda! ??
Textextraktion in Java aus PDF mit pdfbox-2.0.8
Verwendung der Java-API mit Lambda-Ausdrücken
Erstellen Sie Scala Seq aus Java, machen Sie Scala Seq zu einer Java-Liste
Holen Sie sich Unixtime (Sekunden) von ZonedDateTime in Scala / Java
[JAVA] [Spring] [MyBatis] Verwenden Sie IN () mit SQL Builder
[Java] Verwenden Sie Collectors.collectingAndThen
Wie schreibe ich Scala aus der Perspektive von Java
Verhalten beim Aufrufen von Java-Argumentmethoden mit variabler Länge aus Scala / Kotlin / Java
Rufen Sie eine Methode mit Kotlins Rückrufblock von Java aus auf
Verwenden Sie die aggregierte Abfrage (Anzahl) mit dem Azure CosmosDB Java SDK
Java getClass () ist nicht kompatibel mit Generika (oder Typvariablen).
6 Funktionen, die ich nach meiner Rückkehr von Scala nach Java verpasst habe
Spielen Sie mit Java-Funktionsknoten, die Java mit Node-RED verwenden können
[Hinweis] Erstellen Sie mit Docker eine Java-Umgebung von Grund auf neu
Verwendung der JDD-Bibliothek in Scala mit Eclipse
Verwenden Sie java1.7 (zulu7) in einem bestimmten Verzeichnis mit jenv
Lesen Sie Temperatur / Luftfeuchtigkeit von Raspberry Pi 3 & DHT11 mit Java ab
JAWJAW ist praktisch, wenn Sie WordNet aus Java verwenden