Are there any Plotting/graphing/data visualisation libraries which allow rendering/plotting on PGraphic layers without major hacks?


#1

Hi everyone,

I have been trying to find convenient ways to plot onto Pgraphics. Unfortunately, a lot of libraries that I have tried do not support this and it seems one needs to manipulate and hack around library code and classes to get the job done. The good thing is that this is doable and achievable on Java mode, but it makes it difficult on Android mode or on a Android device. Does anyone know of a library which allows plotting and data visualisation on Pgraphic layers? The Pgraphics layers will then serve as my widgets with different functions on my android app.

Many thanks :grin::grin:


#2

Is there something wrong with the question? Or am I asking it in a bad way or in the wrong place? Or actually nobody knows about it?


#3

I believe in this case if you provide some code, or show your attempt, you might get some feedback. Creating a PGraphics just to not show it but to save its content is not that common. Because it is android, you are limited to the Processing design and Android guidelines.

Kf


#4

Absolutely.
So as a bit of a context, I am trying to show some graphs on a carousel. I am trying to use grafica for making the graphs and using a carousel code which @Chrisir kindly showed me to do this. Also I have been using some helpful code snippets from @GoToLoop.
So in the code you will see that by default the carousel shows two slides and in the draw loop a white rectangle is rendered in one of the slides. I believe the rendering is done in using the texture() function in the bottom of the update() function in the Photo class.
You can comment and uncomment the texture() function variations to see what it does to the rendering and compare the the hacked and unhacked version of the Pgraphics.

import grafica.*;
import processing.core.PApplet;
import processing.awt.PGraphicsJava2D;
 
final float MAX_ANGLE = radians(70); 
final float interval = 500;           
final int   offsetZ  = 400;           
final int   bgColor  = color(255, 255, 255);
final int array_size = 2;
CustomPGraph pg3;
int w, h;
PGraphics [] pg;
//CustomPGraph [] pg;
Photo[] p;
void setup() {
  size(800, 600, P3D); 
  pg = new PGraphics[array_size]; //Use this if you want to use pgraphics
  //pg = new CustomPGraph[array_size]; //Use this if you want to use hacked pgraphics 
  
  
  println( pg3 = new CustomPGraph(width*3 >> 2, height*3 >> 2, this) );
  w = pg3.width; 
  h = pg3.height;
  //pg3.strokeWeight(3);
  //pg3.beginDraw();
  //pg3.background(200);
  //pg3.endDraw();
  
  
  pg[0] = createGraphics(100, 100);
  //pg[1] = createGraphics(100, 100);
  //pg[0] = pg3.script(0,0,50,50);
  //pg[0] = pg3.script(0,0,50,50);

// Adding pgraphic elements to Photo objects for displaying in carousel
//---------------------------------------------------------------------------
  p = new Photo[array_size];
  for(int i = 0; i < p.length; i++) {
    p[i] = new Photo(pg[i]);
    p[i].nX = (i - p.length / 2) * interval;
  }
//---------------------------------------------------------------------------
}
 
void draw() {
  
  //This section pretty much takes care of carousel events
  //-----------------------------------------------------------------------------
  camera(0, 0, 1200, 0, 0, 0, 0, 1, 0);
  background(bgColor);
  
  double minX = 9999;
  for(int i = 0; i < p.length; i++) { 
    p[i].update();
    if(abs((float)p[i].nX) < abs((float)minX)) minX = p[i].nX;
  }
   
  double offsetX;
  if(mousePressed) offsetX = 6*(mouseX - pmouseX);
  else offsetX = -minX * 0.1;
  for(int i = 0; i < p.length; i++) { 
    p[i].nX += offsetX;
  }
  //-----------------------------------------------------------------------------
  
  //I have commented the code below, but I was basically playing with changing
  //what will be written to the elements of the pg array which has been declared
  //at the very beginning. The pg array elements are then fed into "Photo" objects
  //to be displayed in the carousel as indicated in the void setup().
  
  // renders a little white rectangle on the first slide
  pg[0].beginDraw();
  pg[0].background(100);
  pg[0].stroke(255);
  pg[0].rectMode(CENTER);
  pg[0].rect(50, 50, 10, 10);
  pg[0].endDraw();
  
  //pg[1].beginDraw();
  //pg[1].background(50);
  //pg[1].stroke(255);
  //pg[1].rectMode(CENTER);
  //pg[1].rect(50, 50, 10, 10);
  //pg[1].endDraw();
  
 //pg.beginDraw();
 //set(width-w >> 1, height-h >> 1, pg.script(c));
 //pg.script(c);
 //pg3.script(200,0,100,100);
 //pg.endDraw();
 
  //pg3.beginDraw();
  //pg3.background(200);
  //pg3.endDraw();
 
 //image(pg,0,300);
}


// The class Photo allows me to render images or Pgraphics objects as elements
//of a carousel.
//-----------------------------------------------------------------------------
class Photo {
  int width  = 640;
  int height = 480;
  
  double x;
  double z;
  private double angle;
  double nX;
  private double rate = 4.0;
  
  PGraphics img;

  //Photo below used to take image files.
  Photo(PGraphics pg) {
    //img  = loadImage(fileName);
    img = pg;
    if(img == null) {
      img = createGraphics(100, 100);
      img.beginDraw();
      img.background(0);
      img.endDraw();
      //img = createImage(128, 128, RGB);
      //for(int i = 0; i < img.pixels.length; i++) {
      //  img.pixels[i] = 0xFFFFFFFF;
      //}
    }
  }
  
  void update() {
    z = 0;
    angle = MAX_ANGLE;
    if(nX < 0) angle = -angle;
    noStroke();
    fill(255);
    
    if(abs((float)x) <= interval + 0.1) {
      x = nX;
      angle = MAX_ANGLE * x / interval;
      z = offsetZ * (interval - abs((float)nX))/interval;
    } else {
      x = nX;
      double offset = interval;
      if(nX < 0) offset = -offset;
      x -= offset;
      x /= rate;
      x += offset;
    }
    
    pushMatrix();
    translate((float)x, 0, (float)z);
    rotateY(-(float)angle);
    

    int   n     = 20; 
    float dW    = (float)this.width / n;
    float dTexW = (float)img.width  / n;
    
    //lights();
    beginShape(QUAD_STRIP);
    
    //Make sure one of the textures() calls is commented at a time
    //-----------------------------------------------------------------------
    //texture(pg3.script(-300,-300,640,480)); //This allows you to see graphs using the hack but its dodgy as....
    texture(img); // This pretty much shows the standard Pgraphics array pg
    //-----------------------------------------------------------------------
    for(int i = 0; i <= n; i++) {
      vertex(-this.width / 2.0 + i*dW, -this.height / 2.0, i*dTexW, 0);
      vertex(-this.width / 2.0 + i*dW,  this.height / 2.0, i*dTexW, img.height);
    }
    endShape(); 
    
    popMatrix();
  }
}
//-----------------------------------------------------------------------------


// The calss below is a hacked version of the Pgraphics (by GoToLoop) to allow me to draw my plots
//--------------------------------------------------------------------------------------------------
public class Layer extends PGraphicsJava2D {
  public Layer() {
  }
 
  public Layer(int w, int h) {
    PApplet p = getEnclosingPApplet();
    initialize(w, h, p, p.dataPath(""));
    ignite();
  }
 
  public Layer(int w, int h, PApplet p) {
    initialize(w, h, p, p.dataPath(""));
    ignite();
  }
 
  public Layer(int w, int h, PApplet p, String s) {
    initialize(w, h, p, s);
    ignite();
  }
 
  public void initialize(int w, int h, PApplet p, String s) {
    setParent(p);
    setPrimary(false);
    setPath(s);
    setSize(w, h);
  }
 
  public void ignite() {
    beginDraw();
    smooth(4);
    fill(-1);
    stroke(0);
    endDraw();
  }
 
  protected PApplet getEnclosingPApplet() {
    try {
      return (PApplet) getClass()
        .getDeclaredField("this$0").get(this);
    }
    catch (ReflectiveOperationException cause) {
      throw new RuntimeException(cause);
    }
  }
 
  @ Override public String toString() {
    return "Width: " + width + "\t Height: " + height
      + "\nPath:  " + path;
  }
}

// This class extends the above class (i.e. Layer) to allow me to draw my graph
//-----------------------------------------------------------------------------
final class CustomPGraph extends Layer {
  
  GPlot plot;
  final PApplet p;
  
  CustomPGraph(int w, int h, PApplet pa) {
    super(w, h, pa);
    setParent(p = pa);
  }
 
  CustomPGraph script(int x, int y, int w, int h) {
    
    //The code commented below is what GoToLoop had used as an example.
    //-----------------------------------------------------------------
    //background(c);
    //fill(~c | ALPHA_MASK);
    //ellipse(width>>1, height>>1, random(width), random(height));
 
    //fill(#FF0000);
    //beginShape(TRIANGLES);
    //vertex(0, 0);
    //vertex(100, 0);
    //vertex(0, 100);
    //endShape();
    //endDraw();
    //-----------------------------------------------------------------
    
    //The code below was added by me to plot a test graph in this function:
    //---------------------------------------------------------------------
    // Create the plot
    plot = new GPlot(p);
    plot.setPos(x, y);
    plot.setDim(w, h);
    // Set the plot title and the axis labels
    plot.setTitleText("Exponential law");
    plot.getXAxis().setAxisLabelText("x");
    plot.getYAxis().setAxisLabelText("y");

    //plot.setPoints(points);
    plot.setLineColor(color(0, 0, 0));
    plot.setPointColor(color(100, 100, 255));
    plot.activatePointLabels();
    //plot.activatePanning();
    //plot.activateZooming(1.1, CENTER, CENTER);
    
    plot.beginDraw();
    plot.drawBackground();
    plot.drawBox();
    plot.drawXAxis();
    plot.drawYAxis();
    plot.drawTopAxis();
    plot.drawRightAxis();
    plot.drawTitle();
    plot.drawLines();
    plot.drawLabels();
    plot.drawGridLines(GPlot.BOTH);
    plot.drawPoints();
    plot.endDraw();
 
    return this;
  }
 //---------------------------------------------------------------------
}

Many Thanks


#5

Any ideas or thoughts anyone?:cry:


#6

I was looking at your question. Maybe I am missing a detail, but I am not sure why you need the hack to start with. My understanding from the other post is that you wanted to create a PG that was not associated with the current PApplet, as you didn’t want it to be visible on screen, but still able to save it. Here in your example, from what I understand, you are drawing directly on a PGraphics. Couldn’t something like this work when it comes to modifying/drawing on a picture?

  pg[0] = createGraphics(100, 100);
  pg[0].beginDraw();
  pg[0].background(100);
  pg[0].image(   your_image.jpg/png/tiff/etc,   0,   0  );
  pg[0].stroke(255);
  pg[0].rectMode(CENTER);
  pg[0].rect(50, 50, 10, 10);
  pg[0].endDraw();

Then you can set this as a texture using texture(pg[0].get());

I did notice your are using GPlot. Even if you try to implement this hack, I do not think you are going the right direction. One could make it work in Java, but in android you will need to work with a new fragment and probably a Canvas object. Because GPlot works with a papplet, no sure if you will be able to pull it off using this code. Wouldn’t just be easier to write your own minimalist version of GPLot? It would be a PGraphics and you will draw into it on an area defined by you. You will need to implement axis and boundaries.

Before writing this GPlot version, is there anything else in the market that could do this job for you using Android elements?

Kf


#7

I thought I needed to hack PGraphics because I could not find any other way which would allow me to show graphs in the carousel. As you can see in the code the carousel only shows images or as I have slightly changed it, it can show PGraphics. My end goal or what I like to do is to show a number of graphs on the carousel.

I am trying to do the same thing in Android Studio at the moment and I have kind of given up on doing it in processing as I feel it is easier and more worth the while. But I do not know of any android elements which would allow me to conveniently and easily implement what I want in processing.

Thank you very much for your help though.:star_struck::blush:


#8

Processing: You can plot in an array of PGraphics

Then treat those as images in the carousel


#9

Quick quote:

A PGraphics is actually a PImage, with added stuff to allow drawing on it. You can use it whenever you need a PImage, even where a parameter specify it wants a PImage.

So I think you can say

image(PGraphicsVariable, 22,22);


#10

Thanks for the note @Chrisir. I am aware of that and that is what I am doing in the code at the moment. The problem however is not PGraphics, but rather the graphing or the plotting bit. I cannot plot on Pgraphics as you may have noticed from my post.

A workaround that I tried, which worked on my computer but failed on android, was to plot the graphs, save the frame of the plotted graphs with saveFrame() and the refresh the everything by calling background etc. This is a dodgy way of doing it though and as I mentioned it did not work on Android.