How to draw this graph

yes perfectly got it ,thank you

i have tried to draw graph , somehow i got success

import processing.serial.*;

Serial port;
ArrayList<PVector> dataPoints;
float graphX;  // X-coordinate of the graph
float graphY;  // Y-coordinate of the graph
float graphWidth; // Width of the graph
float graphHeight;

// x axis label range
int xMin = 0;
int xMax = 100;
int xStep = 10;

// y axis label range
int yMin = 0;
int yMax = 5;
int yStep = 1;

void setup() {
  size(750, 500);  // Set the size of the window
  graphX = width * 0.2;  // Set the initial X-coordinate of the graph
  graphY = height * 0.8;  // Set the initial Y-coordinate of the graph
  graphWidth = width * 0.6; // Width of the graph
  graphHeight = height * 0.6; // Height of the graph
  
  printArray(Serial.list());  // Print available serial ports in the console
  port = new Serial(this, "COM3", 9600);  // Replace "COM3" with the appropriate port name
  port.bufferUntil('\n');  // Set the character to buffer until newline
  
  // Initialize data points list
  dataPoints = new ArrayList<PVector>();
}

void draw() {
  background(255);  // Set the background color to white
  // Set the stroke color and weight for axes and origin
  stroke(0);  // Set the stroke color to black
  strokeWeight(1);  // Set the stroke weight to 1

  // Update the position of the graph based on mouse movement
  if (mousePressed) {
    graphX += mouseX - pmouseX;  // Update the X-coordinate of the graph based on mouse movement on the X-axis
    graphY += mouseY - pmouseY;  // Update the Y-coordinate of the graph based on mouse movement on the Y-axis
  }

  // Draw the x-axis
  line(graphX, graphY, graphX + graphWidth, graphY);
  
  // Draw the arrowhead at the end of the x-axis
  float arrowSize = 8;  // Size of the arrowhead
  triangle(graphX + graphWidth - arrowSize, graphY - arrowSize/2,
    graphX + graphWidth - arrowSize, graphY + arrowSize/2,
    graphX + graphWidth, graphY);
    
  // Draw the x-axis label
  textAlign(RIGHT);
  fill(0);
  text("Angle(θ)", graphX + graphWidth/2 + 24, graphY + 42);
  
  // Draw the y-axis
  line(graphX, graphY, graphX, graphY - graphHeight);
  
  // Draw the arrowhead at the end of the y-axis
  triangle(graphX - arrowSize/2, graphY - graphHeight + arrowSize,
    graphX + arrowSize/2, graphY - graphHeight + arrowSize,
    graphX, graphY - graphHeight);
  
  // Draw the "h_dot" label on the y-axis
  textAlign(RIGHT);
  fill(0);
  text("Velocity of Mechanism (m/s)", graphX - 25, graphY - graphHeight +152);
  
  // Draw the origin O(0,0)
  fill(255, 0, 0);
  noStroke();
  float originSize = 10;
  ellipse(graphX, graphY, originSize, originSize);
  
  // Write x-axis values
  textAlign(CENTER);
  fill(0);
  stroke(0);

  for (int i = xMin; i <= xMax; i += xStep) {
    float xPos = map(i, xMin, xMax, graphX, graphX + graphWidth );
    line(xPos, graphY, xPos, graphY + 8);
    text(i, xPos, graphY + 25);
    int numSubDivisions = 10; // Number of smaller divisions within each major division
    float majorDivisionWidth = graphWidth  / (float)(xMax - xMin) * xStep;
    float subDivisionWidth = majorDivisionWidth / numSubDivisions;
    for (int j = 0; j < numSubDivisions; j++) {
      float subXPos = xPos + (j * subDivisionWidth);
      if (subXPos < graphX + graphWidth ) {
        line(subXPos, graphY, subXPos, graphY + 4);
      }
    }
  }
  
 // Write y-axis values
  textAlign(RIGHT, CENTER);
  fill(0);
  stroke(0);
  for (int i = yMin; i <= yMax; i += yStep) {
    float yPos = map(i, yMin, yMax, graphY, graphY - graphHeight);
    line(graphX - 8, yPos, graphX, yPos);
    text(i, graphX - 12, yPos);
     int numSubDivisions = 10; // Number of smaller divisions within each major division
    float majorDivisionWidth = graphHeight / (float)(yMax - yMin) * yStep;
    float subDivisionWidth = majorDivisionWidth / numSubDivisions;
    for (int k = 0; k < numSubDivisions; k++) {
      float subYPos = yPos + (k * subDivisionWidth);
      if (graphY > subYPos) {
        line(graphX - 4, subYPos, graphX, subYPos );
      }
    }
  }
  // Draw data points
  noFill();
  stroke(0, 0, 255);
  
  for (int i = 1; i < dataPoints.size(); i++) {
    PVector prevPoint = dataPoints.get(i - 1);
    PVector point = dataPoints.get(i);
    
    float prevX = map(prevPoint.x, xMin, xMax, graphX, graphX + graphWidth);
    float prevY = map(prevPoint.y, yMin, yMax, graphY, graphY - graphHeight);
    float x = map(point.x, xMin, xMax, graphX, graphX + graphWidth);
    float y = map(point.y, yMin, yMax, graphY, graphY - graphHeight);
    
    line(prevX, prevY, x, y);
  }
  
  // Draw latest point
  if (dataPoints.size() > 0) {
    PVector latestPoint = dataPoints.get(dataPoints.size() - 1);
    float x = map(latestPoint.x, xMin, xMax, graphX, graphX + graphWidth);
    float y = map(latestPoint.y, yMin, yMax, graphY, graphY - graphHeight);
    fill(255, 0, 0);
    ellipse(x, y, 8, 8);
  }
}

void serialEvent(Serial port) {
  String data = port.readStringUntil('\n');  // Read the received data until newline character
  if (data != null) {
    data = data.trim();
    println("Data received: " + data);
    
    // Parse the data string
    int commaIndex = data.indexOf(',');
    if (commaIndex != -1) {
      String angleStr = data.substring(0, commaIndex);
      String hDotStr = data.substring(commaIndex + 1);
      
      // Convert the parsed values to floats
      float angle = float(angleStr);
      float h_dot = float(hDotStr);
      
      // Create a PVector with angle and h_dot values
      PVector point = new PVector(angle, h_dot);
      
      // Add the point to the data points list
      dataPoints.add(point);
      
      // Print the parsed values
      println("Parsed Angle: " + angle);
      println("Parsed h_dot: " + h_dot);
    }
  }
}

there is a problem that pink circle should follow the exact path before and after drawing happen , but the graph is not clear , like lot of lines , please can you see this .Thank you very much
Capture

Some observations:

  1. Is that a red dot overlying the xAxis arrow? I’m not sure you really need those arrows. The values are clearly increasing on both axes.

  2. What is the significance of the red dots? If they are data points, why do we only see two of them?

like lot of lines
3) I see multiple (more than one) blue lines. In the draw() function I do not see code for redrawing the background. Commonly data is recorded left to right with the x value incremented with time. When the data reaches the right side of the graph, the background is redrawn, thereby erasing the old data, and new data resumes being plotted left to right. In your case, you might not want to erase the entire graph and re-draw everything. An alternative would be to refresh the background only on the plot area, sparing the axes and labels. Either method should eliminate multiple data lines.

1 Like

the red dot i will remove it , since the mechanism moving up and down continuosuly so the graph once generated , it should be same till mechanism stopped ,the pink dot on graph just to show path

i have create button which will generate table , it is tested and work well , however i want to have separate window for table , please guide

thankyou

import processing.serial.*;
import processing.core.PFont;  // Import PFont for setting the font

Serial port;
ArrayList<PVector> dataPoints;
float graphX;  // X-coordinate of the graph
float graphY;  // Y-coordinate of the graph
float graphWidth; // Width of the graph
float graphHeight;

// x axis label range
int xMin = 0;
int xMax = 100;
int xStep = 10;

// y axis label range
int yMin = 0;
int yMax = 5;
int yStep = 1;

PFont boldFont;  // Declare a variable for the bold font

Button generateButton;
float buttonX;
float buttonY;
boolean showTable;
Table dataTable;

void setup() {
  size(750, 500);  // Set the size of the window
   buttonX = graphX + graphWidth + 300;
  buttonY = graphY - graphHeight + 20;
  graphX = width * 0.2;  // Set the initial X-coordinate of the graph
  graphY = height * 0.8;  // Set the initial Y-coordinate of the graph
  graphWidth = width * 0.6; // Width of the graph
  graphHeight = height * 0.6; // Height of the graph
  
  printArray(Serial.list());  // Print available serial ports in the console
  port = new Serial(this, "COM5", 9600);  // Replace "COM3" with the appropriate port name
  port.bufferUntil('\n');  // Set the character to buffer until newline
  
  // Initialize data points list
  dataPoints = new ArrayList<PVector>();
  
  // Load a bold font
  boldFont = createFont("Arial Bold", 12);  // Replace "Arial Bold" with the name of your desired bold font
  
  // Create generate button
  generateButton = new Button("Generate Table", 50, 50, 120, 30);
  
  showTable = false;
}

void draw() {
  background(255);  // Set the background color to white
  // Set the stroke color and weight for axes and origin
  stroke(0);  // Set the stroke color to black
  strokeWeight(1);  // Set the stroke weight to 1
generateButton.display();
  // Update the position of the graph based on mouse movement
  if (mousePressed) {
    graphX += mouseX - pmouseX;  // Update the X-coordinate of the graph based on mouse movement on the X-axis
    graphY += mouseY - pmouseY;  // Update the Y-coordinate of the graph based on mouse movement on the Y-axis
  }

  // Draw the x-axis
  line(graphX, graphY, graphX + graphWidth, graphY);
  
  // Draw the arrowhead at the end of the x-axis
  float arrowSize = 8;  // Size of the arrowhead
  triangle(graphX + graphWidth - arrowSize, graphY - arrowSize/2,
    graphX + graphWidth - arrowSize, graphY + arrowSize/2,
    graphX + graphWidth, graphY);
    
  textAlign(RIGHT);
  fill(0);
  textFont(boldFont);  // Set the text font to bold
  textSize(12);  // Set the font size for "Angle"
  text("Angle(θ)", graphX + graphWidth/2 + 24, graphY + 42);

  // Draw the y-axis
  line(graphX, graphY, graphX, graphY - graphHeight);
  
  // Draw the arrowhead at the end of the y-axis
  triangle(graphX - arrowSize/2, graphY - graphHeight + arrowSize,
    graphX + arrowSize/2, graphY - graphHeight + arrowSize,
    graphX, graphY - graphHeight);
  
 textAlign(RIGHT);
  fill(0);
  textFont(boldFont);  // Set the text font to bold
  textSize(12);  // Set the font size for "Velocity of Mechanism"
  text("Velocity of Mechanism (m / s)", graphX - 25, graphY - graphHeight + 152);
  
  // Write x-axis values
  textAlign(CENTER);
  fill(0);
  stroke(0);

  for (int i = xMin; i <= xMax; i += xStep) {
    float xPos = map(i, xMin, xMax, graphX, graphX + graphWidth );
    line(xPos, graphY, xPos, graphY + 8);
    text(i, xPos, graphY + 25);
    int numSubDivisions = 10; // Number of smaller divisions within each major division
    float majorDivisionWidth = graphWidth  / (float)(xMax - xMin) * xStep;
    float subDivisionWidth = majorDivisionWidth / numSubDivisions;
    for (int j = 0; j < numSubDivisions; j++) {
      float subXPos = xPos + (j * subDivisionWidth);
      if (subXPos < graphX + graphWidth ) {
        line(subXPos, graphY, subXPos, graphY + 4);
      }
    }
  }
  
 // Write y-axis values
  textAlign(RIGHT, CENTER);
  fill(0);
  stroke(0);
  for (int i = yMin; i <= yMax; i += yStep) {
    float yPos = map(i, yMin, yMax, graphY, graphY - graphHeight);
    line(graphX - 8, yPos, graphX, yPos);
    text(i, graphX - 12, yPos);
     int numSubDivisions = 10; // Number of smaller divisions within each major division
    float majorDivisionWidth = graphHeight / (float)(yMax - yMin) * yStep;
    float subDivisionWidth = majorDivisionWidth / numSubDivisions;
    for (int k = 0; k < numSubDivisions; k++) {
      float subYPos = yPos + (k * subDivisionWidth);
      if (graphY > subYPos) {
        line(graphX - 4, subYPos, graphX, subYPos );
      }
    }
  }
  
  // Draw latest point
  if (dataPoints.size() > 0) {
    PVector latestPoint = dataPoints.get(dataPoints.size() - 1);
    float x = map(latestPoint.x, xMin, xMax, graphX, graphX + graphWidth);
    float y = map(latestPoint.y, yMin, yMax, graphY, graphY - graphHeight);
    fill(255, 0, 0);
    ellipse(x, y, 8, 8);
  }
  
  // Draw data points
  noFill();
  stroke(0, 0, 255);
  
  for (int i = 1; i < dataPoints.size(); i++) {
    PVector prevPoint = dataPoints.get(i - 1);
    PVector point = dataPoints.get(i);
    
    float prevX = map(prevPoint.x, xMin, xMax, graphX, graphX + graphWidth);
    float prevY = map(prevPoint.y, yMin, yMax, graphY, graphY - graphHeight);
    float x = map(point.x, xMin, xMax, graphX, graphX + graphWidth);
    float y = map(point.y, yMin, yMax, graphY, graphY - graphHeight);
    
    line(prevX, prevY, x, y);
  }
  
  // Display table if showTable is true
  if (showTable) {
    drawTable();
  }
}

void serialEvent(Serial port) {
  String data = port.readStringUntil('\n');  // Read the received data until newline character
  if (data != null) {
    data = data.trim();
    println("Data received: " + data);
    
    // Parse the data string
    int commaIndex = data.indexOf(',');
    if (commaIndex != -1) {
      String angleStr = data.substring(0, commaIndex);
      String hDotStr = data.substring(commaIndex + 1);
      
      // Convert the parsed values to floats
      float angle = float(angleStr);
      float h_dot = float(hDotStr);
      
      // Create a PVector with angle and h_dot values
      PVector point = new PVector(angle, h_dot);
      
      // Add the point to the data points list
      dataPoints.add(point);
      
      // Print the parsed values
      println("Parsed Angle: " + angle);
      println("Parsed h_dot: " + h_dot);
    }
  }
}

void mousePressed() {
  if (generateButton.isClicked()) {
    generateTable();
    showTable = true;
  }
}

void generateTable() {
  dataTable = new Table();
  dataTable.addColumn("Angle");
  dataTable.addColumn("Velocity of Mechanism");

  for (PVector point : dataPoints) {
    TableRow row = dataTable.addRow();
    float mappedAngle = map(point.x, graphX, graphX + graphWidth, xMin, xMax);
    row.setFloat("Angle", mappedAngle);
    row.setFloat("Velocity of Mechanism", point.y);
  }
}


void drawTable() {
  float tableX = 50;
  float tableY = 100;
  float columnWidth = 100;
  float rowHeight = 30;

  fill(255);
  stroke(0);
  rect(tableX, tableY, columnWidth * 2, rowHeight);

  textAlign(CENTER, CENTER);
  fill(0);
  textFont(boldFont);
  textSize(12);

  float headerX = tableX + columnWidth / 2;
  float headerY = tableY + rowHeight / 2;
  text("Angle (θ)", headerX, headerY);
  text("Velocity of Mechanism", headerX + columnWidth, headerY);

  for (int i = 0; i < dataTable.getRowCount(); i++) {
    TableRow row = dataTable.getRow(i);
    float rowX = tableX;
    float rowY = tableY + rowHeight * (i + 1);
    float mappedAngle = row.getFloat("Angle");
    float angleDegrees = map(mappedAngle, xMin, xMax, graphX, graphX + graphWidth);
    text(nf(angleDegrees, 0, 2), rowX + columnWidth / 2, rowY + rowHeight / 2);
    text(nf(row.getFloat("Velocity of Mechanism"), 0, 2), rowX + columnWidth * 1.5, rowY + rowHeight / 2);
  }
}

class Button {
  String label;
  float x, y, width, height;

  Button(String label, float x, float y, float width, float height) {
    this.label = label;
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
  }

  void display() {
    // Draw button
    rectMode(CORNER);
    fill(200);
    stroke(0);
    rect(buttonX, buttonY, width, height);

    // Draw label
   textAlign(CENTER, CENTER);
    fill(0);
    textFont(boldFont);
    textSize(12);
    text(label, buttonX + width / 2, buttonY + height / 2);
  }

  boolean isClicked() {
  return mouseX >= buttonX && mouseX <= buttonX + width && mouseY >= buttonY && mouseY <= buttonY + height;
}
}

As far as a separate window goes you could a) use a class which extends PApplet or b) add a separate JFrame window to the default Processing window. Do you want the window to be shown all the time or only when the generate table button is pressed? Have you considered the length of that table? It could run into the thousands of data points depending on how long the user waits to hit the button. You’re not going to be able to get a window long enough to show all the data. Otherwise, you would need a table with a vertical scrollbar to display the data in a conventional sized window. The other option would be to not to show all the data but only the last 32 points (or similar limitation), depending on window size.

the rows should be 18 , columns 2 , and when i press button the table should pop out , right now both windows in same spot thats why do not good looking

Another option would be to widen out your main window and print the data over to the right; it’s only two columns. You could print the data into a rectangle (with or without colored fill) to make it stand out. If you used a separate JFrame window you would probably have to use a JTable on a separate thread. If you used a separate class which extends PApplet you could likely use the same table, but when the user closed the second window I believe it will also close the main window. It might be easier to experiment with the different options in a separate project until you figure out which method you prefer.

1 Like

thats perfect idea going to try this

i can not make separate window for generate table , please can you guide me

One possibility is to make a hybrid window: part with JFrame and JTable and part with default AWT canvas so that you can still use draw():

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

javax.swing.JFrame frame;
java.awt.Canvas canvas;

int _wndW = 700;
int _wndH = 600;

void table(int x, int y, int w, int h) {
  String data[][] = {
    {"Boat", "Yellow"},
    {"Car", "Magenta"},
    {"House", "White"}
  };
  String header[] = {"ITEM", "COLOR"};
  JTable table = new JTable(data, header);
  table.setSelectionForeground(Color.WHITE);
  JScrollPane scrlPane = new JScrollPane(table);
  scrlPane.setBounds(x, y, w, h);
  frame.add(scrlPane);
  // **** Listener **** //
  ListSelectionModel cellSelectionModel = table.getSelectionModel();
  cellSelectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
  cellSelectionModel.addListSelectionListener(new ListSelectionListener() {
    void valueChanged(ListSelectionEvent evnt) {
      String selectedData = null;
      int[] selectedRow = table.getSelectedRows();
      int[] selectedColumns = table.getSelectedColumns();
      for (int i = 0; i < selectedRow.length; i++) {
        for (int j = 0; j < selectedColumns.length; j++) {
          selectedData = (String) table.getValueAt(selectedRow[i], selectedColumns[j]); 
           println(selectedData);
        }
      }
    }
  }
  );
}

void buildWnd() {
  table(10, 10, 130, _wndH - 50);
}

void setup() {
  size(_wndW, _wndH);
  surface.setTitle("Swing JFrame Components with Default AWT Canvas");
  frame = (javax.swing.JFrame) ((processing.awt.PSurfaceAWT.SmoothCanvas) surface.getNative()).getFrame();
  canvas = (processing.awt.PSurfaceAWT.SmoothCanvas) ((processing.awt.PSurfaceAWT)surface).getNative();
  frame.setBounds(600, 150, _wndW, _wndH); // Makes it possible to add swing components
  canvas.setBounds(150, 0, _wndW - 150, _wndH); // Default canvas used for draw()
  javax.swing.SwingUtilities.invokeLater(new Runnable() {
    public void run() {
      buildWnd(); // Builds components on EventDispatchThread
    }
  }
  );
}

void draw() {
  background(209);
  fill(color(255, 0, 0));
  stroke(0);
  strokeWeight(4.0);
  circle(250, 255, 200);
}

Second option is to create separate windows: one default Processing window and other JFrame window that you could add a JTable to. Can post this code later if you decide to go that way.

1 Like

i would like to go for separate window please

Source code for default Processing window and auxillary JFrame window with JTable. Not sure about EventDispatchThread for Swing component, but since we’re only using one component may be able to get by without it.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import controlP5.*;

ControlP5 cp5;
JFrame frame;

int _wndW = 600;
int _wndH = 600;

void table(int x, int y, int w, int h) {
  String data[][] = {
    {"Boat", "Yellow"},
    {"Car", "Magenta"},
    {"House", "White"}
  };
  String header[] = {"ITEM", "COLOR"};
  JTable table = new JTable(data, header);
  table.setSelectionForeground(Color.WHITE);
  JScrollPane scrlPane = new JScrollPane(table);
  scrlPane.setBounds(x, y, w, h);
  frame.add(scrlPane);
  // **** Listener **** //
  ListSelectionModel cellSelectionModel = table.getSelectionModel();
  cellSelectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
  cellSelectionModel.addListSelectionListener(new ListSelectionListener() {
    void valueChanged(ListSelectionEvent evnt) {
      String selectedData = null;
      int[] selectedRow = table.getSelectedRows();
      int[] selectedColumns = table.getSelectedColumns();
      for (int i = 0; i < selectedRow.length; i++) {
        for (int j = 0; j < selectedColumns.length; j++) {
          selectedData = (String) table.getValueAt(selectedRow[i], selectedColumns[j]);
          println(selectedData);
        }
      }
    }
  }
  );
}

void setup() {
  size(_wndW, _wndH); // default window
  surface.setTitle("Default Window");
  cp5 = new ControlP5(this);

  cp5.addButton("showWnd")
    .setLabel("Show JFrame")
    .setPosition(30, 10)
    .setSize(120, 24)
    ;
// Auxillary window for table
  frame = new JFrame("JFrame Demo");
  frame.setBounds(500, 300, 300, 350);
  frame.setVisible(false); // Don't show initially
}

void draw() {
  fill(0, 255, 0);
  circle( width/2, height/2, 300);
}

void showWnd() {
  frame.setVisible(true);
  table(10, 10, 130, 200);
}

this is also good
“One possibility is to make a hybrid window: part with JFrame and JTable and part with default AWT canvas so that you can still use draw():”
please can you tell how can i manage this code in my code

Draw your graph in the default canvas with draw() just like before. Put the table data into the table (it has a scrollbar when it gets full so should hold a lot of data). You may have to read about how to populate a JTable with your data.

i should draw in original code or make new code in processing ?

import javax.swing.JFrame;
import javax.swing.JTable;

JFrame frame;
JTable table;

void setup() {
  size(700, 500);
  frame = new JFrame("Table");
  String[] columnNames = {"Angle", "Velocity of Mechanism"};
  Object[][] data = { { 0, 0 }, { 10, 1 }, { 20, 2 }, { 30, 3 }, { 40, 4 }, { 50, 5 } };
  table = new JTable(data, columnNames);
  frame.add(table.getTableHeader());
  frame.add(table);
  frame.pack();
  frame.setVisible(true);
}

void draw() {
  background(255);
  // Draw everything as usual
  // ...
  // Get the data from the JTable and update the Processing sketch
  for (int i = 0; i < dataPoints.size(); i++) {
    TableRow row = dataTable.getRow(i);
    float mappedAngle = row.getFloat("Angle");
    float angleDegrees = map(mappedAngle, xMin, xMax, graphX, graphX + graphWidth);
    float velocity = row.getFloat("Velocity of Mechanism");
    // Use the data to draw something on the Processing canvas
    // ...
  }
}

is this fine , please check

I’m unable to run your demo. The two examples that I posted is called ‘boilerplate’ code and is the base code for whatever you are going to add on top of it. Pick one of the examples and add your previous working graph code to it. The circle code in draw() can be deleted. It was used just to show that you can use standard Processing graphics and don’t need Java graphics code. Your previous code should work just fine and you don’t need to write anything new for the graphics. Where you could have problems is populating the JTable because this will be new for you.

1 Like

yes sure thank you very much going to try it now JTable

Actually that code that you posted might work. I don’t have the data points so it wouldn’t run for me. Instead I REMmed out that code and used standard circle code and it worked. Keep going with what you are doing and hold the boilerplate code for now. My result is below:

1 Like