
// JepPlot.java
// Andrew Davison, ad@coe.psu.ac.th, July 2023

/* Calls the Matplotlib module in Python. This is a 
   third-part module for graph plotting
   (https://matplotlib.org/).

   Examples include:
     * call a Matplotlib script
     * generate a bar chart, line graph, scatter plot,
       or histogram
          -- uncomment the relevant lines of code

    * save the graph as an image in Python, and then
      load that image into Java for display.

  Usage:
     > compile JepPlot
     > run JepPlot 

  Based on Python test code in bars1.py,
  hist1.py, line1.py, and scatter1.py. It also calls
  the graphs1.py script.
*/

import java.util.*;
import java.awt.image.*;

import jep.*;
import jep.python.*;


public class JepPlot 
{

  public static void main(String[] args) throws JepException 
  {
    System.out.println("Starting Jep...");
    Interpreter jep = new SharedInterpreter();

    jep.exec("import matplotlib");
    jep.exec("import matplotlib.pyplot as plt");
    jep.exec("import numpy as np");

    jep.exec("matplotlib.use('agg')");
      // non-interactive backend;
      // will get a warning otherwise

    // set the filename used to store the graph
    // in the Python code
    String imFnm = PyUtils.makeTemp("png");  // use a temp file
    jep.set("fileName", imFnm);


   // uncomment one of the following: ---------------
   // generate a plot

    jep.runScript("graphs.py");

   // bar chart
   // plotBars(jep, new String[]{"A", "B", "C", "D"},
   //               new int[]{3, 8, 1, 10});

   // line plot
   // plotLine(jep, new int[]{1, 2, 3, 4},
   //               new int[]{3, 8, 1, 10});

/*  // scatter plots
    plotScatter(jep,
             new int[]{5,7,8,7,2,17,2,9,4,11,12,9,6},
             new int[]{99,86,87,88,111,86,103,
                       87,94,78,77,85,86}
               );
    plotScatter(jep,
         new int[]{2,2,8,1,15,8,12,9,7,3,11,4,7,14,12},
         new int[]{100,105,84,105,90,99,90,95,
                   94,100,79,112,91,80,85}
               );
*/

    // histogram
    // jep.exec("x = np.random.normal(170, 10, 250)");
    // jep.exec("plt.hist(x)");


    jep.exec("plt.savefig(fileName)");  // save the plot
    jep.close();

    // load the image into Java and display
    ImageViewer.view("Matplotlib Graph", imFnm);
    BufferedImage im = PyUtils.loadImage(imFnm);
    System.out.println("Image size: " + im.getWidth() + 
                              " x " + im.getHeight());
  } // end of main()


  private static void plotLine(Interpreter jep,
                 int[] xs, int[] ys)
  {
    if (xs.length != ys.length) {
      System.out.println("Misatch in xs and ys sizes");
      return;
    }
    jep.set("xs", new NDArray<int[]>(xs));
    jep.set("ys", new NDArray<int[]>(ys));
    jep.exec("plt.plot(xs,ys)");
  }  // end of plotLine()


  private static void plotBars(Interpreter jep,
                     String[] labels, int[] data)
  {
    if (labels.length != data.length) {
      System.out.println("Misatch in label and data sizes");
      return;
    }
    setStringArr(jep, "labels", labels);
    jep.set("data", new NDArray<int[]>(data));
    jep.exec("plt.bar(labels,data)");
  }  // end of plotBars()


  private static void setStringArr(Interpreter jep,
                               String nm, String[] labels)
  /* specify the axis labels as a String array
     since JEP does not support
      jep.set("labels", new NDArray<String[]>(labels));
  */
  {
    String labelStr = nm + " = np.array([";
    for (int i=0; i < labels.length-1; i++)
       labelStr += "'" +  labels[i] + "',";
    labelStr += "'" + labels[labels.length-1] +
                       "'])";
    jep.exec(labelStr);
  }  // end of setStringArr()



  private static void plotScatter(Interpreter jep,
                                int[] xs, int[] ys)
  {
    if (xs.length != ys.length) {
      System.out.println("Misatch in xs and ys sizes");
      return;
    }
    jep.set("xs", new NDArray<int[]>(xs));
    jep.set("ys", new NDArray<int[]>(ys));
    jep.exec("plt.scatter(xs,ys)");
  }  // end of plotScatter()


} // end of JepPlot class
