mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-28 07:28:20 -04:00
created a data plotter
This commit is contained in:
parent
218b6e6895
commit
7129b9b5b6
138
src/main/java/de/neemann/digital/data/DataPlotter.java
Normal file
138
src/main/java/de/neemann/digital/data/DataPlotter.java
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
package de.neemann.digital.data;
|
||||||
|
|
||||||
|
import de.neemann.digital.draw.graphics.Graphic;
|
||||||
|
import de.neemann.digital.draw.graphics.Orientation;
|
||||||
|
import de.neemann.digital.draw.graphics.Style;
|
||||||
|
import de.neemann.digital.draw.graphics.Vector;
|
||||||
|
import de.neemann.digital.draw.shapes.Drawable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The dataSet stores the collected DataSamples.
|
||||||
|
* Every DataSample contains the values of al signals at a given time.
|
||||||
|
*
|
||||||
|
* @author hneemann
|
||||||
|
*/
|
||||||
|
public class DataPlotter implements Drawable {
|
||||||
|
private final ValueTable data;
|
||||||
|
private final int maxTextLength;
|
||||||
|
private double size = SIZE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a simple dummy DataSet used for creating the DataShape
|
||||||
|
*/
|
||||||
|
public DataPlotter() {
|
||||||
|
this(new ValueTable("A", "B", "C")
|
||||||
|
.add(new Value[]{new Value(0), new Value(0), new Value(0)})
|
||||||
|
.add(new Value[]{new Value(0), new Value(1), new Value(0)})
|
||||||
|
.add(new Value[]{new Value(0), new Value(1), new Value(0)})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance
|
||||||
|
*
|
||||||
|
* @param data the signals used to collect DataSamples
|
||||||
|
*/
|
||||||
|
public DataPlotter(ValueTable data) {
|
||||||
|
this.data = data;
|
||||||
|
int tl = 0;
|
||||||
|
for (int i = 0; i < data.getColumns(); i++) {
|
||||||
|
String text = data.getColumnName(i);
|
||||||
|
int w = text.length();
|
||||||
|
if (w > tl) tl = w;
|
||||||
|
}
|
||||||
|
maxTextLength = tl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int BORDER = 10;
|
||||||
|
private static final int SIZE = 25;
|
||||||
|
private static final int SEP2 = 5;
|
||||||
|
private static final int SEP = SEP2 * 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fits the data in the visible area
|
||||||
|
*
|
||||||
|
* @param width width of the frame
|
||||||
|
*/
|
||||||
|
public void fitInside(int width) {
|
||||||
|
size = ((double) (width - getTextBorder())) / data.getRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply a scaling factor
|
||||||
|
*
|
||||||
|
* @param f the factor
|
||||||
|
*/
|
||||||
|
public void scale(double f) {
|
||||||
|
size *= f;
|
||||||
|
if (size < Style.NORMAL.getThickness()) size = Style.NORMAL.getThickness();
|
||||||
|
if (size > SIZE * 4) size = SIZE * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
synchronized public void drawTo(Graphic g, Style highLight) {
|
||||||
|
int x = getTextBorder();
|
||||||
|
|
||||||
|
int yOffs = SIZE / 2;
|
||||||
|
int y = BORDER;
|
||||||
|
int signals = data.getColumns();
|
||||||
|
for (int i = 0; i < signals; i++) {
|
||||||
|
String text = data.getColumnName(i);
|
||||||
|
g.drawText(new Vector(x - 2, y + yOffs), new Vector(x + 1, y + yOffs), text, Orientation.RIGHTCENTER, Style.NORMAL);
|
||||||
|
g.drawLine(new Vector(x, y - SEP2), new Vector(x + (int) (size * data.getRows()), y - SEP2), Style.DASH);
|
||||||
|
y += SIZE + SEP;
|
||||||
|
}
|
||||||
|
g.drawLine(new Vector(x, y - SEP2), new Vector(x + (int) (size * data.getRows()), y - SEP2), Style.DASH);
|
||||||
|
|
||||||
|
|
||||||
|
int[] lastRy = new int[signals];
|
||||||
|
boolean first = true;
|
||||||
|
double pos = 0;
|
||||||
|
for (Value[] s : data) {
|
||||||
|
int xx = (int) (pos + x);
|
||||||
|
g.drawLine(new Vector(xx, BORDER - SEP2), new Vector(xx, (SIZE + SEP) * signals + BORDER - SEP2), Style.DASH);
|
||||||
|
y = BORDER;
|
||||||
|
for (int i = 0; i < signals; i++) {
|
||||||
|
|
||||||
|
long width = data.getMax(i);
|
||||||
|
if (width == 0) width = 1;
|
||||||
|
int ry = (int) (SIZE - (SIZE * s[i].getValue()) / width);
|
||||||
|
g.drawLine(new Vector(xx, y + ry), new Vector((int) (xx + size), y + ry), Style.NORMAL);
|
||||||
|
if (!first && ry != lastRy[i])
|
||||||
|
g.drawLine(new Vector(xx, y + lastRy[i]), new Vector(xx, y + ry), Style.NORMAL);
|
||||||
|
|
||||||
|
lastRy[i] = ry;
|
||||||
|
y += SIZE + SEP;
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
pos += size;
|
||||||
|
}
|
||||||
|
g.drawLine(new Vector(x, BORDER - SEP2), new Vector(x, (SIZE + SEP) * signals + BORDER - SEP2), Style.DASH);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getTextBorder() {
|
||||||
|
return maxTextLength * Style.NORMAL.getFontSize() / 2 + BORDER + SEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the preferred width of the graphical representation
|
||||||
|
*/
|
||||||
|
public int getGraphicWidth() {
|
||||||
|
return getTextBorder() + data.getRows() * SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the preferred height of the graphical representation
|
||||||
|
*/
|
||||||
|
public int getGraphicHeight() {
|
||||||
|
return data.getColumns() * (SIZE + SEP) + 2 * BORDER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the current width of the graphical representation
|
||||||
|
*/
|
||||||
|
public int getCurrentGraphicWidth() {
|
||||||
|
return getTextBorder() + (int) (data.getRows() * size);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -68,7 +68,7 @@ public class Value {
|
|||||||
*
|
*
|
||||||
* @param val the value
|
* @param val the value
|
||||||
*/
|
*/
|
||||||
public Value(int val) {
|
public Value(long val) {
|
||||||
this.value = val;
|
this.value = val;
|
||||||
this.type = Type.NORMAL;
|
this.type = Type.NORMAL;
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ public class Value {
|
|||||||
* @param val the string
|
* @param val the string
|
||||||
*/
|
*/
|
||||||
public Value(String val) {
|
public Value(String val) {
|
||||||
val = val.trim();
|
val = val.trim().toUpperCase();
|
||||||
switch (val) {
|
switch (val) {
|
||||||
case "X":
|
case "X":
|
||||||
value = 0;
|
value = 0;
|
||||||
|
@ -1,24 +1,37 @@
|
|||||||
package de.neemann.digital.data;
|
package de.neemann.digital.data;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores values in a table
|
* Stores values in a table
|
||||||
* Created by hneemann on 03.07.17.
|
* Created by hneemann on 03.07.17.
|
||||||
*/
|
*/
|
||||||
public class ValueTable {
|
public class ValueTable implements Iterable<Value[]> {
|
||||||
|
|
||||||
private final ArrayList<String> names;
|
private final String[] names;
|
||||||
private final ArrayList<Value[]> values;
|
private final ArrayList<Value[]> values;
|
||||||
|
private final long[] max;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new table.
|
* Creates a new table.
|
||||||
*
|
*
|
||||||
* @param names the cignal names
|
* @param names the signal names
|
||||||
*/
|
*/
|
||||||
public ValueTable(ArrayList<String> names) {
|
public ValueTable(ArrayList<String> names) {
|
||||||
|
this(names.toArray(new String[names.size()]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new table.
|
||||||
|
*
|
||||||
|
* @param names the signal names
|
||||||
|
*/
|
||||||
|
public ValueTable(String... names) {
|
||||||
this.names = names;
|
this.names = names;
|
||||||
values = new ArrayList<>();
|
values = new ArrayList<>();
|
||||||
|
max = new long[names.length];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,9 +45,13 @@ public class ValueTable {
|
|||||||
* add values without copying them
|
* add values without copying them
|
||||||
*
|
*
|
||||||
* @param row a row to insert, values are not copied!
|
* @param row a row to insert, values are not copied!
|
||||||
|
* @return this for chained calls
|
||||||
*/
|
*/
|
||||||
public void add(Value[] row) {
|
public ValueTable add(Value[] row) {
|
||||||
values.add(row);
|
values.add(row);
|
||||||
|
for (int i = 0; i < row.length; i++)
|
||||||
|
if (max[i] < row[i].getValue()) max[i] = row[i].getValue();
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -50,18 +67,69 @@ public class ValueTable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* the number of signals
|
* the number of signals
|
||||||
|
*
|
||||||
* @return the column count
|
* @return the column count
|
||||||
*/
|
*/
|
||||||
public int getColumns() {
|
public int getColumns() {
|
||||||
return names.size();
|
return names.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the column names
|
* Returns the column names
|
||||||
|
*
|
||||||
* @param col the column
|
* @param col the column
|
||||||
* @return the name
|
* @return the name
|
||||||
*/
|
*/
|
||||||
public String getColumnName(int col) {
|
public String getColumnName(int col) {
|
||||||
return names.get(col);
|
return names[col];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Value[]> iterator() {
|
||||||
|
return values.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the max value stored in the given column
|
||||||
|
*
|
||||||
|
* @param col the column
|
||||||
|
* @return the max value
|
||||||
|
*/
|
||||||
|
public long getMax(int col) {
|
||||||
|
return max[col];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the data in csv file
|
||||||
|
*
|
||||||
|
* @param file the file
|
||||||
|
* @throws IOException IOException
|
||||||
|
*/
|
||||||
|
public void saveCSV(File file) throws IOException {
|
||||||
|
saveCSV(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the data in csv file
|
||||||
|
*
|
||||||
|
* @param w the writer
|
||||||
|
* @throws IOException IOException
|
||||||
|
*/
|
||||||
|
public void saveCSV(BufferedWriter w) throws IOException {
|
||||||
|
try {
|
||||||
|
w.write("\"step\"");
|
||||||
|
for (String s : names)
|
||||||
|
w.write(",\"" + s + '"');
|
||||||
|
w.write("\n");
|
||||||
|
int row = 0;
|
||||||
|
for (Value[] s : this) {
|
||||||
|
w.write("\"" + (row++) + "\"");
|
||||||
|
for (Value value : s) w.write(",\"" + value + "\"");
|
||||||
|
w.write("\n");
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
w.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
47
src/test/java/de/neemann/digital/data/ValueTableTest.java
Normal file
47
src/test/java/de/neemann/digital/data/ValueTableTest.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package de.neemann.digital.data;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by hneemann on 03.07.17.
|
||||||
|
*/
|
||||||
|
public class ValueTableTest extends TestCase {
|
||||||
|
private ValueTable t = new ValueTable("A", "B", "C")
|
||||||
|
.add(new Value[]{new Value(0), new Value(0), new Value(0)})
|
||||||
|
.add(new Value[]{new Value(0), new Value(1), new Value("z")});
|
||||||
|
|
||||||
|
|
||||||
|
public void testGeneral() throws Exception {
|
||||||
|
assertEquals(3, t.getColumns());
|
||||||
|
assertEquals(2, t.getRows());
|
||||||
|
assertEquals("A", t.getColumnName(0));
|
||||||
|
assertEquals("B", t.getColumnName(1));
|
||||||
|
assertEquals("C", t.getColumnName(2));
|
||||||
|
assertTrue(new Value(0).isEqualTo(t.getValue(0, 0)));
|
||||||
|
assertTrue(new Value(1).isEqualTo(t.getValue(1, 1)));
|
||||||
|
assertTrue(new Value("Z").isEqualTo(t.getValue(1, 2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCSV() throws Exception {
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
t.saveCSV(new BufferedWriter(sw));
|
||||||
|
assertEquals("\"step\",\"A\",\"B\",\"C\"\n" +
|
||||||
|
"\"0\",\"0\",\"0\",\"0\"\n" +
|
||||||
|
"\"1\",\"0\",\"1\",\"Z\"\n", sw.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMax() {
|
||||||
|
ValueTable t = new ValueTable("A", "B", "C")
|
||||||
|
.add(new Value[]{new Value(0), new Value(4), new Value(1)})
|
||||||
|
.add(new Value[]{new Value(1), new Value(0), new Value(3)})
|
||||||
|
.add(new Value[]{new Value(2), new Value(0), new Value(1)})
|
||||||
|
.add(new Value[]{new Value(1), new Value(0), new Value(1)});
|
||||||
|
assertEquals(2,t.getMax(0));
|
||||||
|
assertEquals(4,t.getMax(1));
|
||||||
|
assertEquals(3,t.getMax(2));
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user