Hello, I want to ask about the real time serial plotter, I have downloaded it from Sebastian Nilsson’s github, and have modified it as needed. But I’m confused to make my serial value as input update in the graph I created.
I have serial values for Power, Torque and engine RPM. Of the three values I want the engine RPM value on the X axis, Power and Torque on the Y axis. Here’s the picture I attached, please help my bro.
Thanks in Advance…
Actually i still cannot re formated my code, so i’ll give my code here
// import libraries "all library is OK"
import java.awt.Frame;
import java.awt.BorderLayout;
import controlP5.*; // http://www.sojamo.de/libraries/controlP5/
import processing.serial.*;
/* SETTINGS BEGIN */
// Serial port to connect to
String serialPortName = "COM9"; //Ok
// If you want to debug the plotter without using a real serial port set this to true
boolean mockupSerial = true; //Ok
/* SETTINGS END */
Serial serialPort; // Serial port object (OK)
// interface stuff
ControlP5 cp5; //(OK)
// Settings for the plotter are saved in this file
JSONObject plotterConfigJSON;
Graph LineGraph = new Graph(150, 100, 600, 200, color (200, 20, 20));
float[][] lineGraphValues = new float[6][100]; //??
float[] lineGraphSampleNumbers = new float[100]; //??
color[] graphColors = new color[6]; //
// helper for saving the executing path
String topSketchPath = "";
void setup() {
surface.setTitle("EECL Dynotest");
size(890, 500);
// set line graph colors
graphColors[0] = color(255, 0, 0);
graphColors[1] = color(0, 255, 0);
// settings save file
topSketchPath = sketchPath();
plotterConfigJSON = loadJSONObject(topSketchPath+"/plotter_config.json");
// gui
cp5 = new ControlP5(this);
// init charts
setChartSettings();
// build x axis values for the line graph
for (int i=0; i<lineGraphValues.length; i++) {
for (int k=0; k<lineGraphValues[0].length; k++) {
lineGraphValues[i][k] = 0;
if (i==0)
lineGraphSampleNumbers[k] = k;
}
}
// start serial communication
if (!mockupSerial) {
//String serialPortName = Serial.list()[3];
serialPort = new Serial(this, serialPortName, 115200);
}
else
serialPort = null;
}
byte[] inBuffer = new byte[100]; // holds serial message
int i = 0; // loop variable
void draw() {
/* Read serial and update values */
if (mockupSerial || serialPort.available() > 0) {
String myString = "";
if (!mockupSerial) {
try {
serialPort.readBytesUntil('\r', inBuffer);
}
catch (Exception e) {
}
myString = new String(inBuffer);
}
else {
myString = mockupSerialFunction();
}
//println(myString);
// split the string at delimiter (space)
String[] nums = split(myString, ' ');
int numberOfInvisibleLineGraphs = 0;
for (i=0; i<6; i++) {
if (int(getPlotterConfigString("lgVisible"+(i+1))) == 0) {
numberOfInvisibleLineGraphs++;
}
}
// build a new array to fit the data to show
//barChartValues = new float[6-numberOfInvisibleBars];
// build the arrays for bar charts and line graphs
int barchartIndex = 0;
for (i=0; i<nums.length; i++) {
// update barchart
try {
if (int(getPlotterConfigString("bcVisible"+(i+1))) == 1) {
//if (barchartIndex < barChartValues.length)
// barChartValues[barchartIndex++] = float(nums[i])*float(getPlotterConfigString("bcMultiplier"+(i+1)));
}
else {
}
}
catch (Exception e) {
}
// update line graph
try {
if (i<lineGraphValues.length) {
for (int k=0; k<lineGraphValues[i].length-1; k++) {
lineGraphValues[i][k] = lineGraphValues[i][k+1];
}
lineGraphValues[i][lineGraphValues[i].length-1] = float(nums[i])*float(getPlotterConfigString("lgMultiplier"+(i+1)));
}
}
catch (Exception e) {
}
}
}
// draw the bar chart
background(255); //bukan background tabel grafik
// draw the line graphs
LineGraph.DrawAxis();
for (int i=0;i<lineGraphValues.length; i++) {
LineGraph.GraphColor = graphColors[i];
if (int(getPlotterConfigString("lgVisible"+(i+1))) == 1)
LineGraph.LineGraph(lineGraphSampleNumbers, lineGraphValues[i]);
}
}
// called each time the chart settings are changed by the user
void setChartSettings() {
LineGraph.xLabel=" Engine RPM (x1000) ";
LineGraph.yLabel="Torque (Nm)/Power (HP)";
LineGraph.Title="";
LineGraph.xDiv=10;
LineGraph.xMax=10;
LineGraph.xMin=0;
LineGraph.yMax=int(getPlotterConfigString("lgMaxY"));
LineGraph.yMin=int(getPlotterConfigString("lgMinY"));
}
// handle gui actions
void controlEvent(ControlEvent theEvent) {
if (theEvent.isAssignableFrom(Textfield.class) || theEvent.isAssignableFrom(Toggle.class) || theEvent.isAssignableFrom(Button.class)) {
String parameter = theEvent.getName();
String value = "";
if (theEvent.isAssignableFrom(Textfield.class))
value = theEvent.getStringValue();
else if (theEvent.isAssignableFrom(Toggle.class) || theEvent.isAssignableFrom(Button.class))
value = theEvent.getValue()+"";
plotterConfigJSON.setString(parameter, value);
saveJSONObject(plotterConfigJSON, topSketchPath+"/plotter_config.json");
}
setChartSettings();
}
// get gui settings from settings file
String getPlotterConfigString(String id) {
String r = "";
try {
r = plotterConfigJSON.getString(id);
}
catch (Exception e) {
r = "";
}
return r;
}```
Hi @anwar05, Your sketch doesn’t run for me, are there other tabs? Can you post the code for each please?
Hello,
I explored the Realtime Plotter:
but will not be investing any more time into this.
I found the grafica library simple and easy to work with.
I modified the MultiplePlots example:
To give a real time plot (the red one):
Modifications (some) to Plot 2:
// Add a new point to the second plot if the mouse moves significantly
GPoint lastPoint = plot2.getPointsRef().getLastPoint();
int x = frameCount%100;
float y = 30+20*sin(frameCount*TAU/100);
if (lastPoint == null)
{
plot2.addPoint(x, y);
}
else if (!lastPoint.isValid() || frameCount > 0)
{
plot2.addPoint(x, y);
}
// Reset the points if the user pressed the space bar
//if (keyPressed && key == ' ')
if(frameCount%100 == 99)
{
plot2.setPoints(new GPointsArray());
}
Some other modifications were necessary (x and y limits and drawing points) and I gleaned those from the other examples.
I was able to replace the frameCount
generated data with incoming serial data for real time plots.
With some effort you can make this work (hit the play icon on the animation below):
I am just sharing…
This is your project so you make all the decisions.
:)
Hello @RichardDL , yes that’s right, there are still other tabs & arduino code. Do you have arduino around you?
below I attach another tab.
/* =================================================================================
The Graph class contains functions and variables that have been created to draw
graphs. Here is a quick list of functions within the graph class:
Graph(int x, int y, int w, int h,color k)
DrawAxis()
Bar([])
smoothLine([][])
DotGraph([][])
LineGraph([][])
=================================================================================*/
class Graph
{
boolean Dot=true; // Draw dots at each data point if true
boolean RightAxis; // Draw the next graph using the right axis if true
boolean ErrorFlag=false; // If the time array isn't in ascending order, make true
boolean ShowMouseLines=true; // Draw lines and give values of the mouse position
int xDiv=5,yDiv=5; // Number of sub divisions
int xPos,yPos; // location of the top left corner of the graph
int Width,Height; // Width and height of the graph
color GraphColor;
color BackgroundColor=color(255);
color StrokeColor=color(180);
String Title="Title"; // Default titles
String xLabel="x - Label";
String yLabel="y - Label";
float yMax=1024, yMin=0; // Default axis dimensions
float xMax=10, xMin=0;
float yMaxRight=1024,yMinRight=0;
PFont Font; // Selected font used for text
// int Peakcounter=0,nPeakcounter=0;
Graph(int x, int y, int w, int h,color k) { // The main declaration function
xPos = x;
yPos = y;
Width = w;
Height = h;
GraphColor = k;
}
void DrawAxis(){
/* =========================================================================================
Main axes Lines, Graph Labels, Graph Background
========================================================================================== */
fill(BackgroundColor); color(0);stroke(StrokeColor);strokeWeight(1);
int t=60;
rect(xPos-t*1.6,yPos-t,Width+t*2.5,Height+t*2); // outline
textAlign(CENTER);textSize(18);
float c=textWidth(Title);
fill(BackgroundColor); color(0);stroke(0);strokeWeight(1);
rect(xPos+Width/2-c/2,yPos-35,c,0); // Heading Rectangle
fill(0);
text(Title,xPos+Width/2,yPos-37); // Heading Title
textAlign(CENTER);textSize(14);
text(xLabel,xPos+Width/2,yPos+Height+t/1.5); // x-axis Label
rotate(-PI/2); // rotate -90 degrees
text(yLabel,-yPos-Height/2,xPos-t*1.6+20); // y-axis Label
rotate(PI/2); // rotate back
textSize(10); noFill(); stroke(0); smooth();strokeWeight(1);
//Edges
line(xPos-3,yPos+Height,xPos-3,yPos); // y-axis line
line(xPos-3,yPos+Height,xPos+Width+5,yPos+Height); // x-axis line
stroke(200);
if(yMin<0){
line(xPos-7, // zero line
yPos+Height-(abs(yMin)/(yMax-yMin))*Height, //
xPos+Width,
yPos+Height-(abs(yMin)/(yMax-yMin))*Height
);
}
if(RightAxis){ // Right-axis line
stroke(0);
line(xPos+Width+3,yPos+Height,xPos+Width+3,yPos);
}
/* =========================================================================================
Sub-devisions for both axes, left and right
========================================================================================== */
stroke(0);
for(int x=0; x<=xDiv; x++){
/* =========================================================================================
x-axis
========================================================================================== */
line(float(x)/xDiv*Width+xPos-3,yPos+Height, // x-axis Sub devisions
float(x)/xDiv*Width+xPos-3,yPos+Height+5);
textSize(10); // x-axis Labels
String xAxis=str(xMin+float(x)/xDiv*(xMax-xMin)); // the only way to get a specific number of decimals
String[] xAxisMS=split(xAxis,'.'); // is to split the float into strings
text(xAxisMS[0]+"."+xAxisMS[1].charAt(0), // ...
float(x)/xDiv*Width+xPos-3,yPos+Height+15); // x-axis Labels
}
/* =========================================================================================
left y-axis
========================================================================================== */
for(int y=0; y<=yDiv; y++){
line(xPos-3,float(y)/yDiv*Height+yPos, // ...
xPos-7,float(y)/yDiv*Height+yPos); // y-axis lines
textAlign(RIGHT);fill(20);
String yAxis=str(yMin+float(y)/yDiv*(yMax-yMin)); // Make y Label a string
String[] yAxisMS=split(yAxis,'.'); // Split string
text(yAxisMS[0]+"."+yAxisMS[1].charAt(0), // ...
xPos-15,float(yDiv-y)/yDiv*Height+yPos+3); // y-axis Labels
/* =========================================================================================
right y-axis
========================================================================================== */
if(RightAxis){
color(GraphColor); stroke(GraphColor);fill(20);
line(xPos+Width+3,float(y)/yDiv*Height+yPos, // ...
xPos+Width+7,float(y)/yDiv*Height+yPos); // Right Y axis sub devisions
textAlign(LEFT);
String yAxisRight=str(yMinRight+float(y)/ // ...
yDiv*(yMaxRight-yMinRight)); // convert axis values into string
String[] yAxisRightMS=split(yAxisRight,'.'); //
text(yAxisRightMS[0]+"."+yAxisRightMS[1].charAt(0), // Right Y axis text
xPos+Width+15,float(yDiv-y)/yDiv*Height+yPos+3); // it's x,y location
noFill();
}stroke(0);
}
}
/* =========================================================================================
Bar graph
========================================================================================== */
void Bar(float[] a ,int from, int to) {
stroke(GraphColor);
fill(GraphColor);
if(from<0){ // If the From or To value is out of bounds
for (int x=0; x<a.length; x++){ // of the array, adjust them
rect(int(xPos+x*float(Width)/(a.length)),
yPos+Height-2,
Width/a.length-2,
-a[x]/(yMax-yMin)*Height);
}
}
else {
for (int x=from; x<to; x++){
rect(int(xPos+(x-from)*float(Width)/(to-from)),
yPos+Height-2,
Width/(to-from)-2,
-a[x]/(yMax-yMin)*Height);
}
}
}
void Bar(float[] a ) {
stroke(GraphColor);
fill(GraphColor);
for (int x=0; x<a.length; x++){ // of the array, adjust them
rect(int(xPos+x*float(Width)/(a.length)),
yPos+Height-2,
Width/a.length-2,
-a[x]/(yMax-yMin)*Height);
}
}
/* =========================================================================================
Dot graph
========================================================================================== */
void DotGraph(float[] x ,float[] y) {
for (int i=0; i<x.length; i++){
strokeWeight(2);stroke(GraphColor);noFill();smooth();
ellipse(
xPos+(x[i]-x[0])/(x[x.length-1]-x[0])*Width,
yPos+Height-(y[i]/(yMax-yMin)*Height)+(yMin)/(yMax-yMin)*Height,
2,2
);
}
}
/* =========================================================================================
Streight line graph
========================================================================================== */
void LineGraph(float[] x ,float[] y) {
for (int i=0; i<(x.length-1); i++){
strokeWeight(2);stroke(GraphColor);noFill();smooth();
line(xPos+(x[i]-x[0])/(x[x.length-1]-x[0])*Width,
yPos+Height-(y[i]/(yMax-yMin)*Height)+(yMin)/(yMax-yMin)*Height,
xPos+(x[i+1]-x[0])/(x[x.length-1]-x[0])*Width,
yPos+Height-(y[i+1]/(yMax-yMin)*Height)+(yMin)/(yMax-yMin)*Height);
}
}
/* =========================================================================================
smoothLine
========================================================================================== */
void smoothLine(float[] x ,float[] y) {
float tempyMax=yMax, tempyMin=yMin;
if(RightAxis){yMax=yMaxRight;yMin=yMinRight;}
int counter=0;
int xlocation=0,ylocation=0;
// if(!ErrorFlag |true ){ // sort out later!
beginShape(); strokeWeight(2);stroke(GraphColor);noFill();smooth();
for (int i=0; i<x.length; i++){
/* ===========================================================================
Check for errors-> Make sure time array doesn't decrease (go back in time)
===========================================================================*/
if(i<x.length-1){
if(x[i]>x[i+1]){
ErrorFlag=true;
}
}
/* =================================================================================
First and last bits can't be part of the curve, no points before first bit,
none after last bit. So a streight line is drawn instead
================================================================================= */
if(i==0 || i==x.length-2)line(xPos+(x[i]-x[0])/(x[x.length-1]-x[0])*Width,
yPos+Height-(y[i]/(yMax-yMin)*Height)+(yMin)/(yMax-yMin)*Height,
xPos+(x[i+1]-x[0])/(x[x.length-1]-x[0])*Width,
yPos+Height-(y[i+1]/(yMax-yMin)*Height)+(yMin)/(yMax-yMin)*Height);
/* =================================================================================
For the rest of the array a curve (spline curve) can be created making the graph
smooth.
================================================================================= */
curveVertex( xPos+(x[i]-x[0])/(x[x.length-1]-x[0])*Width,
yPos+Height-(y[i]/(yMax-yMin)*Height)+(yMin)/(yMax-yMin)*Height);
/* =================================================================================
If the Dot option is true, Place a dot at each data point.
================================================================================= */
if(Dot)ellipse(
xPos+(x[i]-x[0])/(x[x.length-1]-x[0])*Width,
yPos+Height-(y[i]/(yMax-yMin)*Height)+(yMin)/(yMax-yMin)*Height,
2,2
);
/* =================================================================================
Highlights points closest to Mouse X position
=================================================================================*/
if( abs(mouseX-(xPos+(x[i]-x[0])/(x[x.length-1]-x[0])*Width))<5 ){
float yLinePosition = yPos+Height-(y[i]/(yMax-yMin)*Height)+(yMin)/(yMax-yMin)*Height;
float xLinePosition = xPos+(x[i]-x[0])/(x[x.length-1]-x[0])*Width;
strokeWeight(1);stroke(240);
// line(xPos,yLinePosition,xPos+Width,yLinePosition);
strokeWeight(2);stroke(GraphColor);
ellipse(xLinePosition,yLinePosition,4,4);
}
}
endShape();
yMax=tempyMax; yMin=tempyMin;
float xAxisTitleWidth=textWidth(str(map(xlocation,xPos,xPos+Width,x[0],x[x.length-1])));
if((mouseX>xPos&mouseX<(xPos+Width))&(mouseY>yPos&mouseY<(yPos+Height))){
if(ShowMouseLines){
// if(mouseX<xPos)xlocation=xPos;
if(mouseX>xPos+Width)xlocation=xPos+Width;
else xlocation=mouseX;
stroke(200); strokeWeight(0.5);fill(255);color(50);
// Rectangle and x position
line(xlocation,yPos,xlocation,yPos+Height);
rect(xlocation-xAxisTitleWidth/2-10,yPos+Height-16,xAxisTitleWidth+20,12);
textAlign(CENTER); fill(160);
text(map(xlocation,xPos,xPos+Width,x[0],x[x.length-1]),xlocation,yPos+Height-6);
// if(mouseY<yPos)ylocation=yPos;
if(mouseY>yPos+Height)ylocation=yPos+Height;
else ylocation=mouseY;
// Rectangle and y position
stroke(200); strokeWeight(0.5);fill(255);color(50);
line(xPos,ylocation,xPos+Width,ylocation);
int yAxisTitleWidth=int(textWidth(str(map(ylocation,yPos,yPos+Height,y[0],y[y.length-1]))) );
rect(xPos-15+3,ylocation-6, -60 ,12);
textAlign(RIGHT); fill(GraphColor);//StrokeColor
// text(map(ylocation,yPos+Height,yPos,yMin,yMax),xPos+Width+3,yPos+Height+4);
text(map(ylocation,yPos+Height,yPos,yMin,yMax),xPos -15,ylocation+4);
if(RightAxis){
stroke(200); strokeWeight(0.5);fill(255);color(50);
rect(xPos+Width+15-3,ylocation-6, 60 ,12);
textAlign(LEFT); fill(160);
text(map(ylocation,yPos+Height,yPos,yMinRight,yMaxRight),xPos+Width+15,ylocation+4);
}
noStroke();noFill();
}
}
}
void smoothLine(float[] x ,float[] y, float[] z, float[] a ) {
GraphColor=color(188,53,53);
smoothLine(x ,y);
GraphColor=color(193-100,216-100,16);
smoothLine(z ,a);
}
}
Thank You @glv for replying again.
yes, I just saw it yesterday maybe this is another option for me, and I’m trying to modify it.
I apologize in advance because my knowledge in programming is very limited, because I am taking a mechanical course. But it doesn’t matter I’m ready to learn more for this.
My initial goal was to create two values that move respect to the value on the X axis (Engine RPM). I’ve tried modifying the grafica library but the results are not what I expected,
here is an example of my results
and the code i’m using is here
import grafica.*;
import java.util.Random;
GPlot plot1;
void setup(){
size (600, 350);
// Leave empty the points for the first plot. We will fill them in draw()
// Setup for the first plot
plot1 = new GPlot(this);
plot1.setPos(20, 10);
plot1.setDim(450, 200);
plot1.getTitle().setText("Grafik Torsi dan Daya");
plot1.getXAxis().getAxisLabel().setText("Engine RPM (x1000)");
plot1.getYAxis().getAxisLabel().setText("Torsi (Nm) / Daya (HP)");
}
void draw(){
background(255);
// Add a new point to the first plot (will be from serial port)
GPoint lastPoint1 = plot1.getPointsRef().getLastPoint();
GPoint lastPoint2 = plot1.getPointsRef().getLastPoint();
int x = frameCount%100;
float y1 = 30+20*sin(frameCount*TAU/100);
float y2 = 30+20*cos(frameCount*TAU/10);
if (lastPoint1 == null)
{
plot1.addPoint(x, y1);
}
else if (!lastPoint1.isValid() || frameCount > 0)
{
plot1.addPoint(x, y1);
}
if (lastPoint2 == null)
{
plot1.addPoint(x, y2);
}
else if (!lastPoint2.isValid() || frameCount > 0)
{
plot1.addPoint(x, y2);
}
// Reset the points if the user pressed the space bar
//if (keyPressed && key == ' ')
if(frameCount%100 == 99)
{
plot1.setPoints(new GPointsArray());
}
// Draw the second plot
plot1.beginDraw();
plot1.drawBackground();
plot1.drawBox();
plot1.drawXAxis();
plot1.drawYAxis();
plot1.drawTitle();
plot1.drawGridLines(GPlot.BOTH);
plot1.drawLines();
plot1.endDraw();
}
@anwar05 Your last plot may be suffering from aliasing. Yes I have a few Arduino. Never used Graphica, don’t know why not, looks good. If you want me to run your code please post the json file.
do you mean the mockupserial?
So there is 3 tabs i download from astiannilsson.com/project/realtime-plotter/realtime-data-plotter/. which is Realtimebasicplotter, graphclass and mockupserial. And i modify the realtimebasiplotter. Here is the mockup serial, for realtimeplotter and graphclass i’ve posted before. Thank you @RichardDL . I’m also still doing with grafica library but still not works.
// If you want to debug the plotter without using a real serial port
int mockupValue = 0;
int mockupDirection = 10;
String mockupSerialFunction() {
mockupValue = (mockupValue + mockupDirection);
if (mockupValue > 100)
mockupDirection = -10;
else if (mockupValue < -100)
mockupDirection = 10;
String r = "";
for (int i = 0; i<6; i++) {
switch (i) {
case 0:
r += mockupValue+" ";
break;
case 1:
r += 100*cos(mockupValue*(2*3.14)/1000)+" ";
break;
case 2:
r += mockupValue/4+" ";
break;
case 3:
r += mockupValue/8+" ";
break;
case 4:
r += mockupValue/16+" ";
break;
case 5:
r += mockupValue/32+" ";
break;
}
if (i < 7)
r += '\r';
}
delay(10);
return r;
}
More working now. Still need “plotter_config.json”
Processing: plotter_config.json…
here is the plotter_config @RichardDL
{
"bcMultiplier1": "1",
"bcMaxY": "100",
"lgMaxY": "10",
"lgVisible1": "0.0",
"lgVisible2": "0.0",
"lgVisible5": "1.0",
"lgVisible6": "1.0",
"lgVisible3": "0.0",
"lgVisible4": "0.0",
"bcMultiplier6": "1",
"bcMultiplier3": "1",
"bcMultiplier2": "1",
"bcMultiplier5": "0.3",
"bcMultiplier4": "1",
"lgMultiplier2": "1",
"lgMultiplier3": "1",
"lgMultiplier1": "1",
"lgMultiplier6": "1",
"lgMultiplier4": "1",
"lgMultiplier5": "0.1",
"bcVisible3": "1.0",
"bcVisible4": "1.0",
"lgMinY": "-8",
"bcMinY": "0",
"bcVisible1": "1.0",
"bcVisible2": "0.0",
"bcVisible5": "1.0",
"bcVisible6": "1.0"
}
Hello @anwar05,
You did not set limits on your axes.
Try one graph at at time for starters; you are combining data and plotting it.
I used %100
… % is the modulo operator; look this up and try to understand how it is used and how I used it in my example.
It took some effort for me to get this going…
Keep at it!
:)
@glv,aaaa i see friend
I just combining data and plotting it. i’ll try and read some example again and again.
I have never used the grafica library and had to do some work to get this working the first time.
I saw this as a challenge in this post:
Each step gets you closer to your destination.
:)