From d3f234f33135c821a131074820696a16d32846f6 Mon Sep 17 00:00:00 2001 From: Devin Conley Date: Thu, 5 Jan 2017 17:55:27 -0500 Subject: [PATCH 01/16] Breaking out listener into Graph class. remove redundant directory --- listener/Graph.java | 36 +++++++++++++++++++ ...er_processingListener.pde => listener.pde} | 10 +++--- 2 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 listener/Graph.java rename listener/{ArduinoPlotter_processingListener/ArduinoPlotter_processingListener.pde => listener.pde} (97%) diff --git a/listener/Graph.java b/listener/Graph.java new file mode 100644 index 0000000..18a7e46 --- /dev/null +++ b/listener/Graph.java @@ -0,0 +1,36 @@ + + +class Graph +{ + // Data + + + + // Contructor + public Graph( int posX, int posY, int height, int width, + boolean xvy, int numVars, int maxPoints, + String title, String[] labels ) + { + + } + + // Modifiers + public void Reconfigure() + {} + + public void Update() + {} + + public void Plot() + {} + + // Internal Helpers + private void PlotXY() + {} + + private void PlotTime() + {} + + private void DrawTicks() + {} +} \ No newline at end of file diff --git a/listener/ArduinoPlotter_processingListener/ArduinoPlotter_processingListener.pde b/listener/listener.pde similarity index 97% rename from listener/ArduinoPlotter_processingListener/ArduinoPlotter_processingListener.pde rename to listener/listener.pde index 4bdd1ea..f954cbc 100644 --- a/listener/ArduinoPlotter_processingListener/ArduinoPlotter_processingListener.pde +++ b/listener/listener.pde @@ -1,7 +1,7 @@ /* =========================================================================================== - ArduinoPlotter_processingListener is the source processing script that corresponds to the - Plotter library for Arduino. The library supports plots against time as well as 2-variable + This listener is the source processing script that corresponds to the Arduino Plotter + library for Arduino. The library supports plots against time as well as 2-variable "X vs Y" graphing. ------------------------------------------------------------------------------------------- The library transfers information via the serial port to a listener program written with the @@ -15,7 +15,7 @@ https://github.com/devinconley/Arduino-Plotter ------------------------------------------------------------------------------------------- - ArduinoPlotter_processingListener + Arduino Plotter Listener v2.0.0 https://github.com/devinconley/Arduino-Plotter by Devin Conley @@ -26,7 +26,7 @@ import processing.serial.*; Serial port; //CONSTANTS -final int[] COLORS = {#00FF00,#FF0000,#0000FF, #FEFF00, #FF9900, #FF00FF}; //int color codes +final int[] COLORS = {#00FF00, #FF0000,#0000FF, #FEFF00, #FF9900, #FF00FF}; //int color codes final char OUTER_KEY = '#'; final String INNER_KEY = "@"; final float AXIS_COVERAGE = 0.75; @@ -265,6 +265,8 @@ void serialEvent(Serial ser) { pos_x = new int[max_points]; num_points = new int[num_graphs]; + //Graph test = new Graph(0, 0, 100, 100, false, 1, 1000, "Test", labels); + // Iterate through the individual graph data blocks to get graph specific info int k = 0; // k tracks overall variable index for (int i = 0; i < num_graphs; i++) { From 3ce990ba4b4e954b44adf42519135871f63fd692 Mon Sep 17 00:00:00 2001 From: Devin Conley Date: Mon, 9 Jan 2017 00:36:21 -0500 Subject: [PATCH 02/16] Filled in constructor and reconfig --- listener/Graph.java | 54 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/listener/Graph.java b/listener/Graph.java index 18a7e46..04b5d8b 100644 --- a/listener/Graph.java +++ b/listener/Graph.java @@ -2,35 +2,69 @@ class Graph { - // Data - + // Config + int posY; + int posX; + int height; + int width; + + boolean xvy; + int numVars; + int maxPoints; + String title; + String[] labels; + // Data + int posX; + double[][] data; + int[] extremesCounter; + double[] extremes; // {min_x, max_x, min_y, max_y} // Contructor - public Graph( int posX, int posY, int height, int width, + public Graph( int posY, int posX, int height, int width, boolean xvy, int numVars, int maxPoints, String title, String[] labels ) { - + this.posY = posY; + this.posX = posX; + this.height = height; + this.width = width; + this.xvy = xvy; + this.numVars = numVars; + this.maxPoints = maxPoints; + this.title = title; + this.labels = labels; } // Modifiers - public void Reconfigure() - {} + public void Reconfigure( int posY, int posX, int height, int width, + boolean xvy, int numVars, int maxPoints, + String title, String[] labels ) + { + this.posY = posY; + this.posX = posX; + this.height = height; + this.width = width; + this.xvy = xvy; + this.numVars = numVars; + this.maxPoints = maxPoints; + this.title = title; + this.labels = labels; + } - public void Update() + public void Update( double[] newData ) {} public void Plot() {} // Internal Helpers - private void PlotXY() + private void DrawDataXY() {} - private void PlotTime() + private void DrawDataTime() {} private void DrawTicks() {} -} \ No newline at end of file +} From 12b450e9d3edd58afede04db15226ac8a3c2f0ca Mon Sep 17 00:00:00 2001 From: Devin Conley Date: Wed, 11 Jan 2017 09:43:45 -0500 Subject: [PATCH 03/16] Creating graph objects for handling each subset of data --- listener/Graph.java | 85 ++++- listener/listener.pde | 736 ++++++++++++++++++++++-------------------- 2 files changed, 466 insertions(+), 355 deletions(-) diff --git a/listener/Graph.java b/listener/Graph.java index 04b5d8b..8547961 100644 --- a/listener/Graph.java +++ b/listener/Graph.java @@ -1,12 +1,19 @@ +import processing.core.PApplet; + +// CONST + class Graph { + // Reference to PApplet drawing canvas + PApplet parent; + // Config - int posY; - int posX; - int height; - int width; + float posY; + float posX; + float height; + float width; boolean xvy; int numVars; @@ -15,16 +22,17 @@ class Graph String[] labels; // Data - int posX; + int index; double[][] data; int[] extremesCounter; double[] extremes; // {min_x, max_x, min_y, max_y} // Contructor - public Graph( int posY, int posX, int height, int width, + public Graph( PApplet parent, float posY, float posX, float height, float width, boolean xvy, int numVars, int maxPoints, String title, String[] labels ) { + this.parent = parent; this.posY = posY; this.posX = posX; this.height = height; @@ -34,10 +42,18 @@ public Graph( int posY, int posX, int height, int width, this.maxPoints = maxPoints; this.title = title; this.labels = labels; + + this.parent.println( "Constructed new graph: ", this.title, this.posY, " ", this.posX); + + // Initialize + index = 0; + data = new double[maxPoints][numVars]; + extremesCounter = new int[4]; + extremes = new double[4]; } // Modifiers - public void Reconfigure( int posY, int posX, int height, int width, + public void Reconfigure( float posY, float posX, float height, float width, boolean xvy, int numVars, int maxPoints, String title, String[] labels ) { @@ -52,19 +68,66 @@ public void Reconfigure( int posY, int posX, int height, int width, this.labels = labels; } + public void Reconfigure( int posY, int posX, int height, int width ) + { + this.posY = posY; + this.posX = posX; + this.height = height; + this.width = width; + } + public void Update( double[] newData ) {} public void Plot() - {} + { + // Plot Background + this.parent.fill( PLOT_COL ); + this.parent.stroke( 255 ); + this.parent.rect( this.posX, this.posY, this.width, this.height ); + + // Title + this.parent.textSize( TITLE_SZ ); + this.parent.fill( 255 ); + this.parent.textAlign( this.parent.CENTER, this.parent.TOP ); + this.parent.text( this.title, this.posX + this.height/2, this.posY + TITLE_SZ); - // Internal Helpers - private void DrawDataXY() + + // Calculations for offset and scaling of graph ( vs. time ) + double xScale = this.width / ( this.extremes[1] - this.extremes[0] ); + double xOffset = xScale * this.extremes[0]; + double yScale = AXIS_COV * this.height / ( this.extremes[3] - this.extremes[2] ); + double yOffset = yScale * this.extremes[3] + 0.5 * ( 1.0 - AXIS_COV ) * this.height; + + // Draw + if ( this.xvy ) + { + this.DrawDataXY( xScale, yScale, xOffset, yOffset ); + } + else + { + this.DrawDataTime( xScale, yScale, xOffset, yOffset ); + } + } + + // Internal Helpers + private void DrawDataTime( double xScale, double yScale, double xOffset, double yOffset ) {} - private void DrawDataTime() + private void DrawDataXY( double xScale, double yScale, double xOffset, double yOffset ) {} + private void DrawTicks() {} + + // Constants + private static final float AXIS_COV = 0.75f; + private static final int PLOT_COL = 115; + private static final int LABEL_SZ = 14; + private static final int TITLE_SZ = 16; + private static final int NUM_SZ = 10; + private static final int TICK_LEN = 6; + private static final int NUM_TICKS = 5; + private static final float PT_SZ = 1.5f; } diff --git a/listener/listener.pde b/listener/listener.pde index f954cbc..fd333e6 100644 --- a/listener/listener.pde +++ b/listener/listener.pde @@ -20,7 +20,7 @@ https://github.com/devinconley/Arduino-Plotter by Devin Conley =========================================================================================== - */ +*/ import processing.serial.*; Serial port; @@ -52,6 +52,8 @@ String config_code = "This will not be matched!"; boolean configured = false; int last_config; +ArrayList graphs; + // Graph-specific setup globals float[][] pos_graphs; // stored as {x, y} String[] titles; @@ -69,399 +71,445 @@ String[] labels; void setup() { - size(800, 800); - surface.setResizable(true); - h = height; - w = width; - String portID = Serial.list()[0]; - port = new Serial(this, portID, 115200); - port.bufferUntil('#'); - frameRate(100); - textSize(16); - background(BG_COL); - strokeWeight(PT_SZ); + size(800, 800); + surface.setResizable(true); + h = height; + w = width; + String portID = Serial.list()[0]; + port = new Serial(this, portID, 115200); + port.bufferUntil('#'); + frameRate(100); + textSize(16); + background(BG_COL); + strokeWeight(PT_SZ); } void draw() { - //PLOT ALL - try { - if (configured) { - background(BG_COL); - for (int i = 0; i < num_graphs; i++) { - if (xvy[i]) { - plot_xy(i); - } else{ - plot_time(i); + //PLOT ALL + try { + if (configured) { + background(BG_COL); + for (int i = 0; i < num_graphs; i++) { + if (xvy[i]) { + plot_xy(i); + } else{ + plot_time(i); + } + } + for( int i = 0; i < graphs.size(); i++ ) + { + graphs.get(i).Plot(); + } } - } - } - if ( h != height || w != width) { - h = height; - w = width; - setupGraphPosition(); - } - } catch (Exception e) {} + if ( h != height || w != width) { + h = height; + w = width; + setupGraphPosition( num_graphs ); + } + } catch (Exception e) {} } void plot_xy(int graph_index) { - int g = graph_index; - int k = first_index_graphs[g]; - - // Calculations for offset and scaling of graph - double x_scale = AXIS_COVERAGE * sub_width / (extremes_graphs[g][1] - extremes_graphs[g][0]); - double x_offset = x_scale*extremes_graphs[g][0] - 0.5*(1.0 - AXIS_COVERAGE)*sub_width; - double y_scale = AXIS_COVERAGE * sub_height / (extremes_graphs[g][3] - extremes_graphs[g][2]); - double y_offset = y_scale*extremes_graphs[g][3] + 0.5*(1.0 - AXIS_COVERAGE)*sub_height; - - // Plot Background - fill(PLOT_COL); - stroke(255); - rect(pos_graphs[g][0],pos_graphs[g][1],sub_width,sub_height); - // Title - textSize(TITLE_SZ); - fill(255); - textAlign(CENTER, TOP); - text(titles[g], pos_graphs[g][0] + sub_width/2, pos_graphs[g][1] + TITLE_SZ); - // X and Y labels - textSize(LABEL_SZ); - textAlign(LEFT, TOP); - text(labels[k+1], pos_graphs[g][0] + 10, pos_graphs[g][1] + 10); - textAlign(RIGHT, BOTTOM); - text(labels[k], pos_graphs[g][0] + sub_width - 10, pos_graphs[g][1] + sub_height - 3*NUM_SZ); - drawTicks(g); - - // ** add support for multiple paths in x-y here ** - stroke(COLORS[0]); - for (int j = 0; j < num_points[g]; j++) { - point( (float)(pos_graphs[g][0] + (data[j][k][1]*x_scale - x_offset)), - (float)(pos_graphs[g][1] + y_offset - data[j][k+1][1]*y_scale) ); - } + int g = graph_index; + int k = first_index_graphs[g]; + + // Calculations for offset and scaling of graph + double x_scale = AXIS_COVERAGE * sub_width / (extremes_graphs[g][1] - extremes_graphs[g][0]); + double x_offset = x_scale*extremes_graphs[g][0] - 0.5*(1.0 - AXIS_COVERAGE)*sub_width; + double y_scale = AXIS_COVERAGE * sub_height / (extremes_graphs[g][3] - extremes_graphs[g][2]); + double y_offset = y_scale*extremes_graphs[g][3] + 0.5*(1.0 - AXIS_COVERAGE)*sub_height; + + // Plot Background + fill(PLOT_COL); + stroke(255); + rect(pos_graphs[g][0],pos_graphs[g][1],sub_width,sub_height); + // Title + textSize(TITLE_SZ); + fill(255); + textAlign(CENTER, TOP); + text(titles[g], pos_graphs[g][0] + sub_width/2, pos_graphs[g][1] + TITLE_SZ); + // X and Y labels + textSize(LABEL_SZ); + textAlign(LEFT, TOP); + text(labels[k+1], pos_graphs[g][0] + 10, pos_graphs[g][1] + 10); + textAlign(RIGHT, BOTTOM); + text(labels[k], pos_graphs[g][0] + sub_width - 10, pos_graphs[g][1] + sub_height - 3*NUM_SZ); + drawTicks(g); + + // ** add support for multiple paths in x-y here ** + stroke(COLORS[0]); + for (int j = 0; j < num_points[g]; j++) { + point( (float)(pos_graphs[g][0] + (data[j][k][1]*x_scale - x_offset)), + (float)(pos_graphs[g][1] + y_offset - data[j][k+1][1]*y_scale) ); + } } void plot_time(int graph_index) { - int g = graph_index; - int k = first_index_graphs[g]; - - // Calculations for offset and scaling of graph - double x_scale = sub_width / (extremes_graphs[g][1] - extremes_graphs[g][0]); - double x_offset = x_scale*extremes_graphs[g][0]; - double y_scale = AXIS_COVERAGE*sub_height / (extremes_graphs[g][3] - extremes_graphs[g][2]); - double y_offset = y_scale*extremes_graphs[g][3] + 0.5*(1.0 - AXIS_COVERAGE)*sub_height; + int g = graph_index; + int k = first_index_graphs[g]; + + // Calculations for offset and scaling of graph + double x_scale = sub_width / (extremes_graphs[g][1] - extremes_graphs[g][0]); + double x_offset = x_scale*extremes_graphs[g][0]; + double y_scale = AXIS_COVERAGE*sub_height / (extremes_graphs[g][3] - extremes_graphs[g][2]); + double y_offset = y_scale*extremes_graphs[g][3] + 0.5*(1.0 - AXIS_COVERAGE)*sub_height; - // Plot Background - fill(PLOT_COL); - stroke(255); - rect(pos_graphs[g][0],pos_graphs[g][1],sub_width,sub_height); - // Title - textSize(TITLE_SZ); - fill(255); - textAlign(CENTER, TOP); - text(titles[g], pos_graphs[g][0] + sub_width/2, pos_graphs[g][1] + TITLE_SZ); + // Plot Background + fill(PLOT_COL); + stroke(255); + rect(pos_graphs[g][0],pos_graphs[g][1],sub_width,sub_height); + // Title + textSize(TITLE_SZ); + fill(255); + textAlign(CENTER, TOP); + text(titles[g], pos_graphs[g][0] + sub_width/2, pos_graphs[g][1] + TITLE_SZ); - // Plot legend - float textPos = pos_graphs[g][1] + LABEL_SZ; - textAlign(RIGHT, TOP); - textSize(LABEL_SZ); - // Plot each line - for (int i = 0; i < sz_graphs[g]; i++) { - fill(COLORS[i]); - text(labels[k + i],pos_graphs[g][0] + sub_width - 10,textPos); - textPos += (LABEL_SZ + 3); - stroke(COLORS[i]); + // Plot legend + float textPos = pos_graphs[g][1] + LABEL_SZ; + textAlign(RIGHT, TOP); + textSize(LABEL_SZ); + // Plot each line + for (int i = 0; i < sz_graphs[g]; i++) { + fill(COLORS[i]); + text(labels[k + i],pos_graphs[g][0] + sub_width - 10,textPos); + textPos += (LABEL_SZ + 3); + stroke(COLORS[i]); - for (int j = 0; j < num_points[g]; j++) { - point( (float)(pos_graphs[g][0] + (data[j][k+i][0]*x_scale - x_offset)), - (float)(pos_graphs[g][1] + y_offset - data[j][k+i][1]*y_scale) ); + for (int j = 0; j < num_points[g]; j++) { + point( (float)(pos_graphs[g][0] + (data[j][k+i][0]*x_scale - x_offset)), + (float)(pos_graphs[g][1] + y_offset - data[j][k+i][1]*y_scale) ); - } + } - } - // Draw axis - noFill(); - stroke(255); - rect(pos_graphs[g][0],pos_graphs[g][1],sub_width,sub_height); - drawTicks(g); // draw ticks over any data (only an issue with time plot) + } + // Draw axis + noFill(); + stroke(255); + rect(pos_graphs[g][0],pos_graphs[g][1],sub_width,sub_height); + drawTicks(g); // draw ticks over any data (only an issue with time plot) } void drawTicks(int g) { - // Label graph with numbered tick marks - stroke(255); - fill(255); - textSize(NUM_SZ); - textAlign(LEFT, CENTER); - // Draw ticks along y-axis - float temp_x = pos_graphs[g][0] - TICK_LEN/2; - float tick_offset = 0.5*(1.0 - AXIS_COVERAGE)*sub_height; - float tick_interval = AXIS_COVERAGE * sub_height / (NUM_TICKS - 1); - float val = (float)extremes_graphs[g][3]; - float val_interval = (float)(extremes_graphs[g][3] - extremes_graphs[g][2]) / (NUM_TICKS - 1); - for (float temp_y = pos_graphs[g][1] + tick_offset; - temp_y <= pos_graphs[g][1] + sub_height - tick_offset; temp_y += tick_interval) { - line(temp_x, temp_y, temp_x + TICK_LEN, temp_y); - text(Float.toString(val), temp_x + TICK_LEN + 5, temp_y); - val -= val_interval; - } - // Draw along x-axis (will be diff for each type of graph) - float temp_y = pos_graphs[g][1] + sub_height - TICK_LEN/2; - // if XvY graph, evenly spaced ticks within coverage - if (xvy[g]) { - val = (float)extremes_graphs[g][0]; - val_interval = (float)(extremes_graphs[g][1] - extremes_graphs[g][0]) / (NUM_TICKS - 1); - tick_offset = 0.5*(1.0 - AXIS_COVERAGE)*sub_width; - tick_interval = AXIS_COVERAGE * sub_width / (NUM_TICKS - 1); - // if a time graph, evenly spaced ticks across all - } else { - val_interval = (float)(extremes_graphs[g][1] - extremes_graphs[g][0]) / (NUM_TICKS + 1); - val = (float)extremes_graphs[g][0] + val_interval; - tick_offset = sub_width / (NUM_TICKS + 1); - tick_interval = tick_offset; - } - textAlign(CENTER, BOTTOM); - for (temp_x = pos_graphs[g][0] + tick_offset; - temp_x <= pos_graphs[g][0] + sub_width - tick_offset; - temp_x += tick_interval) { - line(temp_x, temp_y, temp_x, temp_y + TICK_LEN); - text(Float.toString(val), temp_x, temp_y - 5); - val += val_interval; - } + // Label graph with numbered tick marks + stroke(255); + fill(255); + textSize(NUM_SZ); + textAlign(LEFT, CENTER); + // Draw ticks along y-axis + float temp_x = pos_graphs[g][0] - TICK_LEN/2; + float tick_offset = 0.5*(1.0 - AXIS_COVERAGE)*sub_height; + float tick_interval = AXIS_COVERAGE * sub_height / (NUM_TICKS - 1); + float val = (float)extremes_graphs[g][3]; + float val_interval = (float)(extremes_graphs[g][3] - extremes_graphs[g][2]) / (NUM_TICKS - 1); + for (float temp_y = pos_graphs[g][1] + tick_offset; + temp_y <= pos_graphs[g][1] + sub_height - tick_offset; temp_y += tick_interval) { + line(temp_x, temp_y, temp_x + TICK_LEN, temp_y); + text(Float.toString(val), temp_x + TICK_LEN + 5, temp_y); + val -= val_interval; + } + // Draw along x-axis (will be diff for each type of graph) + float temp_y = pos_graphs[g][1] + sub_height - TICK_LEN/2; + // if XvY graph, evenly spaced ticks within coverage + if (xvy[g]) { + val = (float)extremes_graphs[g][0]; + val_interval = (float)(extremes_graphs[g][1] - extremes_graphs[g][0]) / (NUM_TICKS - 1); + tick_offset = 0.5*(1.0 - AXIS_COVERAGE)*sub_width; + tick_interval = AXIS_COVERAGE * sub_width / (NUM_TICKS - 1); + // if a time graph, evenly spaced ticks across all + } else { + val_interval = (float)(extremes_graphs[g][1] - extremes_graphs[g][0]) / (NUM_TICKS + 1); + val = (float)extremes_graphs[g][0] + val_interval; + tick_offset = sub_width / (NUM_TICKS + 1); + tick_interval = tick_offset; + } + textAlign(CENTER, BOTTOM); + for (temp_x = pos_graphs[g][0] + tick_offset; + temp_x <= pos_graphs[g][0] + sub_width - tick_offset; + temp_x += tick_interval) { + line(temp_x, temp_y, temp_x, temp_y + TICK_LEN); + text(Float.toString(val), temp_x, temp_y - 5); + val += val_interval; + } } void serialEvent(Serial ser) { - // Listen for serial data until #, the end of transmission key - try { - String temp = ser.readStringUntil(OUTER_KEY); - String[] array_main = temp.split("\n"); + // Listen for serial data until #, the end of transmission key + try { + String message = ser.readStringUntil(OUTER_KEY); + String[] arrayMain = message.split("\n"); - // ********************************************************* // - // ************* PLOT SETUP FROM CONFIG CODE *************** // - // ********************************************************* // + // ********************************************************* // + // ************* PLOT SETUP FROM CONFIG CODE *************** // + // ********************************************************* // - // If config code has changed, need to go through setup again - if (!config_code.equals(array_main[0])) { - String[] array_sub = array_main[0].split(INNER_KEY); - // Check for size of full transmission against expected to flag bad transmission - num_graphs = Integer.parseInt(array_sub[0]); - if (array_main.length != num_graphs+1) { - throw new Exception(); - } - configured = false; - //print("New config"); + // If config code has changed, need to go through setup again + if (!config_code.equals(arrayMain[0])) { + String[] arraySub = arrayMain[0].split(INNER_KEY); + // Check for size of full transmission against expected to flag bad transmission + num_graphs = Integer.parseInt(arraySub[0]); + if (arrayMain.length != num_graphs+1) { + throw new Exception(); + } + configured = false; + //print("New config"); - setupGraphPosition(); + - // Pull more values and reset datastore arrays as appropriate - total_vars = Integer.parseInt(array_sub[1]); - max_points = Integer.parseInt(array_sub[2]); - labels = new String[total_vars]; - titles = new String[num_graphs]; - xvy = new boolean[num_graphs]; - sz_graphs = new int[num_graphs]; - extremes_graphs = new double[num_graphs][4]; - extremes_graphs_counter = new int[num_graphs][4]; - first_index_graphs = new int[num_graphs]; - data = new double[max_points][total_vars][2]; + // Pull more values and reset datastore arrays as appropriate + total_vars = Integer.parseInt(arraySub[1]); + max_points = Integer.parseInt(arraySub[2]); + labels = new String[total_vars]; + titles = new String[num_graphs]; + xvy = new boolean[num_graphs]; + sz_graphs = new int[num_graphs]; + extremes_graphs = new double[num_graphs][4]; + extremes_graphs_counter = new int[num_graphs][4]; + first_index_graphs = new int[num_graphs]; + data = new double[max_points][total_vars][2]; - pos_x = new int[max_points]; - num_points = new int[num_graphs]; + pos_x = new int[max_points]; + num_points = new int[num_graphs]; + + // Setup new layout + float[][] posGraphs = setupGraphPosition( num_graphs ); + - //Graph test = new Graph(0, 0, 100, 100, false, 1, 1000, "Test", labels); + graphs = new ArrayList(); - // Iterate through the individual graph data blocks to get graph specific info - int k = 0; // k tracks overall variable index - for (int i = 0; i < num_graphs; i++) { - array_sub = array_main[i+1].split(INNER_KEY); - titles[i] = array_sub[0]; - xvy[i] = Integer.parseInt(array_sub[1]) == 1; - num_points[i] = Integer.parseInt(array_sub[2]); - sz_graphs[i] = Integer.parseInt(array_sub[3]); - first_index_graphs[i] = k; - int p = 4; // first label of this graph falls at index 4 - for (int j = 0; j < sz_graphs[i]; j++) { - labels[k] = array_sub[p]; - p += 2; - k++; - } - } - // Set new config code - config_code = array_main[0]; - //println(config_code); - last_config = millis(); - } else { - // Matching a code means we have configured correctly - configured = true; + // Iterate through the individual graph data blocks to get graph specific info + int k = 0; // k tracks overall variable index + for (int i = 0; i < num_graphs; i++) { + arraySub = arrayMain[i+1].split(INNER_KEY); + String title = arraySub[0]; + boolean xvyTemp = Integer.parseInt(arraySub[1]) == 1; + int maxPoints = Integer.parseInt(arraySub[2]); + int numVars = Integer.parseInt(arraySub[3]); + String[] labelsTemp = new String[numVars]; + + + titles[i] = title; + xvy[i] = xvyTemp; + num_points[i] = maxPoints; + sz_graphs[i] = numVars; + first_index_graphs[i] = k; + int p = 4; // first label of this graph falls at index 4 + + for (int j = 0; j < numVars; j++) + { + labelsTemp[j] = arraySub[4 + 2*j]; + labels[k] = arraySub[p]; + p += 2; + k++; + } + // Create new Graph + Graph temp = new Graph(this, posGraphs[i][0], posGraphs[i][1], 100, 100, + xvyTemp, numVars, maxPoints, title, labelsTemp); + graphs.add( temp ); + } + println("Added ", graphs.size() ); + + // Set new config code + config_code = arrayMain[0]; + //println(config_code); + last_config = millis(); + } else { + // Matching a code means we have configured correctly + configured = true; - // *********************************************************** // - // ************ NORMAL PLOTTING FUNCTIONALITY **************** // - // *********************************************************** // - int temp_time = millis(); + // *********************************************************** // + // ************ NORMAL PLOTTING FUNCTIONALITY **************** // + // *********************************************************** // + int temp_time = millis(); - for (int i = 0; i < num_graphs; i++) { - String[] array_sub = array_main[i+1].split(INNER_KEY); + for (int i = 0; i < num_graphs; i++) { + String[] array_sub = arrayMain[i+1].split(INNER_KEY); - if (xvy[i]) { - // Plot x vs y graph - int p = 5; // first index of double in split array + if (xvy[i]) { + // Plot x vs y graph + int p = 5; // first index of double in split array - // j is only a counter for var in graph context - for (int j = first_index_graphs[i]; j < first_index_graphs[i] + sz_graphs[i]; j++) { - data[pos_x[i]][j][1] = Double.parseDouble(array_sub[p]); + // j is only a counter for var in graph context + for (int j = first_index_graphs[i]; j < first_index_graphs[i] + sz_graphs[i]; j++) { + data[pos_x[i]][j][1] = Double.parseDouble(array_sub[p]); - // Check for new extremes ("p-5, "p-4" is just to get index at x:0,1 then y:2,3) - if (data[pos_x[i]][j][1] < extremes_graphs[i][p-5]) { - extremes_graphs[i][p-5] = data[pos_x[i]][j][1]; - extremes_graphs_counter[i][p-5] = 0; - } else if (data[pos_x[i]][j][1] > extremes_graphs[i][p-4]) { - extremes_graphs[i][p-4] = data[pos_x[i]][j][1]; - extremes_graphs_counter[i][p-4] = 0; - } + // Check for new extremes ("p-5, "p-4" is just to get index at x:0,1 then y:2,3) + if (data[pos_x[i]][j][1] < extremes_graphs[i][p-5]) { + extremes_graphs[i][p-5] = data[pos_x[i]][j][1]; + extremes_graphs_counter[i][p-5] = 0; + } else if (data[pos_x[i]][j][1] > extremes_graphs[i][p-4]) { + extremes_graphs[i][p-4] = data[pos_x[i]][j][1]; + extremes_graphs_counter[i][p-4] = 0; + } - p += 2; - } + p += 2; + } - // Check for extremes going out of scope, to need a full new max/min calc - boolean[] needs_calc = {false, false, false, false}; - for (int j = 0; j < 4; j++) { - if (extremes_graphs_counter[i][j] > num_points[i]) { - needs_calc[j] = true; - } else { - extremes_graphs_counter[i][j]++; - } - } - if (needs_calc[0] || needs_calc[1] || needs_calc[2] || needs_calc[3]) { - int j = first_index_graphs[i]; - for (int k = 0; k < num_points[i]; k++) { - // x-direction - if (needs_calc[0] && data[k][j][1] < extremes_graphs[i][0]) { - extremes_graphs[i][0] = data[k][j][1]; - extremes_graphs_counter[i][0] = 0; - } else if (needs_calc[1] && data[k][j][1] > extremes_graphs[i][1]) { - extremes_graphs[i][1] = data[k][j][1]; - extremes_graphs_counter[i][1] = 0; - } - // y-direction - if (needs_calc[2] && data[k][j+1][1] < extremes_graphs[i][2]) { - extremes_graphs[i][2] = data[k][j+1][1]; - extremes_graphs_counter[i][2] = 0; - } else if (needs_calc[3] && data[k][j+1][1] > extremes_graphs[i][3]) { - extremes_graphs[i][3] = data[k][j+1][1]; - extremes_graphs_counter[i][3] = 0; - } - } - } + // Check for extremes going out of scope, to need a full new max/min calc + boolean[] needs_calc = {false, false, false, false}; + for (int j = 0; j < 4; j++) { + if (extremes_graphs_counter[i][j] > num_points[i]) { + needs_calc[j] = true; + } else { + extremes_graphs_counter[i][j]++; + } + } + if (needs_calc[0] || needs_calc[1] || needs_calc[2] || needs_calc[3]) { + int j = first_index_graphs[i]; + for (int k = 0; k < num_points[i]; k++) { + // x-direction + if (needs_calc[0] && data[k][j][1] < extremes_graphs[i][0]) { + extremes_graphs[i][0] = data[k][j][1]; + extremes_graphs_counter[i][0] = 0; + } else if (needs_calc[1] && data[k][j][1] > extremes_graphs[i][1]) { + extremes_graphs[i][1] = data[k][j][1]; + extremes_graphs_counter[i][1] = 0; + } + // y-direction + if (needs_calc[2] && data[k][j+1][1] < extremes_graphs[i][2]) { + extremes_graphs[i][2] = data[k][j+1][1]; + extremes_graphs_counter[i][2] = 0; + } else if (needs_calc[3] && data[k][j+1][1] > extremes_graphs[i][3]) { + extremes_graphs[i][3] = data[k][j+1][1]; + extremes_graphs_counter[i][3] = 0; + } + } + } - // Advance pos_x and rollback pos_x if exceeds max points for specific graph - pos_x[i]++; - if (pos_x[i] >= num_points[i]) { - pos_x[i] = 0; - } + // Advance pos_x and rollback pos_x if exceeds max points for specific graph + pos_x[i]++; + if (pos_x[i] >= num_points[i]) { + pos_x[i] = 0; + } - } else { - // TIME GRAPH HANDLER + } else { + // TIME GRAPH HANDLER - int p = 5; // first index of double in split array - for (int j = first_index_graphs[i]; j < first_index_graphs[i] + sz_graphs[i]; j++) { - data[pos_x[i]][j][0] = temp_time; - data[pos_x[i]][j][1] = Double.parseDouble(array_sub[p]); - p += 2; - - // Check for new extremes - if (data[pos_x[i]][j][1] <= extremes_graphs[i][2]) { - extremes_graphs[i][2] = data[pos_x[i]][j][1]; - extremes_graphs_counter[i][2] = 0; - } else if (data[pos_x[i]][j][1] >= extremes_graphs[i][3]) { - extremes_graphs[i][3] = data[pos_x[i]][j][1]; - - extremes_graphs_counter[i][3] = 0; - } + int p = 5; // first index of double in split array + for (int j = first_index_graphs[i]; j < first_index_graphs[i] + sz_graphs[i]; j++) { + data[pos_x[i]][j][0] = temp_time; + data[pos_x[i]][j][1] = Double.parseDouble(array_sub[p]); + p += 2; + + // Check for new extremes + if (data[pos_x[i]][j][1] <= extremes_graphs[i][2]) { + extremes_graphs[i][2] = data[pos_x[i]][j][1]; + extremes_graphs_counter[i][2] = 0; + } else if (data[pos_x[i]][j][1] >= extremes_graphs[i][3]) { + extremes_graphs[i][3] = data[pos_x[i]][j][1]; + + extremes_graphs_counter[i][3] = 0; + } - } - - // Check for extremes going out of scope, to need a full new max/min calc - boolean[] needs_calc = {false, false, false, false}; - for (int j = 2; j < 4; j++) { - if (extremes_graphs_counter[i][j] > num_points[i]) { - needs_calc[j] = true; - } else { - extremes_graphs_counter[i][j]++; - } - } - if (needs_calc[2] || needs_calc[3]) { - for (int j = first_index_graphs[i]; j < first_index_graphs[i] + sz_graphs[i]; j++) { - for (int k = 0; k < num_points[i]; k++) { - if (needs_calc[2] && data[k][j][1] < extremes_graphs[i][2]) { - extremes_graphs[i][2] = data[k][j][1]; - extremes_graphs_counter[i][2] = 0; - } else if (needs_calc[3] && data[k][j][1] > extremes_graphs[i][3]) { - extremes_graphs[i][3] = data[k][j][1]; - extremes_graphs_counter[i][3] = 0; - } - } - } - } + } + + // Check for extremes going out of scope, to need a full new max/min calc + boolean[] needs_calc = {false, false, false, false}; + for (int j = 2; j < 4; j++) { + if (extremes_graphs_counter[i][j] > num_points[i]) { + needs_calc[j] = true; + } else { + extremes_graphs_counter[i][j]++; + } + } + if (needs_calc[2] || needs_calc[3]) { + for (int j = first_index_graphs[i]; j < first_index_graphs[i] + sz_graphs[i]; j++) { + for (int k = 0; k < num_points[i]; k++) { + if (needs_calc[2] && data[k][j][1] < extremes_graphs[i][2]) { + extremes_graphs[i][2] = data[k][j][1]; + extremes_graphs_counter[i][2] = 0; + } else if (needs_calc[3] && data[k][j][1] > extremes_graphs[i][3]) { + extremes_graphs[i][3] = data[k][j][1]; + extremes_graphs_counter[i][3] = 0; + } + } + } + } - // Max timestamp of graph will be now - extremes_graphs[i][1] = temp_time; + // Max timestamp of graph will be now + extremes_graphs[i][1] = temp_time; - // Advance pos_x and rollback pos_x if exceeds max points for specific graph - pos_x[i]++; - if (pos_x[i] >= num_points[i]) { - pos_x[i] = 0; - } + // Advance pos_x and rollback pos_x if exceeds max points for specific graph + pos_x[i]++; + if (pos_x[i] >= num_points[i]) { + pos_x[i] = 0; + } - // Min timestamp will be whatever this new pos_x has (about to be replaced) - if (data[pos_x[i]][first_index_graphs[i]][0] != 0) { - extremes_graphs[i][0] = data[pos_x[i]][first_index_graphs[i]][0]; - } else { - // But if hasn't fully filled array, need to estimate - extremes_graphs[i][0] = temp_time - - ((temp_time - data[0][first_index_graphs[i]][0]) / pos_x[i])*num_points[i]; - } + // Min timestamp will be whatever this new pos_x has (about to be replaced) + if (data[pos_x[i]][first_index_graphs[i]][0] != 0) { + extremes_graphs[i][0] = data[pos_x[i]][first_index_graphs[i]][0]; + } else { + // But if hasn't fully filled array, need to estimate + extremes_graphs[i][0] = temp_time - + ((temp_time - data[0][first_index_graphs[i]][0]) / pos_x[i])*num_points[i]; + } + } + } } - } } - } - catch (Exception e) { - //println("exception...."); - } + catch (Exception e) { + //println("exception...."); + } } // Helper method to calculate bounds of graphs -void setupGraphPosition() { - // Determine orientation of each graph - int num_high = 1; - int num_wide = 1; - // Increase num subsections in each direction until all graphs can fit - while (num_high * num_wide < num_graphs) { - if (num_wide > num_high) { - num_high++; - } else if (num_high > num_wide) { - num_wide++; - } else if (height >= width ) { - num_high++; - } else { - // Want to increase in width first - num_wide++; - } - } - - // Set bounding box for each subsection - pos_graphs = new float[num_graphs][2]; - int k = 0; // k tracks overall graph index - sub_width = round(w/num_wide); - sub_height = round(h/num_high); - for (int i = 0; i < num_high; i++) { - for (int j = 0; j < num_wide; j++) { - if (k < num_graphs) { - pos_graphs[k][0] = j*sub_width + MARGIN_SZ/2; - pos_graphs[k][1] = i*sub_height + MARGIN_SZ/2; - } - k++; +float[][] setupGraphPosition( int numGraphs ) { + // Determine orientation of each graph + int numHigh = 1; + int numWide = 1; + // Increase num subsections in each direction until all graphs can fit + while ( numHigh * numWide < numGraphs ) + { + if ( numWide > numHigh ) + { + numHigh++; + } + else if ( numHigh > numWide ) + { + numWide++; + } + else if ( height >= width ) + { + numHigh++; + } + else + { + // Want to increase in width first + numWide++; + } + } + + float[][] posGraphs = new float[numGraphs][2]; + + float subHeight = round( h / numHigh ); + float subWidth = round( w / numWide ); + + // Set bounding box for each subsection + pos_graphs = new float[num_graphs][2]; + + sub_width = subWidth; + sub_height = subHeight; + + for(int i = 0; i < numHigh; i++) { + for (int j = 0; j < numWide; j++) { + int k = i * numWide + j; + if ( k < numGraphs ) + { + posGraphs[k][0] = i*subHeight + MARGIN_SZ / 2; + posGraphs[k][1] = j*subWidth + MARGIN_SZ / 2; + } + + if (k < num_graphs) { + pos_graphs[k][0] = j*subWidth + MARGIN_SZ/2; + pos_graphs[k][1] = i*subHeight + MARGIN_SZ/2; + } + k++; + } } - } - sub_width -= MARGIN_SZ; - sub_height -= MARGIN_SZ; + sub_width -= MARGIN_SZ; + sub_height -= MARGIN_SZ; + return posGraphs; } \ No newline at end of file From d43029db19b7469fa4132f8e447e69fe8cfb4b11 Mon Sep 17 00:00:00 2001 From: Devin Conley Date: Wed, 18 Jan 2017 12:35:58 -0500 Subject: [PATCH 04/16] Fully ported listener into graph class, including data updates, extreme checking, data plotting, etc. Made significant changes to improve and consolidate functions between X vs Y and time graphs (specifically for plotting, extremes checking and tick drawing) --- listener/Graph.java | 265 ++++++++++++++++++++++++++++++++++++++---- listener/listener.pde | 25 +++- 2 files changed, 263 insertions(+), 27 deletions(-) diff --git a/listener/Graph.java b/listener/Graph.java index 8547961..bec3fad 100644 --- a/listener/Graph.java +++ b/listener/Graph.java @@ -1,9 +1,5 @@ import processing.core.PApplet; -// CONST - - - class Graph { // Reference to PApplet drawing canvas @@ -15,22 +11,24 @@ class Graph float height; float width; - boolean xvy; + boolean xvy; // ( alternative is vs time ) int numVars; int maxPoints; String title; String[] labels; + int[] colors; // TODO: Configurable colors // Data int index; - double[][] data; + double[][][] data; int[] extremesCounter; double[] extremes; // {min_x, max_x, min_y, max_y} + int currPoints; // Contructor public Graph( PApplet parent, float posY, float posX, float height, float width, boolean xvy, int numVars, int maxPoints, - String title, String[] labels ) + String title, String[] labels, int[] colors ) { this.parent = parent; this.posY = posY; @@ -41,15 +39,17 @@ public Graph( PApplet parent, float posY, float posX, float height, float width, this.numVars = numVars; this.maxPoints = maxPoints; this.title = title; - this.labels = labels; + this.labels = labels; + this.colors = colors; this.parent.println( "Constructed new graph: ", this.title, this.posY, " ", this.posX); // Initialize - index = 0; - data = new double[maxPoints][numVars]; - extremesCounter = new int[4]; - extremes = new double[4]; + this.index = 0; + this.data = new double[maxPoints][numVars][2]; + this.extremesCounter = new int[4]; + this.extremes = new double[4]; + this.currPoints = 0; } // Modifiers @@ -76,8 +76,53 @@ public void Reconfigure( int posY, int posX, int height, int width ) this.width = width; } - public void Update( double[] newData ) - {} + public void Update( double[] newData, int time ) + { + // Store data + if ( this.xvy ) + { + // Validate + if ( newData.length != 2 ) + { + this.parent.println( "Invalid data passed to X v. Y graph." ); + return; + } + + this.data[this.index][0][0] = newData[0]; + this.data[this.index][0][1] = newData[1]; + } + else + { + // Validate + if ( newData.length != this.numVars ) + { + this.parent.println( "Invalid data passed to time graph." ); + return; + } + + for ( int i = 0; i < this.numVars; i++ ) + { + this.data[this.index][i][0] = time; + this.data[this.index][i][1] = newData[i]; + } + } + + // Counter for num points defined + if ( this.currPoints < this.maxPoints ) + { + this.currPoints++; + } + + // Check extremes + this.CheckExtremes(); + + // Advance index position and rollback if needed + this.index++; + if ( this.index >= this.maxPoints ) + { + this.index = 0; + } + } public void Plot() { @@ -99,27 +144,198 @@ public void Plot() double yScale = AXIS_COV * this.height / ( this.extremes[3] - this.extremes[2] ); double yOffset = yScale * this.extremes[3] + 0.5 * ( 1.0 - AXIS_COV ) * this.height; - // Draw + // X vs Y and vs Time specific stuff if ( this.xvy ) { - this.DrawDataXY( xScale, yScale, xOffset, yOffset ); + this.DrawXYStuff(); + + // Modify scaling and offset + xScale *= AXIS_COV; + xOffset = xScale * this.extremes[0] - 0.5 * ( 1.0 - AXIS_COV ) * this.width; } else { - this.DrawDataTime( xScale, yScale, xOffset, yOffset ); + this.DrawTimeStuff(); + } + + // Draw Ticks + this.DrawTicks( xScale, xOffset, yScale, yOffset ); + + // Do actual data plotting + for ( int i = 0; i < this.numVars; i++ ) + { + this.parent.stroke( this.colors[i] ); + for ( int j = 0; j < this.currPoints; j++ ) + { + this.parent.point( (float)(this.posX + (this.data[j][i][0]*xScale - xOffset)), + (float)(this.posY + yOffset - data[j][i][1]*yScale) ); + } + } + } + + // Private Helpers + + private void DrawTimeStuff() + { + // Setup legend start + float textPos = this.posY + LABEL_SZ; + this.parent.textAlign( this.parent.RIGHT, this.parent.TOP ); + this.parent.textSize( LABEL_SZ ); + + // Draw each legend entry + for ( int i = 0; i < this.numVars; i++ ) + { + this.parent.fill( this.colors[i] ); + this.parent.text( this.labels[i], this.posX + this.width - 10, textPos); + textPos += ( LABEL_SZ + LABEL_SZ/4 ); + this.parent.stroke( this.colors[i] ); } + + } + + private void DrawXYStuff() + { + // X and Y labels + this.parent.textSize( LABEL_SZ ); + this.parent.textAlign( this.parent.LEFT, this.parent.TOP ); + //text(labels[k+1], pos_graphs[g][0] + 10, pos_graphs[g][1] + 10); + this.parent.textAlign( this.parent.RIGHT, this.parent.BOTTOM ); + //text(labels[k], pos_graphs[g][0] + sub_width - 10, pos_graphs[g][1] + sub_height - 3*NUM_SZ); } - // Internal Helpers - private void DrawDataTime( double xScale, double yScale, double xOffset, double yOffset ) - {} - private void DrawDataXY( double xScale, double yScale, double xOffset, double yOffset ) - {} + private void DrawTicks( double xScale, double xOffset, double yScale, double yOffset ) + { + // Label graph with numbered tick marks + this.parent.stroke( 255 ); + this.parent.fill( 255 ); + this.parent.textSize( NUM_SZ ); + this.parent.textAlign( this.parent.LEFT, this.parent.CENTER ); + // Draw ticks along y-axis + float tempX = this.posX - TICK_LEN / 2; + float tickOffset = 0.5f * ( 1.0f - AXIS_COV ) * this.height; + float tickInterval = AXIS_COV * this.height / (NUM_TICKS - 1); + for ( float tempY = this.posY + tickOffset; tempY <= this.posY + this.height - tickOffset; + tempY += tickInterval ) + { + float val = (float) ( ( (double)tempY - ( yOffset + this.posY ) ) / yScale ); + this.parent.line( tempX, tempY, tempX + TICK_LEN, tempY ); + this.parent.text( Float.toString( val ), tempX + TICK_LEN + 5, tempY ); + } - private void DrawTicks() - {} + // x-axis + this.parent.textAlign( this.parent.CENTER, this.parent.BOTTOM ); + float tempY = this.posY + this.height - TICK_LEN / 2; + tickOffset = 0.5f * ( 1.0f - AXIS_COV ) * this.width; + tickInterval = AXIS_COV * this.width / (NUM_TICKS - 1); + for ( tempX = this.posX + tickOffset; tempX <= this.posX + this.width - tickOffset; + tempX += tickInterval ) + { + float val = (float) ( ( (double)tempX + xOffset - this.posX ) / xScale ); + this.parent.line( tempX, tempY, tempX, tempY + TICK_LEN ); + this.parent.text( Float.toString( val ), tempX, tempY - 5 ); + } + + } + + private void CheckExtremes() + { + // Check new values + this.CompareToExtremes( this.index ); + + // Time extremes + if ( ! this.xvy ) + { + // Get index of oldest data point + int oldest = this.index + 1; + if ( oldest >= this.currPoints ) + { + oldest = 0; + } + + if ( this.currPoints < this.maxPoints ) + { + // Estimate lower extreme + this.extremes[0] = this.data[this.index][0][0] + - ( this.data[this.index][0][0] - this.data[oldest][0][0] ) + * ( (double)this.maxPoints / (double)this.currPoints ); + } + else + { + // Normally just take oldest + this.extremes[0] = this.data[oldest][0][0]; + } + this.extremesCounter[0] = 0; + this.extremes[1] = this.data[this.index][0][0]; + this.extremesCounter[1] = 0; + } + + // Check for extremes going out of scope + boolean recalc = false; + for ( int i = 0; i < 4; i++ ) + { + this.extremesCounter[i]++; + recalc |= this.extremesCounter[i] > this.maxPoints; + } + + if ( ! recalc ) + { + return; + } + + this.parent.println("Recalculating extremes..."); + + // Full re-calculation for new extremes + if ( this.xvy ) + { + this.extremes[0] = this.data[0][0][0]; // (x-min) + this.extremesCounter[0] = 0; + this.extremes[1] = this.data[0][0][0]; // (x-max) + this.extremesCounter[1] = 0; + } + this.extremes[2] = this.data[0][0][1]; // (y-min) + this.extremesCounter[2] = 0; + this.extremes[3] = this.data[0][0][1]; // (y-max) + this.extremesCounter[3] = 0; + + for ( int i = 0; i < this.currPoints; i++ ) + { + this.CompareToExtremes( i ); + } + } + + private void CompareToExtremes( int i ) // i : dataIndex + { + for ( int j = 0; j < this.numVars; j++ ) + { + // Y max/min + if ( this.data[i][j][1] < this.extremes[2] ) // (min) + { + this.extremes[2] = this.data[i][j][1]; + this.extremesCounter[2] = 0; + } + else if ( this.data[i][j][1] > this.extremes[3] ) // (max) + { + this.extremes[3] = this.data[i][j][1]; + this.extremesCounter[3] = 0; + } + // X max/min + if ( this.xvy ) + { + if ( this.data[i][j][0] < this.extremes[0] ) // (min) + { + this.extremes[0] = this.data[i][j][0]; + this.extremesCounter[0] = 0; + } + else if ( this.data[i][j][0] > this.extremes[1] ) // (max) + { + this.extremes[1] = this.data[i][j][0]; + this.extremesCounter[1] = 0; + } + } + } + } // Constants private static final float AXIS_COV = 0.75f; @@ -130,4 +346,5 @@ private void DrawTicks() private static final int TICK_LEN = 6; private static final int NUM_TICKS = 5; private static final float PT_SZ = 1.5f; + } diff --git a/listener/listener.pde b/listener/listener.pde index fd333e6..c1033d5 100644 --- a/listener/listener.pde +++ b/listener/listener.pde @@ -302,9 +302,15 @@ void serialEvent(Serial ser) { p += 2; k++; } + + if ( xvyTemp ) + { + numVars = 1; + } + // Create new Graph - Graph temp = new Graph(this, posGraphs[i][0], posGraphs[i][1], 100, 100, - xvyTemp, numVars, maxPoints, title, labelsTemp); + Graph temp = new Graph(this, posGraphs[i][0], posGraphs[i][1], 300, 300, + xvyTemp, numVars, maxPoints, title, labelsTemp, COLORS); graphs.add( temp ); } println("Added ", graphs.size() ); @@ -324,8 +330,21 @@ void serialEvent(Serial ser) { int temp_time = millis(); for (int i = 0; i < num_graphs; i++) { - String[] array_sub = arrayMain[i+1].split(INNER_KEY); + String[] arraySub = arrayMain[i+1].split( INNER_KEY ); + String[] array_sub = arraySub; + + double[] tempData = new double[ (arraySub.length - 5) / 2 ]; + + // Update graph objects with new data + int q = 0; + for ( int j = 5; j < arraySub.length; j += 2 ) + { + tempData[q] = Double.parseDouble( arraySub[j] ); + q++; + } + graphs.get( i ).Update( tempData, temp_time ); + if (xvy[i]) { // Plot x vs y graph int p = 5; // first index of double in split array From 679c6c898a1854b1db4fd4d2ef1369d228d76543 Mon Sep 17 00:00:00 2001 From: Devin Conley Date: Wed, 18 Jan 2017 14:45:08 -0500 Subject: [PATCH 05/16] Stripped out all old code. Caught a few bugs in Graph class. Added resizing to graph --- listener/Graph.java | 12 +- listener/listener.pde | 442 +++++++----------------------------------- 2 files changed, 78 insertions(+), 376 deletions(-) diff --git a/listener/Graph.java b/listener/Graph.java index bec3fad..c7e1d50 100644 --- a/listener/Graph.java +++ b/listener/Graph.java @@ -68,7 +68,7 @@ public void Reconfigure( float posY, float posX, float height, float width, this.labels = labels; } - public void Reconfigure( int posY, int posX, int height, int width ) + public void Reconfigure( float posY, float posX, float height, float width ) { this.posY = posY; this.posX = posX; @@ -129,13 +129,14 @@ public void Plot() // Plot Background this.parent.fill( PLOT_COL ); this.parent.stroke( 255 ); + this.parent.strokeWeight( PT_SZ ); this.parent.rect( this.posX, this.posY, this.width, this.height ); // Title this.parent.textSize( TITLE_SZ ); this.parent.fill( 255 ); this.parent.textAlign( this.parent.CENTER, this.parent.TOP ); - this.parent.text( this.title, this.posX + this.height/2, this.posY + TITLE_SZ); + this.parent.text( this.title, this.posX + this.width / 2, this.posY + TITLE_SZ); // Calculations for offset and scaling of graph ( vs. time ) @@ -198,9 +199,10 @@ private void DrawXYStuff() // X and Y labels this.parent.textSize( LABEL_SZ ); this.parent.textAlign( this.parent.LEFT, this.parent.TOP ); - //text(labels[k+1], pos_graphs[g][0] + 10, pos_graphs[g][1] + 10); + this.parent.text( this.labels[1], this.posY + 10, this.posY + 10); + this.parent.textAlign( this.parent.RIGHT, this.parent.BOTTOM ); - //text(labels[k], pos_graphs[g][0] + sub_width - 10, pos_graphs[g][1] + sub_height - 3*NUM_SZ); + this.parent.text( this.labels[0], this.posX + this.width - 10, this.posY + this.height - 3*NUM_SZ); } @@ -219,7 +221,7 @@ private void DrawTicks( double xScale, double xOffset, double yScale, double yOf for ( float tempY = this.posY + tickOffset; tempY <= this.posY + this.height - tickOffset; tempY += tickInterval ) { - float val = (float) ( ( (double)tempY - ( yOffset + this.posY ) ) / yScale ); + float val = (float) ( ( ( yOffset + this.posY ) - (double)tempY ) / yScale ); this.parent.line( tempX, tempY, tempX + TICK_LEN, tempY ); this.parent.text( Float.toString( val ), tempX + TICK_LEN + 5, tempY ); } diff --git a/listener/listener.pde b/listener/listener.pde index c1033d5..5e2a8c8 100644 --- a/listener/listener.pde +++ b/listener/listener.pde @@ -29,278 +29,107 @@ Serial port; final int[] COLORS = {#00FF00, #FF0000,#0000FF, #FEFF00, #FF9900, #FF00FF}; //int color codes final char OUTER_KEY = '#'; final String INNER_KEY = "@"; -final float AXIS_COVERAGE = 0.75; -final int LABEL_SZ = 14; // text sizes -final int TITLE_SZ = 16; -final int NUM_SZ = 10; final int MARGIN_SZ = 20; // between plots final int BG_COL = 75; // -final int PLOT_COL = 115; -final int TICK_LEN = 6; -final int NUM_TICKS = 5; -final float PT_SZ = 1.5; // Setup and config Globals int h; int w; -float sub_height; -float sub_width; -int num_graphs; -int total_vars; -int max_points; -String config_code = "This will not be matched!"; +int numGraphs; +String configCode = "This will not be matched!"; boolean configured = false; -int last_config; +int lastConfig; ArrayList graphs; -// Graph-specific setup globals -float[][] pos_graphs; // stored as {x, y} -String[] titles; -boolean[] xvy; -int[] first_index_graphs; -int[] sz_graphs; // num of values tracked in each graph -int[] num_points; -double[][] extremes_graphs; // {min_x, max_x, min_y, max_y} -int[][] extremes_graphs_counter; // tracker for values since last set -int[] pos_x; - -// Variable-specific Globals -double[][][] data; -String[] labels; - - -void setup() { - size(800, 800); +void setup() +{ + size( 800, 800 ); surface.setResizable(true); h = height; w = width; String portID = Serial.list()[0]; - port = new Serial(this, portID, 115200); - port.bufferUntil('#'); - frameRate(100); - textSize(16); - background(BG_COL); - strokeWeight(PT_SZ); + // Add handshake here + port = new Serial( this, portID, 115200 ); + port.bufferUntil( OUTER_KEY ); + frameRate( 100 ); + textSize( 16 ); + background( BG_COL ); } -void draw() { +void draw() +{ //PLOT ALL - try { - if (configured) { - background(BG_COL); - for (int i = 0; i < num_graphs; i++) { - if (xvy[i]) { - plot_xy(i); - } else{ - plot_time(i); - } - } + try + { + if ( configured ) + { + background( BG_COL ); + for( int i = 0; i < graphs.size(); i++ ) { graphs.get(i).Plot(); } } - if ( h != height || w != width) { + // Resize if needed + if ( h != height || w != width) + { h = height; w = width; - setupGraphPosition( num_graphs ); - } - } catch (Exception e) {} -} - -void plot_xy(int graph_index) { - int g = graph_index; - int k = first_index_graphs[g]; - - // Calculations for offset and scaling of graph - double x_scale = AXIS_COVERAGE * sub_width / (extremes_graphs[g][1] - extremes_graphs[g][0]); - double x_offset = x_scale*extremes_graphs[g][0] - 0.5*(1.0 - AXIS_COVERAGE)*sub_width; - double y_scale = AXIS_COVERAGE * sub_height / (extremes_graphs[g][3] - extremes_graphs[g][2]); - double y_offset = y_scale*extremes_graphs[g][3] + 0.5*(1.0 - AXIS_COVERAGE)*sub_height; - - // Plot Background - fill(PLOT_COL); - stroke(255); - rect(pos_graphs[g][0],pos_graphs[g][1],sub_width,sub_height); - // Title - textSize(TITLE_SZ); - fill(255); - textAlign(CENTER, TOP); - text(titles[g], pos_graphs[g][0] + sub_width/2, pos_graphs[g][1] + TITLE_SZ); - // X and Y labels - textSize(LABEL_SZ); - textAlign(LEFT, TOP); - text(labels[k+1], pos_graphs[g][0] + 10, pos_graphs[g][1] + 10); - textAlign(RIGHT, BOTTOM); - text(labels[k], pos_graphs[g][0] + sub_width - 10, pos_graphs[g][1] + sub_height - 3*NUM_SZ); - drawTicks(g); - - // ** add support for multiple paths in x-y here ** - stroke(COLORS[0]); - for (int j = 0; j < num_points[g]; j++) { - point( (float)(pos_graphs[g][0] + (data[j][k][1]*x_scale - x_offset)), - (float)(pos_graphs[g][1] + y_offset - data[j][k+1][1]*y_scale) ); - } - -} - -void plot_time(int graph_index) { - int g = graph_index; - int k = first_index_graphs[g]; - - // Calculations for offset and scaling of graph - double x_scale = sub_width / (extremes_graphs[g][1] - extremes_graphs[g][0]); - double x_offset = x_scale*extremes_graphs[g][0]; - double y_scale = AXIS_COVERAGE*sub_height / (extremes_graphs[g][3] - extremes_graphs[g][2]); - double y_offset = y_scale*extremes_graphs[g][3] + 0.5*(1.0 - AXIS_COVERAGE)*sub_height; - - // Plot Background - fill(PLOT_COL); - stroke(255); - rect(pos_graphs[g][0],pos_graphs[g][1],sub_width,sub_height); - // Title - textSize(TITLE_SZ); - fill(255); - textAlign(CENTER, TOP); - text(titles[g], pos_graphs[g][0] + sub_width/2, pos_graphs[g][1] + TITLE_SZ); - - // Plot legend - float textPos = pos_graphs[g][1] + LABEL_SZ; - textAlign(RIGHT, TOP); - textSize(LABEL_SZ); - // Plot each line - for (int i = 0; i < sz_graphs[g]; i++) { - fill(COLORS[i]); - text(labels[k + i],pos_graphs[g][0] + sub_width - 10,textPos); - textPos += (LABEL_SZ + 3); - stroke(COLORS[i]); - - for (int j = 0; j < num_points[g]; j++) { - point( (float)(pos_graphs[g][0] + (data[j][k+i][0]*x_scale - x_offset)), - (float)(pos_graphs[g][1] + y_offset - data[j][k+i][1]*y_scale) ); - + float[][] posGraphs = setupGraphPosition( numGraphs ); + for ( int i = 0; i < numGraphs; i++ ) + { + graphs.get(i).Reconfigure( posGraphs[i][0], posGraphs[i][1], posGraphs[i][2], posGraphs[i][3] ); + } } - } - // Draw axis - noFill(); - stroke(255); - rect(pos_graphs[g][0],pos_graphs[g][1],sub_width,sub_height); - drawTicks(g); // draw ticks over any data (only an issue with time plot) + catch ( Exception e ) + {} } -void drawTicks(int g) { - // Label graph with numbered tick marks - stroke(255); - fill(255); - textSize(NUM_SZ); - textAlign(LEFT, CENTER); - // Draw ticks along y-axis - float temp_x = pos_graphs[g][0] - TICK_LEN/2; - float tick_offset = 0.5*(1.0 - AXIS_COVERAGE)*sub_height; - float tick_interval = AXIS_COVERAGE * sub_height / (NUM_TICKS - 1); - float val = (float)extremes_graphs[g][3]; - float val_interval = (float)(extremes_graphs[g][3] - extremes_graphs[g][2]) / (NUM_TICKS - 1); - for (float temp_y = pos_graphs[g][1] + tick_offset; - temp_y <= pos_graphs[g][1] + sub_height - tick_offset; temp_y += tick_interval) { - line(temp_x, temp_y, temp_x + TICK_LEN, temp_y); - text(Float.toString(val), temp_x + TICK_LEN + 5, temp_y); - val -= val_interval; - } - // Draw along x-axis (will be diff for each type of graph) - float temp_y = pos_graphs[g][1] + sub_height - TICK_LEN/2; - // if XvY graph, evenly spaced ticks within coverage - if (xvy[g]) { - val = (float)extremes_graphs[g][0]; - val_interval = (float)(extremes_graphs[g][1] - extremes_graphs[g][0]) / (NUM_TICKS - 1); - tick_offset = 0.5*(1.0 - AXIS_COVERAGE)*sub_width; - tick_interval = AXIS_COVERAGE * sub_width / (NUM_TICKS - 1); - // if a time graph, evenly spaced ticks across all - } else { - val_interval = (float)(extremes_graphs[g][1] - extremes_graphs[g][0]) / (NUM_TICKS + 1); - val = (float)extremes_graphs[g][0] + val_interval; - tick_offset = sub_width / (NUM_TICKS + 1); - tick_interval = tick_offset; - } - textAlign(CENTER, BOTTOM); - for (temp_x = pos_graphs[g][0] + tick_offset; - temp_x <= pos_graphs[g][0] + sub_width - tick_offset; - temp_x += tick_interval) { - line(temp_x, temp_y, temp_x, temp_y + TICK_LEN); - text(Float.toString(val), temp_x, temp_y - 5); - val += val_interval; - } -} - -void serialEvent(Serial ser) { +void serialEvent( Serial ser ) +{ // Listen for serial data until #, the end of transmission key - try { - String message = ser.readStringUntil(OUTER_KEY); - String[] arrayMain = message.split("\n"); + try + { + String message = ser.readStringUntil( OUTER_KEY ); + String[] arrayMain = message.split( "\n" ); // ********************************************************* // // ************* PLOT SETUP FROM CONFIG CODE *************** // // ********************************************************* // // If config code has changed, need to go through setup again - if (!config_code.equals(arrayMain[0])) { - String[] arraySub = arrayMain[0].split(INNER_KEY); + if ( !configCode.equals( arrayMain[0] ) ) + { + String[] arraySub = arrayMain[0].split( INNER_KEY ); // Check for size of full transmission against expected to flag bad transmission - num_graphs = Integer.parseInt(arraySub[0]); - if (arrayMain.length != num_graphs+1) { + numGraphs = Integer.parseInt( arraySub[0] ); + if ( arrayMain.length != numGraphs + 1 ) + { throw new Exception(); } configured = false; //print("New config"); - - - - // Pull more values and reset datastore arrays as appropriate - total_vars = Integer.parseInt(arraySub[1]); - max_points = Integer.parseInt(arraySub[2]); - labels = new String[total_vars]; - titles = new String[num_graphs]; - xvy = new boolean[num_graphs]; - sz_graphs = new int[num_graphs]; - extremes_graphs = new double[num_graphs][4]; - extremes_graphs_counter = new int[num_graphs][4]; - first_index_graphs = new int[num_graphs]; - data = new double[max_points][total_vars][2]; - - pos_x = new int[max_points]; - num_points = new int[num_graphs]; - + // Setup new layout - float[][] posGraphs = setupGraphPosition( num_graphs ); - + float[][] posGraphs = setupGraphPosition( numGraphs ); graphs = new ArrayList(); // Iterate through the individual graph data blocks to get graph specific info - int k = 0; // k tracks overall variable index - for (int i = 0; i < num_graphs; i++) { - arraySub = arrayMain[i+1].split(INNER_KEY); + for ( int i = 0; i < numGraphs; i++ ) + { + arraySub = arrayMain[i+1].split( INNER_KEY ); String title = arraySub[0]; - boolean xvyTemp = Integer.parseInt(arraySub[1]) == 1; - int maxPoints = Integer.parseInt(arraySub[2]); - int numVars = Integer.parseInt(arraySub[3]); + boolean xvyTemp = Integer.parseInt( arraySub[1] ) == 1; + int maxPoints = Integer.parseInt( arraySub[2] ); + int numVars = Integer.parseInt( arraySub[3] ); String[] labelsTemp = new String[numVars]; - - titles[i] = title; - xvy[i] = xvyTemp; - num_points[i] = maxPoints; - sz_graphs[i] = numVars; - first_index_graphs[i] = k; - int p = 4; // first label of this graph falls at index 4 - - for (int j = 0; j < numVars; j++) + for ( int j = 0; j < numVars; j++ ) { labelsTemp[j] = arraySub[4 + 2*j]; - labels[k] = arraySub[p]; - p += 2; - k++; } if ( xvyTemp ) @@ -309,31 +138,31 @@ void serialEvent(Serial ser) { } // Create new Graph - Graph temp = new Graph(this, posGraphs[i][0], posGraphs[i][1], 300, 300, + Graph temp = new Graph(this, posGraphs[i][0], posGraphs[i][1], posGraphs[i][2], posGraphs[i][3], xvyTemp, numVars, maxPoints, title, labelsTemp, COLORS); graphs.add( temp ); } println("Added ", graphs.size() ); // Set new config code - config_code = arrayMain[0]; + configCode = arrayMain[0]; //println(config_code); - last_config = millis(); - } else { + lastConfig = millis(); + } + else + { // Matching a code means we have configured correctly configured = true; - - + // *********************************************************** // // ************ NORMAL PLOTTING FUNCTIONALITY **************** // // *********************************************************** // - int temp_time = millis(); + int tempTime = millis(); - for (int i = 0; i < num_graphs; i++) { + for ( int i = 0; i < numGraphs; i++ ) + { String[] arraySub = arrayMain[i+1].split( INNER_KEY ); - String[] array_sub = arraySub; - double[] tempData = new double[ (arraySub.length - 5) / 2 ]; // Update graph objects with new data @@ -343,128 +172,7 @@ void serialEvent(Serial ser) { tempData[q] = Double.parseDouble( arraySub[j] ); q++; } - graphs.get( i ).Update( tempData, temp_time ); - - if (xvy[i]) { - // Plot x vs y graph - int p = 5; // first index of double in split array - - // j is only a counter for var in graph context - for (int j = first_index_graphs[i]; j < first_index_graphs[i] + sz_graphs[i]; j++) { - data[pos_x[i]][j][1] = Double.parseDouble(array_sub[p]); - - // Check for new extremes ("p-5, "p-4" is just to get index at x:0,1 then y:2,3) - if (data[pos_x[i]][j][1] < extremes_graphs[i][p-5]) { - extremes_graphs[i][p-5] = data[pos_x[i]][j][1]; - extremes_graphs_counter[i][p-5] = 0; - } else if (data[pos_x[i]][j][1] > extremes_graphs[i][p-4]) { - extremes_graphs[i][p-4] = data[pos_x[i]][j][1]; - extremes_graphs_counter[i][p-4] = 0; - } - - p += 2; - } - - // Check for extremes going out of scope, to need a full new max/min calc - boolean[] needs_calc = {false, false, false, false}; - for (int j = 0; j < 4; j++) { - if (extremes_graphs_counter[i][j] > num_points[i]) { - needs_calc[j] = true; - } else { - extremes_graphs_counter[i][j]++; - } - } - if (needs_calc[0] || needs_calc[1] || needs_calc[2] || needs_calc[3]) { - int j = first_index_graphs[i]; - for (int k = 0; k < num_points[i]; k++) { - // x-direction - if (needs_calc[0] && data[k][j][1] < extremes_graphs[i][0]) { - extremes_graphs[i][0] = data[k][j][1]; - extremes_graphs_counter[i][0] = 0; - } else if (needs_calc[1] && data[k][j][1] > extremes_graphs[i][1]) { - extremes_graphs[i][1] = data[k][j][1]; - extremes_graphs_counter[i][1] = 0; - } - // y-direction - if (needs_calc[2] && data[k][j+1][1] < extremes_graphs[i][2]) { - extremes_graphs[i][2] = data[k][j+1][1]; - extremes_graphs_counter[i][2] = 0; - } else if (needs_calc[3] && data[k][j+1][1] > extremes_graphs[i][3]) { - extremes_graphs[i][3] = data[k][j+1][1]; - extremes_graphs_counter[i][3] = 0; - } - } - } - - // Advance pos_x and rollback pos_x if exceeds max points for specific graph - pos_x[i]++; - if (pos_x[i] >= num_points[i]) { - pos_x[i] = 0; - } - - } else { - // TIME GRAPH HANDLER - - int p = 5; // first index of double in split array - for (int j = first_index_graphs[i]; j < first_index_graphs[i] + sz_graphs[i]; j++) { - data[pos_x[i]][j][0] = temp_time; - data[pos_x[i]][j][1] = Double.parseDouble(array_sub[p]); - p += 2; - - // Check for new extremes - if (data[pos_x[i]][j][1] <= extremes_graphs[i][2]) { - extremes_graphs[i][2] = data[pos_x[i]][j][1]; - extremes_graphs_counter[i][2] = 0; - } else if (data[pos_x[i]][j][1] >= extremes_graphs[i][3]) { - extremes_graphs[i][3] = data[pos_x[i]][j][1]; - - extremes_graphs_counter[i][3] = 0; - } - - } - - // Check for extremes going out of scope, to need a full new max/min calc - boolean[] needs_calc = {false, false, false, false}; - for (int j = 2; j < 4; j++) { - if (extremes_graphs_counter[i][j] > num_points[i]) { - needs_calc[j] = true; - } else { - extremes_graphs_counter[i][j]++; - } - } - if (needs_calc[2] || needs_calc[3]) { - for (int j = first_index_graphs[i]; j < first_index_graphs[i] + sz_graphs[i]; j++) { - for (int k = 0; k < num_points[i]; k++) { - if (needs_calc[2] && data[k][j][1] < extremes_graphs[i][2]) { - extremes_graphs[i][2] = data[k][j][1]; - extremes_graphs_counter[i][2] = 0; - } else if (needs_calc[3] && data[k][j][1] > extremes_graphs[i][3]) { - extremes_graphs[i][3] = data[k][j][1]; - extremes_graphs_counter[i][3] = 0; - } - } - } - } - - // Max timestamp of graph will be now - extremes_graphs[i][1] = temp_time; - - // Advance pos_x and rollback pos_x if exceeds max points for specific graph - pos_x[i]++; - if (pos_x[i] >= num_points[i]) { - pos_x[i] = 0; - } - - // Min timestamp will be whatever this new pos_x has (about to be replaced) - if (data[pos_x[i]][first_index_graphs[i]][0] != 0) { - extremes_graphs[i][0] = data[pos_x[i]][first_index_graphs[i]][0]; - } else { - // But if hasn't fully filled array, need to estimate - extremes_graphs[i][0] = temp_time - - ((temp_time - data[0][first_index_graphs[i]][0]) / pos_x[i])*num_points[i]; - } - - } + graphs.get( i ).Update( tempData, tempTime ); } } } @@ -474,7 +182,8 @@ void serialEvent(Serial ser) { } // Helper method to calculate bounds of graphs -float[][] setupGraphPosition( int numGraphs ) { +float[][] setupGraphPosition( int numGraphs ) +{ // Determine orientation of each graph int numHigh = 1; int numWide = 1; @@ -500,35 +209,26 @@ float[][] setupGraphPosition( int numGraphs ) { } } - float[][] posGraphs = new float[numGraphs][2]; + float[][] posGraphs = new float[numGraphs][4]; float subHeight = round( h / numHigh ); float subWidth = round( w / numWide ); // Set bounding box for each subsection - pos_graphs = new float[num_graphs][2]; - - sub_width = subWidth; - sub_height = subHeight; - - for(int i = 0; i < numHigh; i++) { - for (int j = 0; j < numWide; j++) { + for(int i = 0; i < numHigh; i++) + { + for (int j = 0; j < numWide; j++) + { int k = i * numWide + j; if ( k < numGraphs ) { posGraphs[k][0] = i*subHeight + MARGIN_SZ / 2; posGraphs[k][1] = j*subWidth + MARGIN_SZ / 2; + posGraphs[k][2] = subHeight - MARGIN_SZ; + posGraphs[k][3] = subWidth - MARGIN_SZ; } - - if (k < num_graphs) { - pos_graphs[k][0] = j*subWidth + MARGIN_SZ/2; - pos_graphs[k][1] = i*subHeight + MARGIN_SZ/2; - } - k++; } } - sub_width -= MARGIN_SZ; - sub_height -= MARGIN_SZ; return posGraphs; } \ No newline at end of file From 4fb987a5a16025e4d4c6f37b87f7f7e2b7c762e2 Mon Sep 17 00:00:00 2001 From: Devin Conley Date: Wed, 18 Jan 2017 15:29:24 -0500 Subject: [PATCH 06/16] Scan all serial ports when trouble configuring --- listener/listener.pde | 59 +++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/listener/listener.pde b/listener/listener.pde index 5e2a8c8..5db729c 100644 --- a/listener/listener.pde +++ b/listener/listener.pde @@ -23,14 +23,15 @@ */ import processing.serial.*; -Serial port; //CONSTANTS -final int[] COLORS = {#00FF00, #FF0000,#0000FF, #FEFF00, #FF9900, #FF00FF}; //int color codes +final int[] COLORS = {#00FF00, #FF0000, #0000FF, #FEFF00, #FF9900, #FF00FF}; //int color codes final char OUTER_KEY = '#'; final String INNER_KEY = "@"; final int MARGIN_SZ = 20; // between plots -final int BG_COL = 75; // +final int BG_COL = 75; // background +final int PORT_INTERVAL = 5000; // time to sit on each port +final int BAUD_RATE = 115200; // Setup and config Globals int h; @@ -39,22 +40,24 @@ int numGraphs; String configCode = "This will not be matched!"; boolean configured = false; int lastConfig; - +int lastPortSwitch; +int portIndex; +Serial port; ArrayList graphs; void setup() { + // Canvas size( 800, 800 ); - surface.setResizable(true); + surface.setResizable( true ); h = height; w = width; - String portID = Serial.list()[0]; - // Add handshake here - port = new Serial( this, portID, 115200 ); - port.bufferUntil( OUTER_KEY ); frameRate( 100 ); - textSize( 16 ); - background( BG_COL ); + + // Serial comms + portIndex = 0; + lastPortSwitch = millis(); + attemptConnect( portIndex ); } void draw() @@ -62,15 +65,29 @@ void draw() //PLOT ALL try { + background( BG_COL ); + if ( configured ) - { - background( BG_COL ); - + { for( int i = 0; i < graphs.size(); i++ ) { graphs.get(i).Plot(); } } + else + { + text( "Scanning serial ports... (Port " + portIndex + ")", 20, 20 ); + // Continue to scan ports if not configuring + if ( millis() - lastPortSwitch > PORT_INTERVAL ) + { // Go to next port + portIndex++; + if ( portIndex >= Serial.list().length ) + { + portIndex = 0; + } + attemptConnect( portIndex ); + } + } // Resize if needed if ( h != height || w != width) { @@ -231,4 +248,18 @@ float[][] setupGraphPosition( int numGraphs ) } return posGraphs; +} + +void attemptConnect( int index ) +{ + // Attempt connect on specified serial port + try + { + // Configure + port = new Serial( this, Serial.list()[portIndex], BAUD_RATE ); + port.bufferUntil( OUTER_KEY ); + lastPortSwitch = millis(); // at end so that we try again immediately on invalid port + } + catch ( Exception e ) + {} } \ No newline at end of file From 0efa0cf6ae01f1c09d9ebe76d5838cfabebebd62 Mon Sep 17 00:00:00 2001 From: Devin Conley Date: Thu, 19 Jan 2017 16:48:44 -0500 Subject: [PATCH 07/16] Capitalized two functions I missed before --- plotter/Plotter.cpp | 2 +- plotter/Plotter.h | 50 ++++++++++++++++++++++----------------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/plotter/Plotter.cpp b/plotter/Plotter.cpp index bb857a7..98ac896 100644 --- a/plotter/Plotter.cpp +++ b/plotter/Plotter.cpp @@ -73,7 +73,7 @@ void Plotter::AddGraphHelper( String title, VariableWrapper * wrappers, int sz, lastUpdated = millis(); } -bool Plotter::remove(int index) +bool Plotter::Remove(int index) { if ( numGraphs == 0 || index < 0 || numGraphs <= index ) { diff --git a/plotter/Plotter.h b/plotter/Plotter.h index 01b8ce4..c100dff 100644 --- a/plotter/Plotter.h +++ b/plotter/Plotter.h @@ -48,7 +48,7 @@ class Plotter String labelA, A & refA ) { VariableWrapper * wrappers = new VariableWrapper[1]; - wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &dereference ); + wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &Dereference ); AddGraphHelper( title, wrappers, 1, false, pointsDisplayed ); } @@ -68,8 +68,8 @@ class Plotter String labelX, X & refX, String labelY, Y & refY ) { VariableWrapper * wrappers = new VariableWrapper[2]; - wrappers[0] = VariableWrapper( labelX, static_cast( &refX ), &dereference ); - wrappers[1] = VariableWrapper( labelY, static_cast( &refY ), &dereference ); + wrappers[0] = VariableWrapper( labelX, static_cast( &refX ), &Dereference ); + wrappers[1] = VariableWrapper( labelY, static_cast( &refY ), &Dereference ); AddGraphHelper( title, wrappers, 2, true, pointsDisplayed ); } @@ -91,7 +91,7 @@ class Plotter Returns: - true, if successful */ - bool remove( int index ); + bool Remove( int index ); // Add a 2-variable graph vs. time template @@ -99,8 +99,8 @@ class Plotter String labelA, A & refA, String labelB, B & refB ) { VariableWrapper * wrappers = new VariableWrapper[2]; - wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &dereference ); - wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &dereference ); + wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &Dereference ); + wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &Dereference ); AddGraphHelper( title, wrappers, 2, false, pointsDisplayed ); } @@ -110,9 +110,9 @@ class Plotter String labelA, A & refA, String labelB, B & refB, String labelC, C & refC ) { VariableWrapper * wrappers = new VariableWrapper[3]; - wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &dereference ); - wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &dereference ); - wrappers[2] = VariableWrapper( labelC, static_cast( &refC ), &dereference ); + wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &Dereference ); + wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &Dereference ); + wrappers[2] = VariableWrapper( labelC, static_cast( &refC ), &Dereference ); AddGraphHelper( title, wrappers, 3, false, pointsDisplayed ); } @@ -123,10 +123,10 @@ class Plotter String labelD, D & refD ) { VariableWrapper * wrappers = new VariableWrapper[4]; - wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &dereference ); - wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &dereference ); - wrappers[2] = VariableWrapper( labelC, static_cast( &refC ), &dereference ); - wrappers[3] = VariableWrapper( labelD, static_cast( &refD ), &dereference ); + wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &Dereference ); + wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &Dereference ); + wrappers[2] = VariableWrapper( labelC, static_cast( &refC ), &Dereference ); + wrappers[3] = VariableWrapper( labelD, static_cast( &refD ), &Dereference ); AddGraphHelper( title, wrappers, 4, false, pointsDisplayed ); } @@ -137,11 +137,11 @@ class Plotter String labelD, D & refD, String labelE, E & refE ) { VariableWrapper * wrappers = new VariableWrapper[5]; - wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &dereference ); - wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &dereference ); - wrappers[2] = VariableWrapper( labelC, static_cast( &refC ), &dereference ); - wrappers[3] = VariableWrapper( labelD, static_cast( &refD ), &dereference ); - wrappers[4] = VariableWrapper( labelE, static_cast( &refE ), &dereference ); + wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &Dereference ); + wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &Dereference ); + wrappers[2] = VariableWrapper( labelC, static_cast( &refC ), &Dereference ); + wrappers[3] = VariableWrapper( labelD, static_cast( &refD ), &Dereference ); + wrappers[4] = VariableWrapper( labelE, static_cast( &refE ), &Dereference ); AddGraphHelper( title, wrappers, 5, false, pointsDisplayed ); } @@ -152,12 +152,12 @@ class Plotter String labelD, D & refD, String labelE, E & refE, String labelF, F & refF ) { VariableWrapper * wrappers = new VariableWrapper[6]; - wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &dereference ); - wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &dereference ); - wrappers[2] = VariableWrapper( labelC, static_cast( &refC ), &dereference ); - wrappers[3] = VariableWrapper( labelD, static_cast( &refD ), &dereference ); - wrappers[4] = VariableWrapper( labelE, static_cast( &refE ), &dereference ); - wrappers[5] = VariableWrapper( labelF, static_cast( &refF ), &dereference ); + wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &Dereference ); + wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &Dereference ); + wrappers[2] = VariableWrapper( labelC, static_cast( &refC ), &Dereference ); + wrappers[3] = VariableWrapper( labelD, static_cast( &refD ), &Dereference ); + wrappers[4] = VariableWrapper( labelE, static_cast( &refE ), &Dereference ); + wrappers[5] = VariableWrapper( labelF, static_cast( &refF ), &Dereference ); AddGraphHelper( title, wrappers, 6, false, pointsDisplayed ); } @@ -210,7 +210,7 @@ class Plotter void AddGraphHelper(String title, VariableWrapper * wrappers, int sz, bool xvy, int pointsDisplayed); template - static double dereference( void * ref ) + static double Dereference( void * ref ) { return static_cast( (* static_cast( ref ) ) ); } From af4ca85b3a66479aef08e2efc8a3fbc3905dddd7 Mon Sep 17 00:00:00 2001 From: Devin Conley Date: Thu, 19 Jan 2017 19:43:27 -0500 Subject: [PATCH 08/16] Added functionality and exposed methods for configuring colorson each variable --- listener/Graph.java | 8 +- listener/listener.pde | 32 +++++-- plotter/Plotter.cpp | 99 +++++++++++++++++++++- plotter/Plotter.h | 83 ++++++++++++------ plotter/examples/set_colors/set_colors.ino | 36 ++++++++ plotter/keywords.txt | 1 + 6 files changed, 217 insertions(+), 42 deletions(-) create mode 100644 plotter/examples/set_colors/set_colors.ino diff --git a/listener/Graph.java b/listener/Graph.java index c7e1d50..393c650 100644 --- a/listener/Graph.java +++ b/listener/Graph.java @@ -41,9 +41,9 @@ public Graph( PApplet parent, float posY, float posX, float height, float width, this.title = title; this.labels = labels; this.colors = colors; - - this.parent.println( "Constructed new graph: ", this.title, this.posY, " ", this.posX); - + + // this.parent.println( "Constructed new graph: ", this.title, " at ", this.posY, " ", this.posX ); + // Initialize this.index = 0; this.data = new double[maxPoints][numVars][2]; @@ -199,7 +199,7 @@ private void DrawXYStuff() // X and Y labels this.parent.textSize( LABEL_SZ ); this.parent.textAlign( this.parent.LEFT, this.parent.TOP ); - this.parent.text( this.labels[1], this.posY + 10, this.posY + 10); + this.parent.text( this.labels[1], this.posX + 10, this.posY + 10); this.parent.textAlign( this.parent.RIGHT, this.parent.BOTTOM ); this.parent.text( this.labels[0], this.posX + this.width - 10, this.posY + this.height - 3*NUM_SZ); diff --git a/listener/listener.pde b/listener/listener.pde index 5db729c..10b8612 100644 --- a/listener/listener.pde +++ b/listener/listener.pde @@ -23,15 +23,28 @@ */ import processing.serial.*; +import java.util.Map; //CONSTANTS -final int[] COLORS = {#00FF00, #FF0000, #0000FF, #FEFF00, #FF9900, #FF00FF}; //int color codes final char OUTER_KEY = '#'; final String INNER_KEY = "@"; final int MARGIN_SZ = 20; // between plots final int BG_COL = 75; // background final int PORT_INTERVAL = 5000; // time to sit on each port final int BAUD_RATE = 115200; +final HashMap COLORMAP = new HashMap() +{ + { + put( "red", color( 255, 0, 0 ) ); + put( "green", color( 0, 255, 0 ) ); + put( "blue", color( 0, 0, 255 ) ); + put( "orange", color( 255, 153, 51 ) ); + put( "yellow", color( 255, 255, 0 ) ); + put( "pink", color( 255, 51, 204 ) ); + put( "purple", color( 172, 0, 230 ) ); + put( "cyan", color( 0, 255, 255 ) ); + } +}; // Setup and config Globals int h; @@ -143,10 +156,17 @@ void serialEvent( Serial ser ) int maxPoints = Integer.parseInt( arraySub[2] ); int numVars = Integer.parseInt( arraySub[3] ); String[] labelsTemp = new String[numVars]; + int[] colorsTemp = new int[numVars]; for ( int j = 0; j < numVars; j++ ) { - labelsTemp[j] = arraySub[4 + 2*j]; + labelsTemp[j] = arraySub[4 + 3*j]; + colorsTemp[j] = COLORMAP.get( arraySub[5 + 3*j] ); + if ( colorsTemp[j] == 0 ) + { + colorsTemp[j] = COLORMAP.get( "green" ); + } + println( colorsTemp[j] ); } if ( xvyTemp ) @@ -155,8 +175,8 @@ void serialEvent( Serial ser ) } // Create new Graph - Graph temp = new Graph(this, posGraphs[i][0], posGraphs[i][1], posGraphs[i][2], posGraphs[i][3], - xvyTemp, numVars, maxPoints, title, labelsTemp, COLORS); + Graph temp = new Graph( this, posGraphs[i][0], posGraphs[i][1], posGraphs[i][2], posGraphs[i][3], + xvyTemp, numVars, maxPoints, title, labelsTemp, colorsTemp ); graphs.add( temp ); } println("Added ", graphs.size() ); @@ -180,11 +200,11 @@ void serialEvent( Serial ser ) { String[] arraySub = arrayMain[i+1].split( INNER_KEY ); - double[] tempData = new double[ (arraySub.length - 5) / 2 ]; + double[] tempData = new double[ (arraySub.length - 5) / 3 ]; // Update graph objects with new data int q = 0; - for ( int j = 5; j < arraySub.length; j += 2 ) + for ( int j = 6; j < arraySub.length; j += 3 ) { tempData[q] = Double.parseDouble( arraySub[j] ); q++; diff --git a/plotter/Plotter.cpp b/plotter/Plotter.cpp index 98ac896..fae613c 100644 --- a/plotter/Plotter.cpp +++ b/plotter/Plotter.cpp @@ -73,7 +73,7 @@ void Plotter::AddGraphHelper( String title, VariableWrapper * wrappers, int sz, lastUpdated = millis(); } -bool Plotter::Remove(int index) +bool Plotter::Remove( int index ) { if ( numGraphs == 0 || index < 0 || numGraphs <= index ) { @@ -105,6 +105,64 @@ bool Plotter::Remove(int index) } } +bool Plotter::SetColor( int index, String colorA ) +{ + String colors[] = { colorA }; + return SetColorHelper( index, 1, colors ); +} + +bool Plotter::SetColor( int index, String colorA, String colorB ) +{ + String colors[] = { colorA, colorB }; + return SetColorHelper( index, 2, colors ); +} + +bool Plotter::SetColor( int index, String colorA, String colorB, String colorC ) +{ + String colors[] = { colorA, colorB, colorC }; + return SetColorHelper( index, 3, colors ); +} + +bool Plotter::SetColor( int index, String colorA, String colorB, String colorC, + String colorD ) +{ + String colors[] = { colorA, colorB, colorC, colorD }; + return SetColorHelper( index, 4, colors ); +} + +bool Plotter::SetColor( int index, String colorA, String colorB, String colorC, + String colorD, String colorE ) +{ + String colors[] = { colorA, colorB, colorC, colorD, colorE }; + return SetColorHelper( index, 5, colors ); +} + +bool Plotter::SetColor( int index, String colorA, String colorB, String colorC, + String colorD, String colorE, String colorF ) +{ + String colors[] = { colorA, colorB, colorC, colorD, colorE, colorF }; + return SetColorHelper( index, 5, colors ); +} + +bool Plotter::SetColorHelper( int index, int sz, String * colors ) +{ + if ( numGraphs == 0 || index < 0 || numGraphs <= index ) + { + return false; + } + Graph * temp = head; + for ( int i = 0; i < index; i++ ) + { + temp = temp->next; + } + bool res = temp->SetColor( sz, colors ); + if ( res ) + { + lastUpdated = millis(); + } + return res; +} + void Plotter::Plot() { String code = OUTER_KEY; @@ -146,10 +204,32 @@ void Plotter::Graph::Plot() for (int i = 0; i < size; i++) { Serial.print( wrappers[i].GetLabel() ); Serial.print( INNER_KEY ); + Serial.print( wrappers[i].GetColor() ); Serial.print( INNER_KEY ); Serial.print( wrappers[i].GetValue() ); Serial.print( INNER_KEY ); } } +bool Plotter::Graph::SetColor( int sz, String * colors ) +{ + if ( sz != size && !xvy ) + { + return false; + } + + if ( xvy ) + { + wrappers[0].SetColor( colors[0] ); + } + else + { + for ( int i = 0; i < size; i++ ) + { + wrappers[i].SetColor( colors[i] ); + } + } + return true; +} + // VariableWrapper Plotter::VariableWrapper::VariableWrapper() : @@ -157,10 +237,11 @@ Plotter::VariableWrapper::VariableWrapper() : deref( NULL ) {} -Plotter::VariableWrapper::VariableWrapper( String label, void * ref, double ( * deref )( void * ) ) : +Plotter::VariableWrapper::VariableWrapper( String label, void * ref, double ( * deref )( void * ), String color ) : label( label ), - ref ( ref ), - deref ( deref ) + ref( ref ), + deref( deref ), + color( color ) {} String Plotter::VariableWrapper::GetLabel() @@ -172,3 +253,13 @@ double Plotter::VariableWrapper::GetValue() { return deref( ref ); } + +String Plotter::VariableWrapper::GetColor() +{ + return color; +} + +void Plotter::VariableWrapper::SetColor( String col ) +{ + color = col; +} diff --git a/plotter/Plotter.h b/plotter/Plotter.h index c100dff..7b569c3 100644 --- a/plotter/Plotter.h +++ b/plotter/Plotter.h @@ -48,7 +48,7 @@ class Plotter String labelA, A & refA ) { VariableWrapper * wrappers = new VariableWrapper[1]; - wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &Dereference ); + wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &Dereference, "green" ); AddGraphHelper( title, wrappers, 1, false, pointsDisplayed ); } @@ -68,8 +68,8 @@ class Plotter String labelX, X & refX, String labelY, Y & refY ) { VariableWrapper * wrappers = new VariableWrapper[2]; - wrappers[0] = VariableWrapper( labelX, static_cast( &refX ), &Dereference ); - wrappers[1] = VariableWrapper( labelY, static_cast( &refY ), &Dereference ); + wrappers[0] = VariableWrapper( labelX, static_cast( &refX ), &Dereference, "green" ); + wrappers[1] = VariableWrapper( labelY, static_cast( &refY ), &Dereference, "green" ); AddGraphHelper( title, wrappers, 2, true, pointsDisplayed ); } @@ -92,6 +92,17 @@ class Plotter - true, if successful */ bool Remove( int index ); + + /* + Set Variable Colors + + Args: + - index: position of graph to set colors for + - colorA: new color to set + Returns: + - true, if successful + */ + bool SetColor( int index, String colorA ); // Add a 2-variable graph vs. time template @@ -99,8 +110,8 @@ class Plotter String labelA, A & refA, String labelB, B & refB ) { VariableWrapper * wrappers = new VariableWrapper[2]; - wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &Dereference ); - wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &Dereference ); + wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &Dereference, "green" ); + wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &Dereference, "orange" ); AddGraphHelper( title, wrappers, 2, false, pointsDisplayed ); } @@ -110,9 +121,9 @@ class Plotter String labelA, A & refA, String labelB, B & refB, String labelC, C & refC ) { VariableWrapper * wrappers = new VariableWrapper[3]; - wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &Dereference ); - wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &Dereference ); - wrappers[2] = VariableWrapper( labelC, static_cast( &refC ), &Dereference ); + wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &Dereference, "green" ); + wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &Dereference, "orange" ); + wrappers[2] = VariableWrapper( labelC, static_cast( &refC ), &Dereference, "cyan" ); AddGraphHelper( title, wrappers, 3, false, pointsDisplayed ); } @@ -123,10 +134,10 @@ class Plotter String labelD, D & refD ) { VariableWrapper * wrappers = new VariableWrapper[4]; - wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &Dereference ); - wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &Dereference ); - wrappers[2] = VariableWrapper( labelC, static_cast( &refC ), &Dereference ); - wrappers[3] = VariableWrapper( labelD, static_cast( &refD ), &Dereference ); + wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &Dereference, "green"); + wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &Dereference, "orange" ); + wrappers[2] = VariableWrapper( labelC, static_cast( &refC ), &Dereference, "cyan" ); + wrappers[3] = VariableWrapper( labelD, static_cast( &refD ), &Dereference, "yellow" ); AddGraphHelper( title, wrappers, 4, false, pointsDisplayed ); } @@ -137,11 +148,11 @@ class Plotter String labelD, D & refD, String labelE, E & refE ) { VariableWrapper * wrappers = new VariableWrapper[5]; - wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &Dereference ); - wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &Dereference ); - wrappers[2] = VariableWrapper( labelC, static_cast( &refC ), &Dereference ); - wrappers[3] = VariableWrapper( labelD, static_cast( &refD ), &Dereference ); - wrappers[4] = VariableWrapper( labelE, static_cast( &refE ), &Dereference ); + wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &Dereference, "green" ); + wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &Dereference, "orange" ); + wrappers[2] = VariableWrapper( labelC, static_cast( &refC ), &Dereference, "cyan" ); + wrappers[3] = VariableWrapper( labelD, static_cast( &refD ), &Dereference, "yellow" ); + wrappers[4] = VariableWrapper( labelE, static_cast( &refE ), &Dereference, "pink" ); AddGraphHelper( title, wrappers, 5, false, pointsDisplayed ); } @@ -152,37 +163,51 @@ class Plotter String labelD, D & refD, String labelE, E & refE, String labelF, F & refF ) { VariableWrapper * wrappers = new VariableWrapper[6]; - wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &Dereference ); - wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &Dereference ); - wrappers[2] = VariableWrapper( labelC, static_cast( &refC ), &Dereference ); - wrappers[3] = VariableWrapper( labelD, static_cast( &refD ), &Dereference ); - wrappers[4] = VariableWrapper( labelE, static_cast( &refE ), &Dereference ); - wrappers[5] = VariableWrapper( labelF, static_cast( &refF ), &Dereference ); + wrappers[0] = VariableWrapper( labelA, static_cast( &refA ), &Dereference, "green" ); + wrappers[1] = VariableWrapper( labelB, static_cast( &refB ), &Dereference, "orange" ); + wrappers[2] = VariableWrapper( labelC, static_cast( &refC ), &Dereference, "cyan" ); + wrappers[3] = VariableWrapper( labelD, static_cast( &refD ), &Dereference, "yellow" ); + wrappers[4] = VariableWrapper( labelE, static_cast( &refE ), &Dereference, "pink" ); + wrappers[5] = VariableWrapper( labelF, static_cast( &refF ), &Dereference, "blue" ); AddGraphHelper( title, wrappers, 6, false, pointsDisplayed ); } - + + // Set Colors for multivariable graphs + bool SetColor( int index, String colorA, String colorB ); + bool SetColor( int index, String colorA, String colorB, String colorC ); + bool SetColor( int index, String colorA, String colroB, String colorC, + String colorD ); + bool SetColor( int index, String colorA, String colroB, String colorC, + String colorD, String colorE ); + bool SetColor( int index, String colorA, String colroB, String colorC, + String colorD, String colorE, String colorF ); + // Destructor for Plotter class ~Plotter(); - -public: +public: + // Nested VariableWrapper class class VariableWrapper { public: VariableWrapper(); - VariableWrapper( String label, void * ref, double ( * deref )( void * ) ); + VariableWrapper( String label, void * ref, double ( * deref )( void * ), String color ); String GetLabel(); double GetValue(); + String GetColor(); + void SetColor( String col ); private: // Data String label; + String color; void * ref; double ( * deref )( void * ); }; //-- VariableWrapper + public: // Nested Graph node class @@ -192,6 +217,7 @@ class Plotter Graph(String title, VariableWrapper * wrappers, int size, bool xvy, int pointsDisplayed); ~Graph(); void Plot(); + bool SetColor( int sz, String * colors ); // Data Graph * next; @@ -207,7 +233,8 @@ class Plotter private: // Helpers - void AddGraphHelper(String title, VariableWrapper * wrappers, int sz, bool xvy, int pointsDisplayed); + void AddGraphHelper( String title, VariableWrapper * wrappers, int sz, bool xvy, int pointsDisplayed ); + bool SetColorHelper( int index, int sz, String * colors ); template static double Dereference( void * ref ) diff --git a/plotter/examples/set_colors/set_colors.ino b/plotter/examples/set_colors/set_colors.ino new file mode 100644 index 0000000..a0dbc21 --- /dev/null +++ b/plotter/examples/set_colors/set_colors.ino @@ -0,0 +1,36 @@ +/* + =========================================================================================== + Example to demonstrate configuring specific colors for each variable + ------------------------------------------------------------------------------------------- + Plotter + v2.0.0 + https://github.com/devinconley/Arduino-Plotter + by Devin Conley + =========================================================================================== +*/ + +#include "Plotter.h" + +double x; +double y; + +Plotter p; + +void setup() +{ + p = Plotter(); + + p.AddTimeGraph( "Some title of a graph", 500, "label for x", x, "label for y", y ); + p.AddXYGraph( "Title of X vs Y graph", 1000, "x axis", x, "y axis", y ); + + // Set variable colors of graph with index 0 to pink and orange + p.SetColor( 0, "pink", "orange" ); + p.SetColor( 1, "cyan" ); +} + +void loop() { + x = 10*sin( 2.0*PI*( millis() / 5000.0 ) ); + y = 10*cos( 2.0*PI*( millis() / 5000.0 ) ); + + p.Plot(); // usually called within loop() +} \ No newline at end of file diff --git a/plotter/keywords.txt b/plotter/keywords.txt index bb8acc2..7347281 100644 --- a/plotter/keywords.txt +++ b/plotter/keywords.txt @@ -3,3 +3,4 @@ AddTimeGraph KEYWORD2 AddXYGraph KEYWORD2 Plot KEYWORD2 Remove KEYWORD2 +SetColor KEYWORD2 From 08ab27e4ff3082cc89294387f3c052eac96788b1 Mon Sep 17 00:00:00 2001 From: Devin Conley Date: Thu, 19 Jan 2017 21:35:42 -0500 Subject: [PATCH 09/16] Improved formatting of number axis. Increased precision of values sent over serial --- listener/Graph.java | 35 ++++++++++++++++++---- plotter/Plotter.cpp | 5 +++- plotter/examples/set_colors/set_colors.ino | 7 +++-- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/listener/Graph.java b/listener/Graph.java index 393c650..2f2877f 100644 --- a/listener/Graph.java +++ b/listener/Graph.java @@ -1,4 +1,5 @@ import processing.core.PApplet; +import java.text.DecimalFormat; class Graph { @@ -221,9 +222,12 @@ private void DrawTicks( double xScale, double xOffset, double yScale, double yOf for ( float tempY = this.posY + tickOffset; tempY <= this.posY + this.height - tickOffset; tempY += tickInterval ) { - float val = (float) ( ( ( yOffset + this.posY ) - (double)tempY ) / yScale ); + float val = (float) ( ( ( yOffset + this.posY ) - (double)tempY ) / yScale ); + int n = GetDecimalPlaces( val ); + String fmt = "%" + Integer.toString( 1 + SIG_DIGITS - n ) + "." + Integer.toString( n ) + "g"; + this.parent.println( fmt ); this.parent.line( tempX, tempY, tempX + TICK_LEN, tempY ); - this.parent.text( Float.toString( val ), tempX + TICK_LEN + 5, tempY ); + this.parent.text( String.format( fmt, val ), tempX + TICK_LEN + 5, tempY ); } // x-axis @@ -236,11 +240,32 @@ private void DrawTicks( double xScale, double xOffset, double yScale, double yOf { float val = (float) ( ( (double)tempX + xOffset - this.posX ) / xScale ); this.parent.line( tempX, tempY, tempX, tempY + TICK_LEN ); - this.parent.text( Float.toString( val ), tempX, tempY - 5 ); + if ( this.xvy ) + { + int n = GetDecimalPlaces( val ); + String fmt = "%" + Integer.toString( 1 + SIG_DIGITS - n ) + "." + Integer.toString( n ) + "g"; + this.parent.text( String.format( fmt, val ), tempX, tempY - 5 ); + } + else + { + this.parent.text( String.format( "%d", (int)val ), tempX, tempY - 5 ); + } } } + private int GetDecimalPlaces( float value ) + { + int n = SIG_DIGITS; + int d = 1; + while ( n > 0 && Math.round( Math.abs( value / d ) ) > 0 ) + { + n--; + d *= 10; + } + return n; + } + private void CheckExtremes() { // Check new values @@ -348,5 +373,5 @@ else if ( this.data[i][j][0] > this.extremes[1] ) // (max) private static final int TICK_LEN = 6; private static final int NUM_TICKS = 5; private static final float PT_SZ = 1.5f; - -} + private static final int SIG_DIGITS = 3; +} \ No newline at end of file diff --git a/plotter/Plotter.cpp b/plotter/Plotter.cpp index fae613c..25baf17 100644 --- a/plotter/Plotter.cpp +++ b/plotter/Plotter.cpp @@ -201,11 +201,14 @@ void Plotter::Graph::Plot() Serial.print( xvy ); Serial.print( INNER_KEY ); Serial.print( pointsDisplayed ); Serial.print( INNER_KEY ); Serial.print( size ); Serial.print( INNER_KEY ); + + char val[15]; for (int i = 0; i < size; i++) { Serial.print( wrappers[i].GetLabel() ); Serial.print( INNER_KEY ); Serial.print( wrappers[i].GetColor() ); Serial.print( INNER_KEY ); - Serial.print( wrappers[i].GetValue() ); Serial.print( INNER_KEY ); + dtostrf( wrappers[i].GetValue(), 1, 7, val ); + Serial.print( val ); Serial.print( INNER_KEY ); } } diff --git a/plotter/examples/set_colors/set_colors.ino b/plotter/examples/set_colors/set_colors.ino index a0dbc21..e7bcbbd 100644 --- a/plotter/examples/set_colors/set_colors.ino +++ b/plotter/examples/set_colors/set_colors.ino @@ -26,11 +26,12 @@ void setup() // Set variable colors of graph with index 0 to pink and orange p.SetColor( 0, "pink", "orange" ); p.SetColor( 1, "cyan" ); + } void loop() { - x = 10*sin( 2.0*PI*( millis() / 5000.0 ) ); - y = 10*cos( 2.0*PI*( millis() / 5000.0 ) ); - + x = 0.0009*sin( 2.0*PI*( millis() / 5000.0 ) ); + y = 90000*cos( 2.0*PI*( millis() / 5000.0 ) ); + p.Plot(); // usually called within loop() } \ No newline at end of file From 0fc5f27c979f7d548a198dc744421f02f8ac56ee Mon Sep 17 00:00:00 2001 From: Devin Conley Date: Thu, 19 Jan 2017 22:17:28 -0500 Subject: [PATCH 10/16] Changed all drawing sizes to adjust based on size of frame. Switch between %e and %f explicitly instead of using %g --- listener/Graph.java | 55 ++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/listener/Graph.java b/listener/Graph.java index 2f2877f..72cf44b 100644 --- a/listener/Graph.java +++ b/listener/Graph.java @@ -129,15 +129,15 @@ public void Plot() { // Plot Background this.parent.fill( PLOT_COL ); - this.parent.stroke( 255 ); - this.parent.strokeWeight( PT_SZ ); + this.parent.stroke( PLOT_COL ); + this.parent.strokeWeight( (this.width + this.height) / 2.0f * PT_SZ ); this.parent.rect( this.posX, this.posY, this.width, this.height ); // Title - this.parent.textSize( TITLE_SZ ); + this.parent.textSize( (int)( (this.width + this.height) / 2.0f * TITLE_SZ ) ); this.parent.fill( 255 ); this.parent.textAlign( this.parent.CENTER, this.parent.TOP ); - this.parent.text( this.title, this.posX + this.width / 2, this.posY + TITLE_SZ); + this.parent.text( this.title, this.posX + this.width / 2, this.posY + 10 ); // Calculations for offset and scaling of graph ( vs. time ) @@ -179,17 +179,19 @@ public void Plot() private void DrawTimeStuff() { + int labelSz = (int) ( (this.width + this.height) / 2.0f * LABEL_SZ ); + // Setup legend start - float textPos = this.posY + LABEL_SZ; + float textPos = this.posY + labelSz; this.parent.textAlign( this.parent.RIGHT, this.parent.TOP ); - this.parent.textSize( LABEL_SZ ); + this.parent.textSize( labelSz ); // Draw each legend entry for ( int i = 0; i < this.numVars; i++ ) { this.parent.fill( this.colors[i] ); this.parent.text( this.labels[i], this.posX + this.width - 10, textPos); - textPos += ( LABEL_SZ + LABEL_SZ/4 ); + textPos += ( labelSz + labelSz/4 ); this.parent.stroke( this.colors[i] ); } @@ -198,12 +200,12 @@ private void DrawTimeStuff() private void DrawXYStuff() { // X and Y labels - this.parent.textSize( LABEL_SZ ); + this.parent.textSize( (int)( (this.width + this.height) / 2.0f * LABEL_SZ) ); this.parent.textAlign( this.parent.LEFT, this.parent.TOP ); this.parent.text( this.labels[1], this.posX + 10, this.posY + 10); this.parent.textAlign( this.parent.RIGHT, this.parent.BOTTOM ); - this.parent.text( this.labels[0], this.posX + this.width - 10, this.posY + this.height - 3*NUM_SZ); + this.parent.text( this.labels[0], this.posX + this.width - 10, this.posY + this.height - 3.5f*TICK_LEN); } @@ -212,7 +214,7 @@ private void DrawTicks( double xScale, double xOffset, double yScale, double yOf // Label graph with numbered tick marks this.parent.stroke( 255 ); this.parent.fill( 255 ); - this.parent.textSize( NUM_SZ ); + this.parent.textSize( (int)( ( this.width + this.height ) / 2.0f * NUM_SZ ) ); this.parent.textAlign( this.parent.LEFT, this.parent.CENTER ); // Draw ticks along y-axis @@ -223,9 +225,7 @@ private void DrawTicks( double xScale, double xOffset, double yScale, double yOf tempY += tickInterval ) { float val = (float) ( ( ( yOffset + this.posY ) - (double)tempY ) / yScale ); - int n = GetDecimalPlaces( val ); - String fmt = "%" + Integer.toString( 1 + SIG_DIGITS - n ) + "." + Integer.toString( n ) + "g"; - this.parent.println( fmt ); + String fmt = GetNumberFormat( val ); this.parent.line( tempX, tempY, tempX + TICK_LEN, tempY ); this.parent.text( String.format( fmt, val ), tempX + TICK_LEN + 5, tempY ); } @@ -242,8 +242,7 @@ private void DrawTicks( double xScale, double xOffset, double yScale, double yOf this.parent.line( tempX, tempY, tempX, tempY + TICK_LEN ); if ( this.xvy ) { - int n = GetDecimalPlaces( val ); - String fmt = "%" + Integer.toString( 1 + SIG_DIGITS - n ) + "." + Integer.toString( n ) + "g"; + String fmt = GetNumberFormat( val ); this.parent.text( String.format( fmt, val ), tempX, tempY - 5 ); } else @@ -254,8 +253,8 @@ private void DrawTicks( double xScale, double xOffset, double yScale, double yOf } - private int GetDecimalPlaces( float value ) - { + private String GetNumberFormat( float value ) + { int n = SIG_DIGITS; int d = 1; while ( n > 0 && Math.round( Math.abs( value / d ) ) > 0 ) @@ -263,7 +262,17 @@ private int GetDecimalPlaces( float value ) n--; d *= 10; } - return n; + + String fmt = "%" + Integer.toString( 1 + SIG_DIGITS - n ) + "." + Integer.toString( n ); + if ( ( Math.abs( value ) > 1000 || Math.abs( value ) < 0.001 ) && value != 0 ) + { + fmt += "e"; + } + else + { + fmt += "f"; + } + return fmt; } private void CheckExtremes() @@ -367,11 +376,11 @@ else if ( this.data[i][j][0] > this.extremes[1] ) // (max) // Constants private static final float AXIS_COV = 0.75f; private static final int PLOT_COL = 115; - private static final int LABEL_SZ = 14; - private static final int TITLE_SZ = 16; - private static final int NUM_SZ = 10; + private static final float LABEL_SZ = 0.025f; + private static final float TITLE_SZ = 0.03f; + private static final float NUM_SZ = 0.02f; private static final int TICK_LEN = 6; private static final int NUM_TICKS = 5; - private static final float PT_SZ = 1.5f; + private static final float PT_SZ = 0.0025f; private static final int SIG_DIGITS = 3; -} \ No newline at end of file +} From 8360667aca541b88944c87db1570886e915ce3a5 Mon Sep 17 00:00:00 2001 From: Devin Conley Date: Thu, 19 Jan 2017 22:52:20 -0500 Subject: [PATCH 11/16] Updated README, and comment headers (description and version) --- README.md | 21 ++++++++++++--- listener/Graph.java | 27 ++++++++++++++++++- listener/listener.pde | 19 ++++++------- plotter/Plotter.cpp | 14 +++++----- plotter/Plotter.h | 12 +++++---- .../control_points_displayed.ino | 4 +-- .../different_types/different_types.ino | 4 +-- .../dynamically_modify_graph_layout.ino | 4 +-- .../multivariable_plotting.ino | 4 +-- plotter/examples/quick_start/quick_start.ino | 4 +-- plotter/examples/set_colors/set_colors.ino | 5 ++-- plotter/library.properties | 4 +-- 12 files changed, 83 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 3b16651..c77c98a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Arduino-Plotter +arduino-plotter =============== An Arduino library for easy graphing on host computer via serial communication @@ -6,13 +6,14 @@ _by: Devin Conley_ Features: --- -- Multi-variable plots against time +- Continuous multi-variable plots against time - 2-variable "x" vs "y" plots -- Display multiple graphs within single window +- Display multiple graphs within single resizable window - Support for any data type that can be cast to a double - Simply pass a reference to your variables when the graph is added, no need to update each value explicitly - Control number of data points displayed on each graph - Auto-scaling to fit all data on graph +- Configurable line color per variable - Stand-alone listener application, written with Processing, is provided ![Plotter Preview Image](https://www.dropbox.com/s/0471kf89skyo72x/plotter_preview.png?raw=1) @@ -27,7 +28,7 @@ Search for "Plotter" in the Arduino Library Manager. ___or___ -Install manually with the [ZIP file of Plotter](https://github.com/devinconley/ArduinoPlotter-for-Library-Manager/archive/master.zip). +Install manually with the [ZIP file of Plotter](https://github.com/devinconley/arduino-plotter-for-library-manager/archive/master.zip). --- @@ -146,3 +147,15 @@ Documentation: ##### Returns - bool: true if successful + +--- + +#### bool SetColor( int index, String colorA, ... ) + +*Sets the line colors for each variable in the graph at the specified position with zero-indexing. (ie passing 0 would set colors for the first graph added)* +##### Arguments +- index: position of graph to remove +- colorA: color for first variable + +##### Returns +- bool: true if successful diff --git a/listener/Graph.java b/listener/Graph.java index 72cf44b..306c608 100644 --- a/listener/Graph.java +++ b/listener/Graph.java @@ -1,5 +1,30 @@ +/* + =========================================================================================== + This Graph class handles an individual graph being displayed on the Arduino Plotter + listener. + ------------------------------------------------------------------------------------------- + The library stores and handles all relevant graph information and variable references, + and transfers information via the serial port to a listener program written with the + software provided by Processing. No modification is needed to this program; graph placement, + axis-scaling, etc. are handled automatically. + Multiple options for this listener are available including stand-alone applications as well + as the source Processing script. + + The library, these listeners, a quick-start guide, documentation, and usage examples are + available at: + + https://github.com/devinaconley/arduino-plotter + + ------------------------------------------------------------------------------------------- + Arduino Plotter Listener + v2.1.0 + https://github.com/devinaconley/arduino-plotter + by Devin Conley + =========================================================================================== +*/ + + import processing.core.PApplet; -import java.text.DecimalFormat; class Graph { diff --git a/listener/listener.pde b/listener/listener.pde index 10b8612..e438573 100644 --- a/listener/listener.pde +++ b/listener/listener.pde @@ -1,23 +1,25 @@ /* =========================================================================================== - This listener is the source processing script that corresponds to the Arduino Plotter - library for Arduino. The library supports plots against time as well as 2-variable - "X vs Y" graphing. + This listener is the main processing script that corresponds to the Arduino Plotter + library for Arduino. This driver script handles serial port information and manages a + set of Graph objects to do the actual plotting. ------------------------------------------------------------------------------------------- - The library transfers information via the serial port to a listener program written with the + The library stores and handles all relevant graph information and variable references, + and transfers information via the serial port to a listener program written with the software provided by Processing. No modification is needed to this program; graph placement, axis-scaling, etc. are handled automatically. Multiple options for this listener are available including stand-alone applications as well as the source Processing script. - The library, these listeners, a quick-start guide, and usage examples are available at: + The library, these listeners, a quick-start guide, documentation, and usage examples are + available at: - https://github.com/devinconley/Arduino-Plotter + https://github.com/devinaconley/arduino-plotter ------------------------------------------------------------------------------------------- Arduino Plotter Listener - v2.0.0 - https://github.com/devinconley/Arduino-Plotter + v2.1.0 + https://github.com/devinaconley/arduino-plotter by Devin Conley =========================================================================================== */ @@ -166,7 +168,6 @@ void serialEvent( Serial ser ) { colorsTemp[j] = COLORMAP.get( "green" ); } - println( colorsTemp[j] ); } if ( xvyTemp ) diff --git a/plotter/Plotter.cpp b/plotter/Plotter.cpp index 25baf17..613faec 100644 --- a/plotter/Plotter.cpp +++ b/plotter/Plotter.cpp @@ -3,23 +3,25 @@ Plotter is an Arduino library that allows easy multi-variable and multi-graph plotting. The library supports plots against time as well as 2-variable "X vs Y" graphing. ------------------------------------------------------------------------------------------- - The library transfers information via the serial port to a listener program written with the + The library stores and handles all relevant graph information and variable references, + and transfers information via the serial port to a listener program written with the software provided by Processing. No modification is needed to this program; graph placement, axis-scaling, etc. are handled automatically. Multiple options for this listener are available including stand-alone applications as well as the source Processing script. - The library, these listeners, a quick-start guide, and usage examples are available at: + The library, these listeners, a quick-start guide, documentation, and usage examples are + available at: - https://github.com/devinconley/Arduino-Plotter + https://github.com/devinaconley/arduino-plotter ------------------------------------------------------------------------------------------- Plotter - v2.0.0 - https://github.com/devinconley/Arduino-Plotter + v2.1.0 + https://github.com/devinaconley/arduino-plotter by Devin Conley =========================================================================================== - */ +*/ #include "Plotter.h" diff --git a/plotter/Plotter.h b/plotter/Plotter.h index 7b569c3..ddf8f94 100644 --- a/plotter/Plotter.h +++ b/plotter/Plotter.h @@ -3,20 +3,22 @@ Plotter is an Arduino library that allows easy multi-variable and multi-graph plotting. The library supports plots against time as well as 2-variable "X vs Y" graphing. ------------------------------------------------------------------------------------------- - The library transfers information via the serial port to a listener program written with the + The library stores and handles all relevant graph information and variable references, + and transfers information via the serial port to a listener program written with the software provided by Processing. No modification is needed to this program; graph placement, axis-scaling, etc. are handled automatically. Multiple options for this listener are available including stand-alone applications as well as the source Processing script. - The library, these listeners, a quick-start guide, and usage examples are available at: + The library, these listeners, a quick-start guide, documentation, and usage examples are + available at: - https://github.com/devinconley/Arduino-Plotter + https://github.com/devinaconley/arduino-plotter ------------------------------------------------------------------------------------------- Plotter - v2.0.0 - https://github.com/devinconley/Arduino-Plotter + v2.1.0 + https://github.com/devinaconley/arduino-plotter by Devin Conley =========================================================================================== */ diff --git a/plotter/examples/control_points_displayed/control_points_displayed.ino b/plotter/examples/control_points_displayed/control_points_displayed.ino index 77073b0..c13bc97 100644 --- a/plotter/examples/control_points_displayed/control_points_displayed.ino +++ b/plotter/examples/control_points_displayed/control_points_displayed.ino @@ -3,8 +3,8 @@ Example to demonstrate effect of "Points Displayed" in Time Graph and in XY Graph ------------------------------------------------------------------------------------------- Plotter - v2.0.0 - https://github.com/devinconley/Arduino-Plotter + v2.1.0 + https://github.com/devinaconley/arduino-plotter by Devin Conley =========================================================================================== */ diff --git a/plotter/examples/different_types/different_types.ino b/plotter/examples/different_types/different_types.ino index 7d94c59..e169998 100644 --- a/plotter/examples/different_types/different_types.ino +++ b/plotter/examples/different_types/different_types.ino @@ -3,8 +3,8 @@ Example to demonstrate effect of plotting different variable types ------------------------------------------------------------------------------------------- Plotter - v2.0.0 - https://github.com/devinconley/Arduino-Plotter + v2.1.0 + https://github.com/devinaconley/arduino-plotter by Devin Conley =========================================================================================== */ diff --git a/plotter/examples/dynamically_modify_graph_layout/dynamically_modify_graph_layout.ino b/plotter/examples/dynamically_modify_graph_layout/dynamically_modify_graph_layout.ino index 747eaa2..25d6c00 100644 --- a/plotter/examples/dynamically_modify_graph_layout/dynamically_modify_graph_layout.ino +++ b/plotter/examples/dynamically_modify_graph_layout/dynamically_modify_graph_layout.ino @@ -3,8 +3,8 @@ Example to demonstrate dynamic addition and removal of graphs ------------------------------------------------------------------------------------------- Plotter - v2.0.0 - https://github.com/devinconley/Arduino-Plotter + v2.1.0 + https://github.com/devinaconley/arduino-plotter by Devin Conley =========================================================================================== */ diff --git a/plotter/examples/multivariable_plotting/multivariable_plotting.ino b/plotter/examples/multivariable_plotting/multivariable_plotting.ino index edccfc3..3cd5a1e 100644 --- a/plotter/examples/multivariable_plotting/multivariable_plotting.ino +++ b/plotter/examples/multivariable_plotting/multivariable_plotting.ino @@ -3,8 +3,8 @@ Example to demonstrate multi-variable plotting against time ------------------------------------------------------------------------------------------- Plotter - v2.0.0 - https://github.com/devinconley/Arduino-Plotter + v2.1.0 + https://github.com/devinaconley/arduino-plotter by Devin Conley =========================================================================================== */ diff --git a/plotter/examples/quick_start/quick_start.ino b/plotter/examples/quick_start/quick_start.ino index ceac442..dda4ad4 100644 --- a/plotter/examples/quick_start/quick_start.ino +++ b/plotter/examples/quick_start/quick_start.ino @@ -3,8 +3,8 @@ Example used in Quick-Start ------------------------------------------------------------------------------------------- Plotter - v2.0.0 - https://github.com/devinconley/Arduino-Plotter + v2.1.0 + https://github.com/devinaconley/arduino-plotter by Devin Conley =========================================================================================== */ diff --git a/plotter/examples/set_colors/set_colors.ino b/plotter/examples/set_colors/set_colors.ino index e7bcbbd..f786549 100644 --- a/plotter/examples/set_colors/set_colors.ino +++ b/plotter/examples/set_colors/set_colors.ino @@ -3,8 +3,8 @@ Example to demonstrate configuring specific colors for each variable ------------------------------------------------------------------------------------------- Plotter - v2.0.0 - https://github.com/devinconley/Arduino-Plotter + v2.1.0 + https://github.com/deviaconley/arduino-plotter by Devin Conley =========================================================================================== */ @@ -25,6 +25,7 @@ void setup() // Set variable colors of graph with index 0 to pink and orange p.SetColor( 0, "pink", "orange" ); + // Set color of x vs y graph at index 1 to cyan p.SetColor( 1, "cyan" ); } diff --git a/plotter/library.properties b/plotter/library.properties index 8e0bc4a..a4cccf6 100644 --- a/plotter/library.properties +++ b/plotter/library.properties @@ -1,9 +1,9 @@ name=Plotter -version=2.0.0 +version=2.1.0 author=Devin Conley maintainer=Devin Conley sentence=An Arduino library for easy plotting on host computer via serial communication. paragraph=Supports multi-variable plots against time as well as 2D plotting of an X vs Y variable. Multiple graphs can be displayed at once, with all formatting and scaling handled automatically. A stand-alone listener application, written with Processing, is provided. category=Data Processing -url=https://github.com/devinconley/Arduino-Plotter +url=https://github.com/devinaconley/arduino-plotter architectures=* \ No newline at end of file From dd7e1c8726a4646211d21b64847a242a24c456a4 Mon Sep 17 00:00:00 2001 From: Devin Conley Date: Thu, 19 Jan 2017 23:02:53 -0500 Subject: [PATCH 12/16] Verify correct title/labels before finishing config --- listener/listener.pde | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/listener/listener.pde b/listener/listener.pde index e438573..6cc0d17 100644 --- a/listener/listener.pde +++ b/listener/listener.pde @@ -53,6 +53,7 @@ int h; int w; int numGraphs; String configCode = "This will not be matched!"; +String lastLabels = "Also will not be matched"; boolean configured = false; int lastConfig; int lastPortSwitch; @@ -142,8 +143,8 @@ void serialEvent( Serial ser ) throw new Exception(); } configured = false; - //print("New config"); - + String concatLabels = ""; + // Setup new layout float[][] posGraphs = setupGraphPosition( numGraphs ); @@ -153,13 +154,15 @@ void serialEvent( Serial ser ) for ( int i = 0; i < numGraphs; i++ ) { arraySub = arrayMain[i+1].split( INNER_KEY ); - String title = arraySub[0]; + String title = arraySub[0]; boolean xvyTemp = Integer.parseInt( arraySub[1] ) == 1; int maxPoints = Integer.parseInt( arraySub[2] ); int numVars = Integer.parseInt( arraySub[3] ); String[] labelsTemp = new String[numVars]; int[] colorsTemp = new int[numVars]; - + + concatLabels += title; + for ( int j = 0; j < numVars; j++ ) { labelsTemp[j] = arraySub[4 + 3*j]; @@ -168,6 +171,7 @@ void serialEvent( Serial ser ) { colorsTemp[j] = COLORMAP.get( "green" ); } + concatLabels += labelsTemp[j]; } if ( xvyTemp ) @@ -181,11 +185,14 @@ void serialEvent( Serial ser ) graphs.add( temp ); } println("Added ", graphs.size() ); - + // Set new config code - configCode = arrayMain[0]; - //println(config_code); - lastConfig = millis(); + if ( concatLabels.equals( lastLabels ) ) // Only when we're sure on labels + { + configCode = arrayMain[0]; + lastConfig = millis(); + } + lastLabels = concatLabels; } else { From 4aa5b6fe4e13298e5fc109df1c32581e329a8c1d Mon Sep 17 00:00:00 2001 From: Devin Conley Date: Fri, 20 Jan 2017 00:11:49 -0500 Subject: [PATCH 13/16] Update README.md --- README.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index c77c98a..9ab4615 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Features: - Configurable line color per variable - Stand-alone listener application, written with Processing, is provided -![Plotter Preview Image](https://www.dropbox.com/s/0471kf89skyo72x/plotter_preview.png?raw=1) +![Plotter Preview](https://www.dropbox.com/s/2mtg5ig7lyrrffi/plotter_preview.gif?raw=1) --- @@ -28,16 +28,16 @@ Search for "Plotter" in the Arduino Library Manager. ___or___ -Install manually with the [ZIP file of Plotter](https://github.com/devinconley/arduino-plotter-for-library-manager/archive/master.zip). +Install manually with the [ZIP file of Plotter](https://github.com/devinaconley/arduino-plotter-for-library-manager/archive/master.zip). --- #### Setup Listener Download one of the following stand-alone listener options. Keep the folder intact so the application can access the library and source folders. -- [Windows 32-bit](https://www.dropbox.com/s/88wa2nkfzh5j3uz/ArduinoPlotter_listener_windows32.zip?dl=1) -- [Windows 64-bit](https://www.dropbox.com/s/ahy2ppul6v4lybi/ArduinoPlotter_listener_windows64.zip?dl=1) -- [Linux 32-bit](https://www.dropbox.com/s/ilt9n3hkiw74vrf/ArduinoPlotter_listener_linux32.zip?dl=1) -- [Linux 64-bit](https://www.dropbox.com/s/6irh0fn4c97aqz0/ArduinoPlotter_listener_linux64.zip?dl=1) +- [Windows 32-bit](https://www.dropbox.com/s/vbgd4osedrfgep3/arduino-plotter-listener-windows32.zip?dl=1) +- [Windows 64-bit](https://www.dropbox.com/s/0x4xqv375h4j5hh/arduino-plotter-listener-windows64.zip?dl=1) +- [Linux 32-bit](https://www.dropbox.com/s/u0g1ey96aw14k9z/arduino-plotter-listener-linux32.zip?dl=1) +- [Linux 64-bit](https://www.dropbox.com/s/lsrpo5edb25sv3a/arduino-plotter-listener-linux64.zip?dl=1) - [Mac OS X](https://www.dropbox.com/s/emasvotan4yxbmo/ArduinoPlotter_listener_macOSX.zip?dl=1) ___or___ @@ -150,12 +150,16 @@ Documentation: --- -#### bool SetColor( int index, String colorA, ... ) +#### bool SetColor( int index, String colorA, String colorB, ... ) *Sets the line colors for each variable in the graph at the specified position with zero-indexing. (ie passing 0 would set colors for the first graph added)* + +*Options: "red", "green", "blue", "orange", "yellow", "pink", "purple", "cyan"* ##### Arguments - index: position of graph to remove - colorA: color for first variable +- colorB: color for second variable +- ... ##### Returns -- bool: true if successful +- bool: true if successful. returns false when incorrect number of colors have been passed. From 34fa0d49f2201b431587aa64798b9890b03ec5df Mon Sep 17 00:00:00 2001 From: Devin Conley Date: Fri, 20 Jan 2017 00:37:01 -0500 Subject: [PATCH 14/16] Fixed drawing order in graph object --- listener/Graph.java | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/listener/Graph.java b/listener/Graph.java index 306c608..6fc76c5 100644 --- a/listener/Graph.java +++ b/listener/Graph.java @@ -171,24 +171,15 @@ public void Plot() double yScale = AXIS_COV * this.height / ( this.extremes[3] - this.extremes[2] ); double yOffset = yScale * this.extremes[3] + 0.5 * ( 1.0 - AXIS_COV ) * this.height; - // X vs Y and vs Time specific stuff + // Modify scaling and offset if ( this.xvy ) { - this.DrawXYStuff(); - - // Modify scaling and offset xScale *= AXIS_COV; xOffset = xScale * this.extremes[0] - 0.5 * ( 1.0 - AXIS_COV ) * this.width; } - else - { - this.DrawTimeStuff(); - } - // Draw Ticks - this.DrawTicks( xScale, xOffset, yScale, yOffset ); - // Do actual data plotting + // Do actual data plotting for ( int i = 0; i < this.numVars; i++ ) { this.parent.stroke( this.colors[i] ); @@ -197,7 +188,21 @@ public void Plot() this.parent.point( (float)(this.posX + (this.data[j][i][0]*xScale - xOffset)), (float)(this.posY + yOffset - data[j][i][1]*yScale) ); } + } + + // X vs Y and vs Time specific stuff + if ( this.xvy ) + { + this.DrawXYStuff(); + } + else + { + this.DrawTimeStuff(); } + + // Draw Ticks + this.DrawTicks( xScale, xOffset, yScale, yOffset ); + } // Private Helpers From ef5736e64a8556e8dd69bf1650a7a32b96e2cdae Mon Sep 17 00:00:00 2001 From: Devin Conley Date: Fri, 20 Jan 2017 00:44:45 -0500 Subject: [PATCH 15/16] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9ab4615..e07677a 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Download one of the following stand-alone listener options. Keep the folder inta ___or___ -Download the source script from this repository (ArduinoPlotter_processingListener.pde) and run that with the Processing IDE. +Download the source directory from this repository (listener/) and run that with the Processing IDE. --- From f58a5b89b15b805a5bb5c5496c1ee1584ec23591 Mon Sep 17 00:00:00 2001 From: Devin Conley Date: Fri, 20 Jan 2017 00:52:44 -0500 Subject: [PATCH 16/16] fixed keywords file --- plotter/keywords.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plotter/keywords.txt b/plotter/keywords.txt index 7347281..9a1b355 100644 --- a/plotter/keywords.txt +++ b/plotter/keywords.txt @@ -3,4 +3,4 @@ AddTimeGraph KEYWORD2 AddXYGraph KEYWORD2 Plot KEYWORD2 Remove KEYWORD2 -SetColor KEYWORD2 +SetColor KEYWORD2