Utilisez Matplotlib depuis Java ou Scala avec Matplotlib4j

En essayant de faire du machine learning avec Java ou Scala, je pense que beaucoup de gens ont constaté qu'il n'y avait pas d'outil graphique sympa et que Python avait Matplotlib.

Par conséquent, j'ai créé Matplotlib4j, une bibliothèque qui vous permet d'appeler Matplotlib à partir de Java, je voudrais donc l'introduire.

Comment utiliser

Ajouter une bibliothèque

Voici un exemple de Java. Bien sûr, il peut également être utilisé à partir d'autres langages JVM tels que Scala et Kotlin. Un exemple sera décrit plus loin.

Tout d'abord, ajoutez Matplotlib4j au projet Java dans lequel vous souhaitez utiliser Matplotlib.

Pour Maven, ajoutez la dépendance suivante.

Maven


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

De même, pour Gradle, cela ressemble à ceci:

Gradle


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

Dessiner un graphique

L'utilisation est similaire à l'API Matplotlib, vous pouvez donc l'écrire de manière intuitive. Créez d'abord un objet Plot, ajoutez un graphe arbitraire en lui appelant la méthode pyploy, et enfin appelez la méthode show (). Puisqu'il s'agit d'un modèle Builder, nous ajouterons des options derrière lui en utilisant la complétion IDE.

Nuage de points

Comme point de départ, dessinons un diagramme de dispersion.

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();

Certaines méthodes Numpy, telles que linspace et meshgrid, sont fournies sous forme de classes NumpyUtils pour vous aider à dessiner des graphiques. Nous générons des données x et y pour le traçage dans le premier bloc. Ici, une valeur aléatoire est donnée à la courbe de sin. Après cela, créez un objet Plot, ajoutez les x et y générés à la méthode plot (), et enfin appelez show () pour dessiner le graphique.

Ceci est à peu près équivalent à l'implémentation Python ci-dessous (presque parce que la partie génération de données de numpy est strictement différente). Les méthodes sont dites similaires et sont plus faciles à utiliser pour Pythonista.

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()

Avec le code Java ci-dessus, vous pouvez dessiner le graphique suivant.

scatter.png

Diagramme de contour

Ensuite, dessinons un diagramme de contour (ligne de contour).

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

histogramme

Vous pouvez dessiner un histogramme de la même manière.

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

Enregistrer l'image dans un fichier

Matplotlib4j prend également en charge l'enregistrement dans des fichiers. L'enregistrement du fichier image est pratique pour les cas d'utilisation qui ne disposent pas d'une interface graphique, tels que le traitement périodique de l'apprentissage automatique sur le serveur.

Semblable à l'original Matplotlib, en utilisant la méthode .savefig () au lieu de .show (), l'image est enregistrée dans un fichier au lieu de faire apparaître la fenêtre de tracé. La seule différence est que «.savefig ()» est suivi de «plt.executeSilently ()». (Ceci est nécessaire pour terminer le traitement car la commande savefig est également connectée par une chaîne de méthodes.)

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);

//Requis pour sortir le fichier
plt.executeSilently();

En conséquence, l'image suivante sera sortie.

histogram.png

Changer Python avec pyenv, pyenv-virtualenv

Pour utiliser Matplotlib4j, vous devez utiliser Python avec Matplotlib installé. Par défaut, Matplotlib4j utilise Python qui se trouve dans le chemin, mais je pense qu'il existe de nombreux cas où Matplotlib n'est pas installé dans le système Python par défaut.

Dans ce cas, vous pouvez basculer vers un environnement Python avec Matplotlib installé, tel qu'Anaconda, en utilisant pyenv ou pyenv-virtualenv.

Pour utiliser Python selon l'environnement de Pyenv, spécifiez PythonConfig comme suit lors de la création d'un objet Plot.

pyenv


Plot plot = Plot.create(PythonConfig.pyenvConfig("Tout nom d'environnement pyenv"));

De même, vous pouvez spécifier le nom d'environnement de pyenv-virtualenv.

pyenv-virtualenv


Plot plot = Plot.create(PythonConfig.pyenvVirtualenvConfig("Tout nom d'environnement pyenv", "Tout nom d'environnement virtualenv"));

Scala

Lors de l'utilisation de Scala, l'exemple ci-dessus du diagramme de dispersion peut être écrit comme suit. À ce moment-là, faites attention à la différence entre les classes Box / Unbox et 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()

prime

Déclencheur

J'ai récemment commencé à lire "Deep Learning from scratch-The Theory and Implementation of Deep Learning Learn with Python", mais avec Python tel quel Ce n'est pas intéressant de le copier, j'ai donc décidé de l'implémenter avec Scala, que j'ai beaucoup touché récemment. J'ai pu l'écrire comme un type de fonction dans Scala, et j'en ai été très satisfait, mais seulement lorsque j'ai abordé la propagation arrière par la méthode de descente la plus raide, la perte n'a pas du tout diminué, n'y a-t-il pas un bug quelque part? Je suis tombé sur la situation.

Bien sûr, je pense que c'est une pratique courante dans de tels cas que vous pouvez comprendre en épaississant le test, mais avant tout, j'aimerais afficher rapidement le graphique comme dans le livre et voir ce qui se passe. Mais avec Scala, il n'y a pas d'outil graphique sympa ... Cependant, implémenter l'outil graphique à partir de zéro est trop terrible ... J'ai donc décidé d'utiliser Matplotlib, qui est familier avec Python, et c'est la raison pour laquelle j'ai créé la bibliothèque.

conception

Matplotlib4j appelle Matplotlib sous la forme de génération de code Python sans utiliser JNI ou Jython. Au début, je pensais l'implémenter en utilisant Jython, mais en premier lieu la version Python ne prend en charge que jusqu'à 2.7, et numpy ne peut pas être utilisé, donc cela en dépend. J'ai décidé d'abandonner cette voie car Matplotlib ne fonctionne pas non plus.

Il existe également une Bibliothèque qui permet d'utiliser CPython à partir du code Java, et c'est un candidat car Python3 et numpy peuvent être utilisés. Cependant, pour utiliser JNI, une bibliothèque séparée dépendante de l'environnement est installée, et du côté Python, il est nécessaire d'installer la bibliothèque à partir de pip, donc cela prend trop de temps pour l'utiliser juste pour dessiner un graphique. Après tout, j'ai décidé de l'implémenter indépendamment de ces bibliothèques.

Bien sûr, comme il est exécuté via un fichier, il est nécessaire de concevoir comment passer les variables et utiliser la valeur de retour, et les performances sont-elles bonnes? Je suis inquiet à ce sujet. Heureusement, puisque le seul but est de dessiner un graphique, les fonctions de base peuvent être satisfaites en sortant unilatéralement dans un fichier, et je pense qu'un certain temps d'attente pour les performances est dans la plage autorisée.

Recommended Posts

Utilisez Matplotlib depuis Java ou Scala avec Matplotlib4j
Utilisez JDBC avec Java et Scala.
Utiliser les bibliothèques natives de Scala via Java CPP + Java
Utiliser des couches Lambda avec Java
Utiliser SpatiaLite avec Java / JDBC
Utiliser java avec MSYS et Cygwin
Coder Java depuis Emacs avec Eclim
Utiliser Microsoft Graph avec Java standard
Utiliser Azure Bing SpellCheck avec Java
Utiliser Java 11 avec Google Cloud Functions
Utiliser Chrome Headless de Selenium / Java
Travailler avec des feuilles de calcul Google à partir de Java
Appelez l'API Java de TensorFlow depuis Scala
S'il faut utiliser Java Comparable ou Comparator
Appeler la bibliothèque Java à partir de C avec JNI
Intégration API de Java avec Jersey Client
Introduction à Java à partir de 0 Partie 1
[JaCoCo (Java Code Coverage)] Utilisation avec NetBeans
Exécutez du code Java à partir de cpp sur cocos2dx
Exécuter Rust depuis Java avec JNA (Java Native Access)
[Java] Réglez l'heure depuis le navigateur avec jsoup
Comment utiliser le framework Java avec AWS Lambda! ??
Extraction de texte en Java à partir de PDF avec pdfbox-2.0.8
Comment utiliser l'API Java avec des expressions lambda
Créer Scala Seq à partir de Java, faire de Scala Seq une liste Java
Obtenez unixtime (secondes) de ZonedDateTime dans Scala / Java
[JAVA] [Spring] [MyBatis] Utiliser IN () avec SQL Builder
[Java] Utilisez Collectors.collectingAndThen
Comment écrire Scala du point de vue de Java
Comportement lors de l'appel des méthodes d'argument de longueur variable Java à partir de Scala / Kotlin / Java
Appeler une méthode avec le bloc de rappel de Kotlin depuis Java
Utiliser la requête agrégée (nombre) avec le SDK Java Azure CosmosDB
Java getClass () est incompatible avec les génériques (ou les variables de type)
6 fonctionnalités que j'ai manquées après mon retour de Scala à Java
Jouez avec les nœuds de fonction Java qui peuvent utiliser Java avec Node-RED
[Note] Créez un environnement Java à partir de zéro avec docker
Comment utiliser la bibliothèque JDD dans Scala avec Eclipse
Utilisez java1.7 (zulu7) dans un répertoire spécifique avec jenv
Lire la température / l'humidité avec Java de Raspberry Pi 3 & DHT11
JAWJAW est pratique si vous utilisez WordNet à partir de Java