Version 2: Abstraction of graphs & new implementations: JZY3D, JavaFX, JFreeChart
This commit is contained in:
+33
-7
@@ -2,8 +2,14 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>ch.psi</groupId>
|
||||
<artifactId>plot</artifactId>
|
||||
<version>1.1.31</version>
|
||||
|
||||
<version>2.0-SNAPSHOT</version>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jzy3d-releases</id>
|
||||
<name>Jzy3d Snapshots</name>
|
||||
<url>http://www.jzy3d.org/maven/releases</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jfree</groupId>
|
||||
@@ -16,18 +22,29 @@
|
||||
<version>4.8.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependency>
|
||||
<groupId>fr.esrf.tangoatk.widget.util.chart</groupId>
|
||||
<artifactId>JLChart</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jzy3d</groupId>
|
||||
<artifactId>jzy3d-api</artifactId>
|
||||
<version>0.9.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<encoding>UTF-8</encoding>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugin>
|
||||
<!-- Generate Javadoc Jar -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
@@ -39,6 +56,9 @@
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<additionalparam>-Xdoclint:none</additionalparam>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
@@ -55,7 +75,7 @@
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
@@ -71,4 +91,10 @@
|
||||
<url>http://yoke/artifactory/libs-releases-local</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
<!-- G
|
||||
<properties>
|
||||
<maven.compiler.source>1.7</maven.compiler.source>
|
||||
<maven.compiler.target>1.7</maven.compiler.target>
|
||||
</properties>
|
||||
-->
|
||||
</project>
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot;
|
||||
|
||||
import ch.psi.plot.Plot.AxisId;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class Axis {
|
||||
|
||||
PlotBase plot;
|
||||
AxisId id;
|
||||
|
||||
Axis(String label, PlotBase plot, AxisId id) {
|
||||
this.plot = plot;
|
||||
this.id = id;
|
||||
if (label == null) {
|
||||
label = "";
|
||||
}
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
String label = "";
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setLabel(String value) {
|
||||
label = value;
|
||||
plot.onAxisLabelChanged(id);
|
||||
}
|
||||
|
||||
double min;
|
||||
|
||||
public double getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public void setMin(double value) {
|
||||
min = value;
|
||||
plot.onAxisRangeChanged(id);
|
||||
}
|
||||
|
||||
double max;
|
||||
|
||||
public double getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public void setMax(double value) {
|
||||
max = value;
|
||||
plot.onAxisRangeChanged(id);
|
||||
}
|
||||
|
||||
public void setRange(double min, double max) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
plot.onAxisRangeChanged(id);
|
||||
}
|
||||
|
||||
public boolean isAutoRange() {
|
||||
return (max <= min);
|
||||
}
|
||||
|
||||
public void setAutoRange() {
|
||||
setRange(0, 0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public interface LinePlot extends Plot<LinePlotSeries> {
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot;
|
||||
|
||||
import ch.psi.plot.LinePlotSeries.LinePlotSeriesListener;
|
||||
import ch.psi.plot.utils.IO;
|
||||
import ch.psi.plot.utils.SwingUtils;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.IOException;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
|
||||
/**
|
||||
* TODO: FDA calls to .update -> requestUpdate()
|
||||
*/
|
||||
abstract public class LinePlotBase extends PlotBase<LinePlotSeries> implements LinePlot {
|
||||
|
||||
private String xAxisLabel = "X";
|
||||
private String yAxisLabel = "Y";
|
||||
|
||||
protected LinePlotBase() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
protected LinePlotBase(String title) {
|
||||
super(LinePlotSeries.class, title);
|
||||
createAxis(AxisId.X, "X");
|
||||
createAxis(AxisId.Y, "Y");
|
||||
|
||||
}
|
||||
|
||||
//TODO: Improve it to share the same X rows
|
||||
@Override
|
||||
public void saveData(String filename) throws IOException {
|
||||
StringBuilder str = new StringBuilder(1024);
|
||||
|
||||
int numberSeries = getAllSeries().length;
|
||||
|
||||
str.append(getAxis(AxisId.X).getLabel().isEmpty() ? "X" : getAxis(AxisId.X).getLabel()).append(FIELD_SEPARATOR);
|
||||
for (LinePlotSeries series : getAllSeries()) {
|
||||
str.append(series.getName()).append(FIELD_SEPARATOR);
|
||||
}
|
||||
str.append(LINE_SEPARATOR);
|
||||
|
||||
int seriesIndex = 0;
|
||||
for (LinePlotSeries series : getAllSeries()) {
|
||||
double[][] data = getSeriesData(series);
|
||||
for (int i = 0; i < data[0].length; i++) {
|
||||
double x = data[0][i];
|
||||
double y = data[1][i];
|
||||
str.append(String.format("%1.6f", x)).append(FIELD_SEPARATOR);
|
||||
for (int j = 0; j < seriesIndex; j++) {
|
||||
str.append(String.format("NaN", x)).append(FIELD_SEPARATOR);
|
||||
}
|
||||
str.append(String.format("%1.6f", y)).append(FIELD_SEPARATOR);
|
||||
for (int j = seriesIndex + 1; j < numberSeries; j++) {
|
||||
str.append(String.format("NaN", x)).append(FIELD_SEPARATOR);
|
||||
}
|
||||
str.append(LINE_SEPARATOR);
|
||||
}
|
||||
seriesIndex++;
|
||||
}
|
||||
IO.writeStringToFile(filename, str.toString());
|
||||
}
|
||||
|
||||
final LinePlotSeriesListener seriesListener = new LinePlotSeriesListener() {
|
||||
@Override
|
||||
public void onSeriesAppendData(LinePlotSeries series, double x, double y) {
|
||||
onAppendData(series, x, y);
|
||||
if (getRequireUpdateOnAppend() && isUpdatesEnabled()) {
|
||||
requestSeriesUpdate(series);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSeriesSetData(LinePlotSeries series, double[] x, double[] y) {
|
||||
if (y == null) {
|
||||
y = new double[0];
|
||||
}
|
||||
if ((x == null) || (y.length != x.length)) {
|
||||
x = new double[y.length];
|
||||
for (int i = 0; i < x.length; i++) {
|
||||
x[i] = i;
|
||||
}
|
||||
}
|
||||
onSetData(series, x, y);
|
||||
if (isUpdatesEnabled()) {
|
||||
requestSeriesUpdate(series);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a token to reference underlying data from LinePlotSeries
|
||||
*/
|
||||
abstract protected void onAppendData(LinePlotSeries series, double x, double y);
|
||||
|
||||
abstract protected void onSetData(LinePlotSeries series, double[] x, double[] y);
|
||||
|
||||
//Injecting specific entries in popup menu
|
||||
@Override
|
||||
protected void onCreatedPanel() {
|
||||
addPopupMenuItem(null);//Separator
|
||||
// Detach plot into a separate frame
|
||||
JMenu detachPlotMenu = new JMenu("Detach");
|
||||
String[] implementations = getImplementations();
|
||||
JMenuItem[] detachPlotMenuItems = new JMenuItem[implementations.length];
|
||||
|
||||
ActionListener listener = new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
LinePlot p = newPlot(e.getActionCommand());
|
||||
p.setTitle(getTitle());
|
||||
p.getAxis(AxisId.X).setLabel(getAxis(AxisId.X).getLabel());
|
||||
p.getAxis(AxisId.Y).setLabel(getAxis(AxisId.Y).getLabel());
|
||||
for (LinePlotSeries series : getAllSeries()) {
|
||||
LinePlotSeries detachedSeries = new LinePlotSeries(series.getName(), series.getColor());
|
||||
p.addSeries(detachedSeries);
|
||||
detachedSeries.setData(series.getX(), series.getY());
|
||||
}
|
||||
|
||||
JFrame frame = new JFrame(getTitle());
|
||||
frame.setContentPane(p.getChartPanel());
|
||||
frame.pack();
|
||||
SwingUtils.centerOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
} catch (Exception ex) {
|
||||
SwingUtils.showException(getChartPanel(), ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (int i=0;i<implementations.length;i++){
|
||||
detachPlotMenuItems[i] = new JMenuItem(implementations[i]);
|
||||
detachPlotMenuItems[i].addActionListener(listener);
|
||||
detachPlotMenu.add(detachPlotMenuItems[i]);
|
||||
}
|
||||
addPopupMenuItem(detachPlotMenu);
|
||||
}
|
||||
|
||||
// Known Implemenmtations
|
||||
//TODO: Should add reflection & dynamic including classes?
|
||||
public static LinePlot newPlot(String impl) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
|
||||
return (LinePlot) (Class.forName( "ch.psi.plot." + impl + ".LinePlot")).newInstance();
|
||||
}
|
||||
|
||||
public static String[] getImplementations(){
|
||||
return new String[]{"jfree", "jlchart", "javafx"};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot;
|
||||
|
||||
import ch.psi.plot.utils.SwingUtils;
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class LinePlotSeries extends PlotSeries<LinePlot> {
|
||||
|
||||
public interface LinePlotSeriesListener {
|
||||
|
||||
void onSeriesSetData(LinePlotSeries series, double[] x, double[] y);
|
||||
|
||||
void onSeriesAppendData(LinePlotSeries series, double x, double y);
|
||||
}
|
||||
|
||||
public LinePlotSeries(String name) {
|
||||
this(name, SwingUtils.generateRandomColor());
|
||||
}
|
||||
|
||||
public LinePlotSeries(String name, Color color) {
|
||||
super(name);
|
||||
setColor(color);
|
||||
}
|
||||
|
||||
private Color color;
|
||||
|
||||
void setColor(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
private int axisY = 1;
|
||||
|
||||
void setAxisY(int axis) {
|
||||
this.axisY = axisY;
|
||||
}
|
||||
|
||||
public int getAxisY() {
|
||||
return axisY;
|
||||
}
|
||||
|
||||
public void setData(double[] x, double[] y) {
|
||||
if (getPlot() != null) {
|
||||
((LinePlotBase) getPlot()).seriesListener.onSeriesSetData(this, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
public void appendData(double x, double y) {
|
||||
if (getPlot() != null) {
|
||||
((LinePlotBase) getPlot()).seriesListener.onSeriesAppendData(this, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
setData(new double[0], new double[0]);
|
||||
}
|
||||
|
||||
public double[] getX() {
|
||||
if (getPlot() == null) {
|
||||
return new double[0];
|
||||
}
|
||||
return getPlot().getSeriesData(this)[0];
|
||||
}
|
||||
|
||||
public double[] getY() {
|
||||
if (getPlot() == null) {
|
||||
return new double[0];
|
||||
}
|
||||
return getPlot().getSeriesData(this)[1];
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
if (getPlot() == null) {
|
||||
return 0;
|
||||
}
|
||||
return getPlot().getSeriesData(this)[0].length;
|
||||
}
|
||||
|
||||
//Tools
|
||||
public double getAverage() {
|
||||
double average = 0.0;
|
||||
for (double y : getY()) {
|
||||
average = average + y;
|
||||
}
|
||||
return average / getCount();
|
||||
}
|
||||
|
||||
public double[] getMinimum() {
|
||||
double min = Double.NaN;
|
||||
double xmin = Double.NaN;
|
||||
double[][] data = getPlot().getSeriesData(this);
|
||||
double[] x = data[0];
|
||||
double[] y = data[1];
|
||||
|
||||
for (int i = 0; i < x.length; i++) {
|
||||
if (Double.isNaN(min) || (y[i] < min)) {
|
||||
min = y[i];
|
||||
xmin = x[i];
|
||||
}
|
||||
}
|
||||
return new double[]{xmin, min};
|
||||
}
|
||||
|
||||
public double[] getMaximum() {
|
||||
double max = Double.NaN;
|
||||
double xmax = Double.NaN;
|
||||
double[][] data = getPlot().getSeriesData(this);
|
||||
double[] x = data[0];
|
||||
double[] y = data[1];
|
||||
|
||||
for (int i = 0; i < x.length; i++) {
|
||||
if (Double.isNaN(max) || (y[i] > max)) {
|
||||
max = y[i];
|
||||
xmax = x[i];
|
||||
}
|
||||
}
|
||||
return new double[]{xmax, max};
|
||||
}
|
||||
|
||||
public double[][] getDerivative() {
|
||||
if (getCount() <= 2) {
|
||||
return new double[][]{new double[0], new double[0]};
|
||||
}
|
||||
double[][] data = getPlot().getSeriesData(this);
|
||||
double[] x = data[0];
|
||||
double[] y = data[1];
|
||||
|
||||
double[] dx = new double[getCount() - 2];
|
||||
double[] dy = new double[getCount() - 2];
|
||||
|
||||
for (int i = 1; i < getCount() - 1; i++) { // do not start at 0 but 1 - stop 1 before end
|
||||
double xi = x[i];
|
||||
double ximinus1 = x[i - 1];
|
||||
double xiplus1 = x[i + 1];
|
||||
double yiminus1 = y[i - 1];
|
||||
double yiplus1 = y[i + 1];
|
||||
|
||||
if (xiplus1 - ximinus1 != 0.0) {
|
||||
double di = (yiplus1 - yiminus1) / (xiplus1 - ximinus1);
|
||||
dx[i - 1] = xi;
|
||||
dy[i - 1] = di;
|
||||
} else {
|
||||
dx[i - 1] = xi;
|
||||
dy[i - 1] = Double.NaN;
|
||||
}
|
||||
}
|
||||
|
||||
return new double[][]{dx, dy};
|
||||
}
|
||||
|
||||
public double[][] getIntegral() {
|
||||
if (getCount() <= 1) {
|
||||
return new double[][]{new double[0], new double[0]};
|
||||
}
|
||||
double[][] data = getPlot().getSeriesData(this);
|
||||
double[] x = data[0];
|
||||
double[] y = data[1];
|
||||
|
||||
double[] ix = new double[getCount() - 1];
|
||||
double[] iy = new double[getCount() - 1];
|
||||
double value = 0.0;
|
||||
|
||||
for (int i = 1; i < getCount(); i++) { // Leave out 1. point
|
||||
value += (x[i] - x[i - 1]) * (y[i] + y[i - 1]) / 2.0;
|
||||
ix[i - 1] = x[i];
|
||||
iy[i - 1] = value;
|
||||
}
|
||||
return new double[][]{ix, iy};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public interface MatrixPlot extends Plot<MatrixPlotSeries> {
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot;
|
||||
|
||||
import ch.psi.plot.MatrixPlotSeries.MatrixPlotSeriesListener;
|
||||
import ch.psi.plot.utils.IO;
|
||||
import ch.psi.plot.utils.SwingUtils;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
abstract public class MatrixPlotBase extends PlotBase<MatrixPlotSeries> implements MatrixPlot {
|
||||
|
||||
protected MatrixPlotBase() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
protected MatrixPlotBase(String title) {
|
||||
super(MatrixPlotSeries.class, title);
|
||||
createAxis(AxisId.X, "X");
|
||||
createAxis(AxisId.Y, "Y");
|
||||
createAxis(AxisId.Z);
|
||||
}
|
||||
|
||||
//Only supporting one series for now so let's gain some speed
|
||||
@Override
|
||||
public void addSeries(MatrixPlotSeries series) {
|
||||
if (getAllSeries().length > 0) {
|
||||
removeSeries(getAllSeries()[0]);
|
||||
}
|
||||
super.addSeries(series);
|
||||
|
||||
}
|
||||
|
||||
final MatrixPlotSeriesListener seriesListener = new MatrixPlotSeriesListener() {
|
||||
@Override
|
||||
public void onSeriesAppendData(MatrixPlotSeries series, double x, double y, double z) {
|
||||
|
||||
if ((series == null) || (getNumberOfSeries() == 0)) {
|
||||
return;
|
||||
}
|
||||
final int indexX = ((int) ((x - series.getMinX()) / series.getBinWidthX()));
|
||||
final int indexY = ((int) ((y - series.getMinY()) / series.getBinWidthY()));
|
||||
if (!series.contains(indexX, indexY)) {
|
||||
return;
|
||||
}
|
||||
onAppendData(series, indexX, indexY, x, y, z);
|
||||
if (getRequireUpdateOnAppend() && isUpdatesEnabled()) {
|
||||
requestSeriesUpdate(series);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSeriesSetData(MatrixPlotSeries series, double[][] data) {
|
||||
if ((series == null) || (getNumberOfSeries() == 0)) {
|
||||
return;
|
||||
}
|
||||
//TODO: Check consistency of z
|
||||
onSetData(series, data);
|
||||
if (isUpdatesEnabled()) {
|
||||
requestSeriesUpdate(series);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public void saveData(String filename) throws IOException {
|
||||
if (getAllSeries().length == 0) {
|
||||
return;
|
||||
}
|
||||
MatrixPlotSeries series = getAllSeries()[0];
|
||||
StringBuilder str = new StringBuilder(1024);
|
||||
|
||||
str.append(getAxis(AxisId.X).getLabel().isEmpty() ? "X" : getAxis(AxisId.X).getLabel()).append(FIELD_SEPARATOR);
|
||||
str.append(getAxis(AxisId.Y).getLabel().isEmpty() ? "Y" : getAxis(AxisId.Y).getLabel()).append(FIELD_SEPARATOR);
|
||||
str.append(getAxis(AxisId.Z).getLabel().isEmpty() ? "Z" : getAxis(AxisId.Z).getLabel()).append(LINE_SEPARATOR);
|
||||
|
||||
double[][] data = getSeriesData(getAllSeries()[0]);
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
for (int j = 0; j < data[0].length; j++) {
|
||||
double y = series.getMinY() + i * series.getBinWidthY();
|
||||
double x = series.getMinX() + j * series.getBinWidthX();
|
||||
double z = data[i][j];
|
||||
str.append(String.format("%1.6f", x)).append(FIELD_SEPARATOR);
|
||||
str.append(String.format("%1.6f", y)).append(FIELD_SEPARATOR);
|
||||
str.append(String.format("%1.6f", z)).append(LINE_SEPARATOR);
|
||||
}
|
||||
}
|
||||
IO.writeStringToFile(filename, str.toString());
|
||||
}
|
||||
|
||||
//Injecting specific entries in popup menu
|
||||
@Override
|
||||
protected void onCreatedPanel() {
|
||||
addPopupMenuItem(null);//Separator
|
||||
// Detach plot into a separate frame
|
||||
JMenu detachPlotMenu = new JMenu("Detach");
|
||||
String[] implementations = getImplementations();
|
||||
JMenuItem[] detachPlotMenuItems = new JMenuItem[implementations.length];
|
||||
|
||||
ActionListener listener = new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
if (getAllSeries().length == 0) {
|
||||
return;
|
||||
}
|
||||
MatrixPlotSeries s = getAllSeries()[0];
|
||||
MatrixPlot p = newPlot(e.getActionCommand());
|
||||
p.setTitle(getTitle());
|
||||
p.getAxis(AxisId.X).setLabel(getAxis(AxisId.X).getLabel());
|
||||
p.getAxis(AxisId.Y).setLabel(getAxis(AxisId.Y).getLabel());
|
||||
p.getAxis(AxisId.Z).setLabel(getAxis(AxisId.Z).getLabel());
|
||||
MatrixPlotSeries detachedSeries = new MatrixPlotSeries(null, s.getMinX(), s.getMaxX(), s.getNumberOfBinsX(), s.getMinY(), s.getMaxY(), s.getNumberOfBinsY());
|
||||
p.addSeries(detachedSeries);
|
||||
detachedSeries.setData(s.getData());
|
||||
|
||||
JFrame frame = new JFrame(getTitle());
|
||||
frame.setContentPane(p.getChartPanel());
|
||||
frame.pack();
|
||||
SwingUtils.centerOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
} catch (Exception ex) {
|
||||
SwingUtils.showException(getChartPanel(), ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
for (int i=0;i<implementations.length;i++){
|
||||
detachPlotMenuItems[i] = new JMenuItem(implementations[i]);
|
||||
detachPlotMenuItems[i].addActionListener(listener);
|
||||
detachPlotMenu.add(detachPlotMenuItems[i]);
|
||||
}
|
||||
addPopupMenuItem(detachPlotMenu);
|
||||
}
|
||||
|
||||
//abstract protected Object onSetSeries(MatrixPlotSeries series);
|
||||
abstract protected void onAppendData(MatrixPlotSeries series, int indexX, int indexY, double x, double y, double z);
|
||||
|
||||
abstract protected void onSetData(MatrixPlotSeries series, double[][] data);
|
||||
|
||||
|
||||
// Known Implemenmtations
|
||||
//TODO: Should add reflection & dynamic including classes? Should factorize in PlotBase?
|
||||
|
||||
public static MatrixPlot newPlot(String impl) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
|
||||
return (MatrixPlot) (Class.forName( "ch.psi.plot." + impl + ".MatrixPlot")).newInstance();
|
||||
}
|
||||
|
||||
public static String[] getImplementations(){
|
||||
return new String[]{"jfree", "jzy3d"};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package ch.psi.plot;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* PlotData implementation optimized for matrix data.
|
||||
*/
|
||||
public class MatrixPlotSeries extends PlotSeries<MatrixPlot> {
|
||||
|
||||
public interface MatrixPlotSeriesListener {
|
||||
|
||||
void onSeriesSetData(MatrixPlotSeries series, double[][] data);
|
||||
|
||||
void onSeriesAppendData(MatrixPlotSeries series, double x, double y, double z);
|
||||
}
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MatrixPlotSeries.class.getName());
|
||||
|
||||
private final double minX;
|
||||
private final double maxX;
|
||||
private final int numberOfBinsX;
|
||||
private final double binWidthX;
|
||||
|
||||
private final double minY;
|
||||
private final double maxY;
|
||||
private final int numberOfBinsY;
|
||||
private final double binWidthY;
|
||||
|
||||
public MatrixPlotSeries(String name, double minX, double maxX, int nX, double minY, double maxY, int nY) {
|
||||
super(name);
|
||||
|
||||
this.minX = minX;
|
||||
this.maxX = maxX;
|
||||
this.numberOfBinsX = nX;
|
||||
|
||||
this.minY = minY;
|
||||
this.maxY = maxY;
|
||||
this.numberOfBinsY = nY;
|
||||
|
||||
this.binWidthX = (maxX - minX) / (double) (numberOfBinsX - 1);
|
||||
this.binWidthY = (maxY - minY) / (double) (numberOfBinsY - 1);
|
||||
|
||||
}
|
||||
|
||||
public void setData(double[][] data) {
|
||||
if ((data == null) || (data.length != numberOfBinsY) || (data[0].length != numberOfBinsX)) {
|
||||
data = new double[numberOfBinsY][numberOfBinsX];
|
||||
for (int i = 0; i < numberOfBinsY; i++) {
|
||||
Arrays.fill(data[i], Double.NaN);
|
||||
}
|
||||
}
|
||||
if (getPlot() != null) {
|
||||
((MatrixPlotBase) getPlot()).seriesListener.onSeriesSetData(this, data);
|
||||
}
|
||||
}
|
||||
|
||||
public void appendData(double x, double y, double z) {
|
||||
if (getPlot() != null) {
|
||||
((MatrixPlotBase) getPlot()).seriesListener.onSeriesAppendData(this, x, y, z);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public double[][] getData() {
|
||||
if (getPlot() == null) {
|
||||
return new double[0][0];
|
||||
}
|
||||
return getPlot().getSeriesData(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
setData(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the binWidthX
|
||||
*/
|
||||
public double getBinWidthX() {
|
||||
return binWidthX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the binWidthY
|
||||
*/
|
||||
public double getBinWidthY() {
|
||||
return binWidthY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the minX
|
||||
*/
|
||||
public double getMinX() {
|
||||
return minX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the maxX
|
||||
*/
|
||||
public double getMaxX() {
|
||||
return maxX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the minY
|
||||
*/
|
||||
public double getMinY() {
|
||||
return minY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the maxY
|
||||
*/
|
||||
public double getMaxY() {
|
||||
return maxY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the numberOfBinsX
|
||||
*/
|
||||
public int getNumberOfBinsX() {
|
||||
return numberOfBinsX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the numberOfBinsY
|
||||
*/
|
||||
public int getNumberOfBinsY() {
|
||||
return numberOfBinsY;
|
||||
}
|
||||
|
||||
//Utilities
|
||||
public boolean contains(int indexX, int indexY) {
|
||||
return ((indexX <= numberOfBinsX) && (indexX >= 0) && (indexY <= numberOfBinsY) && (indexY >= 0));
|
||||
|
||||
}
|
||||
|
||||
public double[] minMaxZValue() {
|
||||
|
||||
double min = Double.NaN;
|
||||
double max = Double.NaN;
|
||||
|
||||
double[][] data = getData();
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
for (int j = 0; j < data[0].length; j++) {
|
||||
if (data[i][j] != Double.NEGATIVE_INFINITY) {
|
||||
if (Double.isNaN(min) || (data[i][j] < min)) {
|
||||
min = data[i][j];
|
||||
}
|
||||
if (Double.isNaN(max) || (data[i][j] > max)) {
|
||||
max = data[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new double[]{min, max};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,42 +1,65 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
|
||||
package ch.psi.plot;
|
||||
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
public interface Plot {
|
||||
/**
|
||||
* Get the chart panel
|
||||
* @return
|
||||
*/
|
||||
public ChartPanel getChartPanel();
|
||||
|
||||
/**
|
||||
* Get chart of the plot (e.g. to be able to export the chart as an image)
|
||||
* @return
|
||||
*/
|
||||
public JFreeChart getChart();
|
||||
|
||||
/**
|
||||
* Update plot (notify all components of the plot)
|
||||
*/
|
||||
public void update();
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public interface Plot<T extends PlotSeries> {
|
||||
|
||||
public JPanel getChartPanel();
|
||||
|
||||
//Request update on event loop
|
||||
public void update(boolean deferred);
|
||||
|
||||
public void setUpdatesEnabled(boolean value);
|
||||
|
||||
public boolean isUpdatesEnabled();
|
||||
|
||||
//Generic properties
|
||||
public void setTitle(String title);
|
||||
|
||||
public String getTitle();
|
||||
|
||||
//Generic operations
|
||||
public void saveData(String filename) throws IOException;
|
||||
|
||||
public BufferedImage getSnapshot();
|
||||
|
||||
public void saveSnapshot(String filename, String format) throws IOException;
|
||||
|
||||
//Series list management
|
||||
public void addSeries(T series);
|
||||
|
||||
public void addSeries(T[] series);
|
||||
|
||||
public void removeSeries(T series);
|
||||
|
||||
public T getSeries(String name);
|
||||
|
||||
public T getSeries(int index);
|
||||
|
||||
public int getNumberOfSeries();
|
||||
|
||||
public void updateSeries(T series);
|
||||
|
||||
public void requestSeriesUpdate(final T series);
|
||||
|
||||
public double[][] getSeriesData(final T series);
|
||||
|
||||
public T[] getAllSeries();
|
||||
|
||||
public void clear(); //remove all series
|
||||
|
||||
//Axis
|
||||
public enum AxisId {
|
||||
X, Y, Z;
|
||||
};
|
||||
|
||||
public Axis getAxis(AxisId id);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot;
|
||||
|
||||
import ch.psi.plot.utils.IO;
|
||||
import ch.psi.plot.utils.SwingUtils;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
abstract public class PlotBase<T extends PlotSeries> implements Plot<T> {
|
||||
static{
|
||||
javax.swing.JPopupMenu.setDefaultLightWeightPopupEnabled(false);
|
||||
}
|
||||
|
||||
final String LINE_SEPARATOR = System.lineSeparator();
|
||||
final String FIELD_SEPARATOR = "\t";
|
||||
|
||||
final Class seriesType;
|
||||
|
||||
protected PlotBase(Class<T> seriesType) {
|
||||
this(seriesType, null);
|
||||
|
||||
}
|
||||
|
||||
protected PlotBase(Class<T> seriesType, String title) {
|
||||
if (title == null) {
|
||||
title = "Plot";
|
||||
}
|
||||
setTitle(title);
|
||||
this.seriesType = seriesType;
|
||||
}
|
||||
|
||||
String title;
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
volatile boolean bUpdating;
|
||||
|
||||
public final void update(boolean deferred) {
|
||||
if ((!deferred) && SwingUtilities.isEventDispatchThread()) {
|
||||
bUpdating = false;
|
||||
doUpdate();
|
||||
} else {
|
||||
if (!bUpdating) {
|
||||
bUpdating = true;
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (bUpdating) {
|
||||
bUpdating = false;
|
||||
try {
|
||||
doUpdate();
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(PlotBase.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean requireUpdateOnAppend = true;
|
||||
|
||||
protected void setRequireUpdateOnAppend(boolean value) {
|
||||
requireUpdateOnAppend = value;
|
||||
}
|
||||
|
||||
protected boolean getRequireUpdateOnAppend() {
|
||||
return requireUpdateOnAppend;
|
||||
}
|
||||
|
||||
boolean updatesEnabled = true;
|
||||
|
||||
public void setUpdatesEnabled(boolean value) {
|
||||
updatesEnabled = value;
|
||||
}
|
||||
|
||||
public boolean isUpdatesEnabled() {
|
||||
return updatesEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should be improved in implementations to make it independent of the
|
||||
* window state;
|
||||
*/
|
||||
public BufferedImage getSnapshot() {
|
||||
return SwingUtils.createImage(getChartPanel());
|
||||
}
|
||||
|
||||
public void saveSnapshot(String filename, String format) throws IOException {
|
||||
IO.writeImageToFile(getSnapshot(), filename, format);
|
||||
}
|
||||
|
||||
JPanel panel;
|
||||
|
||||
public JPanel getChartPanel() {
|
||||
if (panel == null) {
|
||||
panel = createChartPanel();
|
||||
|
||||
addPopupMenuItem(null);//Separator
|
||||
JMenuItem saveData = new JMenuItem("Save Data");
|
||||
saveData.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
JFileChooser chooser = new JFileChooser();
|
||||
FileNameExtensionFilter filter = new FileNameExtensionFilter("Text data files", "txt", "dat");
|
||||
chooser.setFileFilter(filter);
|
||||
int returnVal = chooser.showSaveDialog(panel);
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||
String filename = chooser.getSelectedFile().getAbsolutePath();
|
||||
String type = IO.getExtension(chooser.getSelectedFile());
|
||||
if (type == null) {
|
||||
type = "txt";
|
||||
filename += "." + type;
|
||||
}
|
||||
saveData(filename);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
SwingUtils.showException(panel, ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
addPopupMenuItem(saveData);
|
||||
JMenuItem saveSnapshot = new JMenuItem("Save Snapshot");
|
||||
saveSnapshot.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
JFileChooser chooser = new JFileChooser();
|
||||
FileNameExtensionFilter filter = new FileNameExtensionFilter("Image File", "png", "jpg", "bmp");
|
||||
chooser.setFileFilter(filter);
|
||||
int returnVal = chooser.showSaveDialog(panel);
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||
String filename = chooser.getSelectedFile().getAbsolutePath();
|
||||
String type = IO.getExtension(chooser.getSelectedFile());
|
||||
if (type == null) {
|
||||
type = "png";
|
||||
filename += "." + type;
|
||||
}
|
||||
saveSnapshot(filename, type);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
SwingUtils.showException(panel, ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
addPopupMenuItem(saveSnapshot);
|
||||
onCreatedPanel();
|
||||
}
|
||||
return panel;
|
||||
}
|
||||
|
||||
//Overidables
|
||||
protected void onCreatedPanel() {
|
||||
}
|
||||
|
||||
abstract protected JPanel createChartPanel();
|
||||
|
||||
/**
|
||||
* null for separator
|
||||
*/
|
||||
abstract protected void addPopupMenuItem(JMenuItem item);
|
||||
|
||||
//Series list support
|
||||
final HashMap<String, T> seriesList = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void addSeries(T series) {
|
||||
if (series.name == null) {
|
||||
return;
|
||||
}
|
||||
T existingSeries = getSeries(series.name);
|
||||
if (existingSeries == series) {
|
||||
return;
|
||||
}
|
||||
if (existingSeries != null) {
|
||||
removeSeries(existingSeries);
|
||||
}
|
||||
synchronized (seriesList) {
|
||||
seriesList.put(series.name, series);
|
||||
}
|
||||
series.setPlot(this);
|
||||
series.setToken(onAddedSeries(series));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSeries(T[] series) {
|
||||
for (T s : series) {
|
||||
addSeries(s);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSeries(T series) {
|
||||
if (series.getPlot() == this) {
|
||||
series.setPlot(null);
|
||||
}
|
||||
onRemovedSeries(series);
|
||||
synchronized (seriesList) {
|
||||
seriesList.remove(series.name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getSeries(String name) {
|
||||
synchronized (seriesList) {
|
||||
return seriesList.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Not respecting order
|
||||
@Override
|
||||
public T getSeries(int index) {
|
||||
synchronized (seriesList) {
|
||||
if ((index < 0) || (index >= seriesList.size())) {
|
||||
return null;
|
||||
}
|
||||
return seriesList.get(getAllSeries()[index]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfSeries() {
|
||||
return seriesList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T[] getAllSeries() {
|
||||
synchronized (seriesList) {
|
||||
ArrayList<T> list = new ArrayList();
|
||||
for (T series : seriesList.values()) {
|
||||
list.add(series);
|
||||
}
|
||||
return list.toArray((T[]) Array.newInstance(seriesType, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestSeriesUpdate(final T series) {
|
||||
if (!series.updating) {
|
||||
series.updating = true;
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
series.updating = false;
|
||||
try {
|
||||
updateSeries(series);
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(LinePlotBase.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected Object onAddedSeries(T series);
|
||||
|
||||
abstract protected void onRemovedSeries(T series);
|
||||
|
||||
/**
|
||||
* These overridables can be optimised in implementations
|
||||
*/
|
||||
protected void onRemovedAllSeries() {
|
||||
for (T s : getAllSeries()) {
|
||||
removeSeries(s);
|
||||
}
|
||||
}
|
||||
|
||||
protected void doUpdate() {
|
||||
for (T s : getAllSeries()) {
|
||||
updateSeries(s);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
onRemovedAllSeries();
|
||||
synchronized (seriesList) {
|
||||
seriesList.clear();
|
||||
}
|
||||
update(true);
|
||||
}
|
||||
|
||||
//Axis
|
||||
final HashMap<AxisId, Axis> axisList = new HashMap<>();
|
||||
|
||||
protected void createAxis(AxisId axis) {
|
||||
createAxis(axis, null);
|
||||
}
|
||||
|
||||
protected void createAxis(AxisId axis, String label) {
|
||||
axisList.put(axis, new Axis(label, this, axis));
|
||||
}
|
||||
|
||||
public Axis getAxis(AxisId id) {
|
||||
return axisList.get(id);
|
||||
}
|
||||
|
||||
//Axis Callbacks
|
||||
protected void onAxisLabelChanged(AxisId axis) {
|
||||
if (isUpdatesEnabled()) {
|
||||
doUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
protected void onAxisRangeChanged(AxisId axis) {
|
||||
if (isUpdatesEnabled()) {
|
||||
doUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public abstract class PlotSeries<T extends Plot> {
|
||||
|
||||
volatile boolean updating = false;
|
||||
|
||||
protected PlotSeries() {
|
||||
this("");
|
||||
}
|
||||
|
||||
protected PlotSeries(String name) {
|
||||
setName((name == null) ? "" : name);
|
||||
}
|
||||
|
||||
Object token;
|
||||
|
||||
void setToken(Object token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public Object getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
private T plot;
|
||||
|
||||
void setPlot(T plot) {
|
||||
this.plot = plot;
|
||||
}
|
||||
|
||||
public T getPlot() {
|
||||
return plot;
|
||||
}
|
||||
|
||||
String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,625 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot.javafx;
|
||||
|
||||
import ch.psi.plot.LinePlotSeries;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import javafx.animation.AnimationTimer;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.embed.swing.JFXPanel;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.geometry.Point2D;
|
||||
import javafx.scene.Cursor;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.chart.Axis;
|
||||
import javafx.scene.chart.LineChart;
|
||||
import javafx.scene.chart.NumberAxis;
|
||||
import javafx.scene.chart.XYChart;
|
||||
import javafx.scene.chart.XYChart.Data;
|
||||
import javafx.scene.chart.XYChart.Series;
|
||||
import javafx.scene.control.CheckMenuItem;
|
||||
import javafx.scene.control.ContextMenu;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Menu;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.control.SeparatorMenuItem;
|
||||
import javafx.scene.input.MouseButton;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.shape.Rectangle;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class LinePlot extends ch.psi.plot.LinePlotBase {
|
||||
|
||||
final boolean HOVERING_SYMBOLS = true;
|
||||
|
||||
public LinePlot() {
|
||||
super();
|
||||
createChart();
|
||||
setRequireUpdateOnAppend(false);
|
||||
}
|
||||
|
||||
final LinkedHashMap<XYChart.Series, ConcurrentLinkedQueue<Data<Number, Number>>> seriesList = new LinkedHashMap<>();
|
||||
|
||||
@Override
|
||||
protected Object onAddedSeries(final LinePlotSeries series) {
|
||||
XYChart.Series chartSeries = new XYChart.Series<Number, Number>();
|
||||
ConcurrentLinkedQueue<Data<Number, Number>> queue = new ConcurrentLinkedQueue<>();
|
||||
chartSeries.setName(series.getName());
|
||||
synchronized (seriesList) {
|
||||
seriesList.put(chartSeries, queue);
|
||||
}
|
||||
update(true);
|
||||
return chartSeries;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemovedSeries(LinePlotSeries series) {
|
||||
XYChart.Series chartSeries = getChartSeries(series);
|
||||
if (chartSeries != null) {
|
||||
synchronized (seriesList) {
|
||||
seriesList.remove(chartSeries);
|
||||
}
|
||||
update(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAppendData(final LinePlotSeries series, final double x, final double y) {
|
||||
XYChart.Series chartSeries = getChartSeries(series);
|
||||
if (chartSeries != null) {
|
||||
synchronized (seriesList) {
|
||||
ConcurrentLinkedQueue<Data<Number, Number>> queue = seriesList.get(chartSeries);
|
||||
Data<Number, Number> dataPoint = new Data<Number, Number>(x, y);
|
||||
queue.add(dataPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetData(LinePlotSeries series, double[] x, double[] y) {
|
||||
XYChart.Series chartSeries = getChartSeries(series);
|
||||
synchronized (seriesList) {
|
||||
ConcurrentLinkedQueue<Data<Number, Number>> queue = seriesList.get(chartSeries);
|
||||
for (int i = 0; i < x.length; i++) {
|
||||
Data<Number, Number> dataPoint = new Data<Number, Number>(x[i], y[i]);
|
||||
queue.add(dataPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSeries(LinePlotSeries series) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public double[][] getSeriesData(LinePlotSeries series) {
|
||||
XYChart.Series s = getChartSeries(series);
|
||||
ObservableList<Data<Number, Number>> list = s.getData();
|
||||
double[] x = new double[list.size()];
|
||||
double[] y = new double[list.size()];
|
||||
int index = 0;
|
||||
for (Data<Number, Number> item : list) {
|
||||
x[index] = item.getXValue().doubleValue();
|
||||
y[index++] = item.getYValue().doubleValue();
|
||||
}
|
||||
return new double[][]{x, y};
|
||||
|
||||
}
|
||||
|
||||
XYChart.Series getChartSeries(LinePlotSeries series) {
|
||||
return (XYChart.Series) (series.getToken());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doUpdate() {
|
||||
if (mTimerFX != null) {
|
||||
Platform.runLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateFX();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static JFXPanel fxContainer;
|
||||
|
||||
@Override
|
||||
protected JPanel createChartPanel() {
|
||||
fxContainer.setPreferredSize(new Dimension(480, 240));
|
||||
JPanel panel = new JPanel();
|
||||
panel.setLayout(new BorderLayout());
|
||||
panel.add(fxContainer);
|
||||
// create JavaFX scene
|
||||
Platform.runLater(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
createScene();
|
||||
}
|
||||
});
|
||||
return panel;
|
||||
}
|
||||
|
||||
class MyLineChart<X extends Object, Y extends Object> extends LineChart<X, Y> {
|
||||
|
||||
public MyLineChart(Axis<X> axis, Axis<Y> axis1) {
|
||||
super(axis, axis1);
|
||||
}
|
||||
|
||||
public void addNode(Node node) {
|
||||
if (node != null) {
|
||||
getPlotChildren().add(node);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeNode(Node node) {
|
||||
if (node != null) {
|
||||
getPlotChildren().remove(node);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void requestChartLayout() {
|
||||
super.requestChartLayout();
|
||||
}
|
||||
}
|
||||
|
||||
private MyLineChart<Number, Number> chart;
|
||||
|
||||
boolean drawSymbols = false;
|
||||
|
||||
public void setDrawSymbols(boolean value) {
|
||||
if (value != drawSymbols) {
|
||||
drawSymbols = value;
|
||||
if (chart != null) {
|
||||
if (HOVERING_SYMBOLS) {
|
||||
for (Iterator<Series<Number, Number>> it = chart.getData().iterator(); it.hasNext();) {
|
||||
XYChart.Series series = it.next();
|
||||
ObservableList<Data<Number, Number>> list = series.getData();
|
||||
for (Data<Number, Number> item : list) {
|
||||
Node symbol = item.getNode();
|
||||
if (symbol != null) {
|
||||
item.setNode(null);
|
||||
chart.removeNode(symbol);
|
||||
}
|
||||
if (drawSymbols) {
|
||||
symbol = new HoveredThresholdNode(series, item.getXValue(), item.getYValue());
|
||||
//symbol = chart.createSymbol(series,chart.getData().indexOf(series), item, itemIndex);
|
||||
item.setNode(symbol);
|
||||
chart.addNode(symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
chart.setCreateSymbols(getDrawSymbols());
|
||||
}
|
||||
|
||||
chart.requestChartLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getDrawSymbols() {
|
||||
return drawSymbols;
|
||||
}
|
||||
|
||||
private void createChart() {
|
||||
fxContainer = new JFXPanel(); //Must do bedore any JavaFX call
|
||||
//xAxis = new NumberAxis(lower,upper,tick);
|
||||
NumberAxis xAxis = new NumberAxis();
|
||||
xAxis.setForceZeroInRange(false);
|
||||
xAxis.setAutoRanging(true);
|
||||
|
||||
xAxis.setTickLabelsVisible(true);
|
||||
xAxis.setTickMarkVisible(true);
|
||||
xAxis.setMinorTickVisible(true);
|
||||
|
||||
NumberAxis yAxis = new NumberAxis();
|
||||
yAxis.setForceZeroInRange(false);
|
||||
yAxis.setAutoRanging(true);
|
||||
|
||||
//-- Chart
|
||||
chart = new MyLineChart<>(xAxis, yAxis);
|
||||
chart.setAnimated(false);
|
||||
chart.setCreateSymbols(false);
|
||||
chart.setCursor(Cursor.CROSSHAIR);
|
||||
}
|
||||
|
||||
Rectangle zoomRect;
|
||||
|
||||
private void createScene() {
|
||||
/*Platform.runLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {*/
|
||||
chart.setId(getTitle());
|
||||
chart.setTitle(getTitle());
|
||||
|
||||
|
||||
final StackPane chartContainer = new StackPane();
|
||||
chartContainer.getChildren().add(chart);
|
||||
zoomRect = new Rectangle();
|
||||
zoomRect.setManaged(false);
|
||||
zoomRect.setFill(Color.LIGHTSEAGREEN.deriveColor(0, 1, 1, 0.5));
|
||||
chartContainer.getChildren().add(zoomRect);
|
||||
|
||||
setUpZooming(zoomRect, chart);
|
||||
setUpContextMenu();
|
||||
fxContainer.setScene(new Scene(chartContainer));
|
||||
|
||||
synchronized (seriesList) {
|
||||
addSeriesToChart();
|
||||
}
|
||||
|
||||
// Every frame to take any data from queue and add to chart
|
||||
mTimerFX = new AnimationTimer() {
|
||||
@Override
|
||||
public void handle(long now) {
|
||||
onTimerFX(now);
|
||||
}
|
||||
};
|
||||
mTimerFX.start();
|
||||
|
||||
/*
|
||||
mTimerFX = new Timeline(new KeyFrame(Duration.millis(200), new EventHandler<ActionEvent>() {
|
||||
|
||||
@Override
|
||||
public void handle(ActionEvent event) {
|
||||
onTimerFX(System.nanoTime());
|
||||
}
|
||||
}));
|
||||
mTimerFX.setCycleCount(Timeline.INDEFINITE);
|
||||
mTimerFX.play();
|
||||
*/
|
||||
/*
|
||||
}
|
||||
});*/
|
||||
}
|
||||
|
||||
//Timeline mTimerFX;
|
||||
AnimationTimer mTimerFX;
|
||||
|
||||
void onTimerFX(long start) {
|
||||
|
||||
synchronized (seriesList) {
|
||||
for (Iterator<Series> it = seriesList.keySet().iterator(); it.hasNext();) {
|
||||
XYChart.Series series = it.next();
|
||||
if (isPlottingSeries(series)) {
|
||||
ConcurrentLinkedQueue<Data<Number, Number>> queue = seriesList.get(series);
|
||||
//int count=0;
|
||||
//while (!queue.isEmpty() && (count++<1000)) {
|
||||
// series.getData().add(queue.remove());
|
||||
//}
|
||||
if (!queue.isEmpty()) {
|
||||
|
||||
if (getDrawSymbols()) {
|
||||
for (Data<Number, Number> d : queue) {
|
||||
d.setNode(new HoveredThresholdNode(series, d.getXValue(), d.getYValue()));
|
||||
}
|
||||
}
|
||||
series.getData().addAll(queue);
|
||||
queue.clear();
|
||||
|
||||
}
|
||||
}
|
||||
if (getElapsedMillis(start) > 200) {
|
||||
return;
|
||||
}
|
||||
|
||||
//xAxis.setLowerBound(xSeriesData-MAX_DATA_POINTS);
|
||||
//xAxis.setUpperBound(xSeriesData-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long getElapsedMillis(long start) {
|
||||
return (System.nanoTime() - start) / 1000000;
|
||||
}
|
||||
|
||||
void updateFX() {
|
||||
synchronized (seriesList) {
|
||||
addSeriesToChart();
|
||||
removeSeriesFromChart();
|
||||
}
|
||||
}
|
||||
|
||||
void addSeriesToChart() {
|
||||
for (Iterator<Series> it = seriesList.keySet().iterator(); it.hasNext();) {
|
||||
XYChart.Series series = it.next();
|
||||
if (!isPlottingSeries(series)) {
|
||||
chart.getData().add(series);
|
||||
|
||||
//Attempt to have a floating label that could speed up rendering of symbol coordinates
|
||||
//Didn't manage to display the label.
|
||||
/*
|
||||
|
||||
final Label label = new Label("");
|
||||
label.setLabelFor(series.getNode());
|
||||
label.getStyleClass().addAll("chart-line-symbol");
|
||||
label.getStyleClass().addAll(series.getNode().getStyleClass());
|
||||
label.setStyle("-fx-font-size: 13; -fx-font-weight: normal;"); ;
|
||||
label.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
|
||||
chart.addNode(label);
|
||||
|
||||
series.getNode().setOnMouseEntered(new EventHandler<MouseEvent>() {
|
||||
@Override public void handle(MouseEvent mouseEvent) {
|
||||
final NumberAxis yAxis = (NumberAxis) chart.getYAxis();
|
||||
final NumberAxis xAxis = (NumberAxis) chart.getXAxis();
|
||||
Point2D xAxisInScene = xAxis.localToScene(0, 0);
|
||||
double xOffset = mouseEvent.getSceneX() - xAxisInScene.getX();
|
||||
double yOffset = mouseEvent.getSceneY() - xAxisInScene.getY();
|
||||
double xAxisScale = xAxis.getScale();
|
||||
double yAxisScale = yAxis.getScale();
|
||||
double x = xAxis.getLowerBound() + xOffset / xAxisScale;
|
||||
double y = yAxis.getLowerBound() + yOffset / yAxisScale;
|
||||
String str="(" + format.format(x) + ", " + format.format(y) +")";
|
||||
|
||||
//System.out.println(str);
|
||||
label.setText(str);
|
||||
label.setVisible(true);
|
||||
label.toFront();
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
series.getNode().setOnMouseExited(new EventHandler<MouseEvent>() {
|
||||
@Override public void handle(MouseEvent mouseEvent) {
|
||||
label.setVisible(false);
|
||||
}
|
||||
});
|
||||
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void removeSeriesFromChart() {
|
||||
for (Iterator<Series<Number, Number>> it = chart.getData().iterator(); it.hasNext();) {
|
||||
XYChart.Series series = it.next();
|
||||
if (!seriesList.keySet().contains(series)) {
|
||||
chart.getData().remove(series);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isPlottingSeries(Series series) {
|
||||
return chart.getData().contains(series);
|
||||
}
|
||||
|
||||
boolean zooming;
|
||||
|
||||
private void setUpZooming(final Rectangle rect, final Node zoomingNode) {
|
||||
final ObjectProperty<Point2D> mouseAnchor = new SimpleObjectProperty<>();
|
||||
zoomingNode.setOnMousePressed(new EventHandler<MouseEvent>() {
|
||||
@Override
|
||||
public void handle(MouseEvent event) {
|
||||
if (event.isControlDown() && (event.getButton() == MouseButton.PRIMARY)) {
|
||||
mouseAnchor.set(new Point2D(event.getX(), event.getY()));
|
||||
zooming = true;
|
||||
rect.setWidth(0);
|
||||
rect.setHeight(0);
|
||||
} else if (event.getButton() == MouseButton.SECONDARY) {
|
||||
contextMenu.show(zoomingNode, event.getScreenX(), event.getScreenY());
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
zoomingNode.setOnMouseDragged(new EventHandler<MouseEvent>() {
|
||||
@Override
|
||||
public void handle(MouseEvent event) {
|
||||
if (event.isControlDown() && zooming) {
|
||||
double x = event.getX();
|
||||
double y = event.getY();
|
||||
rect.setX(Math.min(x, mouseAnchor.get().getX()));
|
||||
rect.setY(Math.min(y, mouseAnchor.get().getY()));
|
||||
rect.setWidth(Math.abs(x - mouseAnchor.get().getX()));
|
||||
rect.setHeight(Math.abs(y - mouseAnchor.get().getY()));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
zoomingNode.setOnMouseReleased(new EventHandler<MouseEvent>() {
|
||||
@Override
|
||||
public void handle(MouseEvent event) {
|
||||
if (event.isControlDown() && zooming) {
|
||||
doZoom(zoomRect, chart);
|
||||
}
|
||||
rect.setWidth(0);
|
||||
rect.setHeight(0);
|
||||
zooming = false;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void doZoom(Rectangle zoomRect, LineChart<Number, Number> chart) {
|
||||
Point2D zoomTopLeft = new Point2D(zoomRect.getX(), zoomRect.getY());
|
||||
Point2D zoomBottomRight = new Point2D(zoomRect.getX() + zoomRect.getWidth(), zoomRect.getY() + zoomRect.getHeight());
|
||||
final NumberAxis yAxis = (NumberAxis) chart.getYAxis();
|
||||
Point2D yAxisInScene = yAxis.localToScene(0, 0);
|
||||
final NumberAxis xAxis = (NumberAxis) chart.getXAxis();
|
||||
if (zoomTopLeft.getX() < yAxisInScene.getX() && zoomTopLeft.getY() < yAxisInScene.getY()) {
|
||||
resetZoom();
|
||||
} else {
|
||||
xAxis.setAutoRanging(false);
|
||||
yAxis.setAutoRanging(false);
|
||||
Point2D xAxisInScene = xAxis.localToScene(0, 0);
|
||||
double xOffset = zoomTopLeft.getX() - yAxisInScene.getX();
|
||||
double yOffset = zoomBottomRight.getY() - xAxisInScene.getY();
|
||||
double xAxisScale = xAxis.getScale();
|
||||
double yAxisScale = yAxis.getScale();
|
||||
xAxis.setLowerBound(xAxis.getLowerBound() + xOffset / xAxisScale);
|
||||
xAxis.setUpperBound(xAxis.getLowerBound() + zoomRect.getWidth() / xAxisScale);
|
||||
yAxis.setLowerBound(yAxis.getLowerBound() + yOffset / yAxisScale);
|
||||
yAxis.setUpperBound(yAxis.getLowerBound() - zoomRect.getHeight() / yAxisScale);
|
||||
// System.out.println(xAxis.getLowerBound() + " " + xAxis.getUpperBound() + " " + yAxis.getLowerBound() + " " + yAxis.getUpperBound());
|
||||
}
|
||||
|
||||
zoomRect.setWidth(0);
|
||||
zoomRect.setHeight(0);
|
||||
}
|
||||
|
||||
private void resetZoom() {
|
||||
|
||||
final NumberAxis yAxis = (NumberAxis) chart.getYAxis();
|
||||
final NumberAxis xAxis = (NumberAxis) chart.getXAxis();
|
||||
|
||||
if (getAxis(AxisId.Y).isAutoRange()) {
|
||||
yAxis.setLowerBound(getAxis(AxisId.Y).getMin());
|
||||
yAxis.setUpperBound(getAxis(AxisId.Y).getMax());
|
||||
yAxis.setAutoRanging(true);
|
||||
|
||||
} else {
|
||||
yAxis.setAutoRanging(false);
|
||||
yAxis.setLowerBound(getAxis(AxisId.Y).getMin());
|
||||
yAxis.setUpperBound(getAxis(AxisId.Y).getMax());
|
||||
}
|
||||
|
||||
if (getAxis(AxisId.X).isAutoRange()) {
|
||||
xAxis.setLowerBound(getAxis(AxisId.X).getMin());
|
||||
xAxis.setUpperBound(getAxis(AxisId.X).getMax());
|
||||
xAxis.setAutoRanging(true);
|
||||
} else {
|
||||
xAxis.setAutoRanging(false);
|
||||
xAxis.setLowerBound(getAxis(AxisId.X).getMin());
|
||||
xAxis.setUpperBound(getAxis(AxisId.X).getMax());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAxisRangeChanged(AxisId axis_id) {
|
||||
NumberAxis axis = null;
|
||||
switch (axis_id) {
|
||||
case X:
|
||||
axis = (NumberAxis) chart.getXAxis();
|
||||
break;
|
||||
case Y:
|
||||
axis = (NumberAxis) chart.getYAxis();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
axis.setAutoRanging(getAxis(axis_id).isAutoRange());
|
||||
axis.setLowerBound(getAxis(axis_id).getMin());
|
||||
axis.setUpperBound(getAxis(axis_id).getMax());
|
||||
}
|
||||
|
||||
ContextMenu contextMenu;
|
||||
|
||||
public void setUpContextMenu() {
|
||||
contextMenu = new ContextMenu();
|
||||
final CheckMenuItem item1 = new CheckMenuItem("Draw Symbols");
|
||||
item1.setSelected(getDrawSymbols());
|
||||
item1.setOnAction(new EventHandler<ActionEvent>() {
|
||||
public void handle(ActionEvent e) {
|
||||
setDrawSymbols(item1.isSelected());
|
||||
}
|
||||
});
|
||||
final CheckMenuItem item2 = new CheckMenuItem("Show Legend");
|
||||
item2.setSelected(chart.isLegendVisible());
|
||||
item2.setOnAction(new EventHandler<ActionEvent>() {
|
||||
public void handle(ActionEvent e) {
|
||||
chart.setLegendVisible(item2.isSelected());
|
||||
}
|
||||
});
|
||||
MenuItem item3 = new MenuItem("Reset Zoom");
|
||||
item3.setOnAction(new EventHandler<ActionEvent>() {
|
||||
public void handle(ActionEvent e) {
|
||||
resetZoom();
|
||||
}
|
||||
});
|
||||
contextMenu.getItems().addAll(item1, item2, item3);
|
||||
}
|
||||
|
||||
DecimalFormat format = new DecimalFormat("#.######");
|
||||
|
||||
class HoveredThresholdNode extends StackPane {
|
||||
|
||||
HoveredThresholdNode(XYChart.Series series, Number x, Number y) {
|
||||
setPrefSize(8, 8);
|
||||
getStyleClass().addAll("chart-line-symbol");
|
||||
getStyleClass().addAll(series.getNode().getStyleClass());
|
||||
|
||||
final Label label = new Label("(" + format.format(x) + ", " + format.format(y) + ")");
|
||||
label.getStyleClass().addAll("chart-line-symbol");
|
||||
label.getStyleClass().addAll(series.getNode().getStyleClass());
|
||||
label.setStyle("-fx-font-size: 13; -fx-font-weight: normal;");
|
||||
//label.setTextFill(Color.FORESTGREEN);
|
||||
label.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
|
||||
setOnMouseEntered(new EventHandler<MouseEvent>() {
|
||||
@Override
|
||||
public void handle(MouseEvent mouseEvent) {
|
||||
getChildren().setAll(label);
|
||||
setCursor(Cursor.NONE);
|
||||
toFront();
|
||||
}
|
||||
});
|
||||
setOnMouseExited(new EventHandler<MouseEvent>() {
|
||||
@Override
|
||||
public void handle(MouseEvent mouseEvent) {
|
||||
getChildren().clear();
|
||||
setCursor(Cursor.CROSSHAIR);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void addSwingMenuItem(final ObservableList<MenuItem> menu, final JMenuItem item) {
|
||||
if (item instanceof JMenu) {
|
||||
Menu menu_fx = new Menu(item.getText());
|
||||
for (Component menuItem : ((JMenu) item).getMenuComponents()) {
|
||||
if (menuItem instanceof JMenu) {
|
||||
addSwingMenuItem(menu_fx.getItems(), ((JMenu) menuItem));
|
||||
} else if (menuItem instanceof JPopupMenu.Separator) {
|
||||
menu_fx.getItems().add(new SeparatorMenuItem());
|
||||
} else if (menuItem instanceof JMenuItem) {
|
||||
addSwingMenuItem(menu_fx.getItems(), ((JMenuItem) menuItem));
|
||||
}
|
||||
}
|
||||
menu.add(menu_fx);
|
||||
} else if (item instanceof JMenuItem) {
|
||||
MenuItem itemFX = new MenuItem(item.getText());
|
||||
itemFX.setOnAction(new EventHandler<ActionEvent>() {
|
||||
public void handle(ActionEvent e) {
|
||||
item.doClick();
|
||||
}
|
||||
});
|
||||
menu.add(itemFX);
|
||||
}
|
||||
}
|
||||
|
||||
protected void addPopupMenuItem(final JMenuItem item) {
|
||||
Platform.runLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (item == null) {
|
||||
contextMenu.getItems().add(new SeparatorMenuItem());
|
||||
} else {
|
||||
addSwingMenuItem(contextMenu.getItems(), item);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot.jfree;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* Utility class for applying a color map
|
||||
*/
|
||||
public class ColorManager {
|
||||
|
||||
/**
|
||||
* Get color for a given value
|
||||
*
|
||||
* @param v Value to get the color for
|
||||
* @param vmin Lower end value mapped to the lower end of the color map
|
||||
* @param vmax Upper end value mapped to the upper end of the color map
|
||||
* @return Mapped color for the specified value
|
||||
*/
|
||||
public static Color getColourForValue(double v, double vmin, double vmax) {
|
||||
// Standard algorithm for hot-cold color gradient (copied from
|
||||
// http://local.wasp.uwa.edu.au/~pbourke/texture_colour/colourramp/)
|
||||
|
||||
//Init color to white
|
||||
double r = 1.0;
|
||||
double g = 1.0;
|
||||
double b = 1.0;
|
||||
|
||||
double dv;
|
||||
|
||||
if (v < vmin) {
|
||||
v = vmin;
|
||||
}
|
||||
if (v > vmax) {
|
||||
v = vmax;
|
||||
}
|
||||
dv = vmax - vmin;
|
||||
|
||||
if (v < (vmin + 0.25 * dv)) {
|
||||
r = 0.0;
|
||||
g = 4 * (v - vmin) / dv;
|
||||
} else if (v < (vmin + 0.5 * dv)) {
|
||||
r = 0.0;
|
||||
b = 1 + 4 * (vmin + 0.25 * dv - v) / dv;
|
||||
} else if (v < (vmin + 0.75 * dv)) {
|
||||
r = 4 * (v - vmin - 0.5 * dv) / dv;
|
||||
b = 0.0;
|
||||
} else {
|
||||
g = 1 + 4 * (vmin + 0.75 * dv - v) / dv;
|
||||
b = 0.0;
|
||||
}
|
||||
|
||||
return new Color(new Double(255.0 * r).intValue(), new Double(255.0 * g).intValue(), new Double(255.0 * b).intValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a gray value for a given value
|
||||
*
|
||||
* @param value the value (must be within the range specified by the lower
|
||||
* and upper bounds for the scale).
|
||||
*
|
||||
* @return a gray scale color.
|
||||
*/
|
||||
public static Color getGrayForValue(double value, double vmin, double vmax) {
|
||||
double v = Math.max(value, vmin);
|
||||
v = Math.min(v, vmax);
|
||||
int g = (int) ((v - vmin) / (vmax - vmin) * 255.0);
|
||||
// FIXME: it probably makes sense to allocate an array of 256 Colors
|
||||
// and lazily populate this array...
|
||||
return new Color(g, g, g);
|
||||
}
|
||||
}
|
||||
+13
-11
@@ -1,4 +1,4 @@
|
||||
package ch.psi.plot.xy.tools;
|
||||
package ch.psi.plot.jfree;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
@@ -10,29 +10,31 @@ import org.jfree.ui.Drawable;
|
||||
|
||||
/**
|
||||
* Class that draws an cross as annotation.
|
||||
*
|
||||
* This is an implementation of the {@link Drawable} interface, to illustrate the use of the
|
||||
* {@link org.jfree.chart.annotations.XYDrawableAnnotation} class.
|
||||
*
|
||||
* This is an implementation of the {@link Drawable} interface, to illustrate
|
||||
* the use of the {@link org.jfree.chart.annotations.XYDrawableAnnotation}
|
||||
* class.
|
||||
*/
|
||||
public class CrossAnnotation implements Drawable {
|
||||
|
||||
private final Color color;
|
||||
|
||||
private final Color color;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public CrossAnnotation(Color color) {
|
||||
this.color = color;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws cross
|
||||
* @param g2 the graphics device.
|
||||
* @param area the area in which to draw.
|
||||
*
|
||||
* @param g2 the graphics device.
|
||||
* @param area the area in which to draw.
|
||||
*/
|
||||
public void draw(Graphics2D g2, Rectangle2D area) {
|
||||
|
||||
// Draw red cross
|
||||
|
||||
// Draw red cross
|
||||
g2.setPaint(color);
|
||||
g2.setStroke(new BasicStroke(2)); // Stroke width = 2
|
||||
Line2D line1 = new Line2D.Double(area.getCenterX(), area.getMinY(), area.getCenterX(), area.getMaxY());
|
||||
@@ -0,0 +1,544 @@
|
||||
package ch.psi.plot.jfree;
|
||||
|
||||
import ch.psi.plot.LinePlotBase;
|
||||
import ch.psi.plot.LinePlotSeries;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.jfree.chart.ChartFactory;
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.annotations.XYAnnotation;
|
||||
import org.jfree.chart.annotations.XYDrawableAnnotation;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.axis.ValueAxis;
|
||||
import org.jfree.chart.entity.StandardEntityCollection;
|
||||
import org.jfree.chart.labels.StandardXYToolTipGenerator;
|
||||
import org.jfree.chart.labels.XYToolTipGenerator;
|
||||
import org.jfree.chart.plot.Marker;
|
||||
import org.jfree.chart.plot.PlotOrientation;
|
||||
import org.jfree.chart.plot.ValueMarker;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
|
||||
import org.jfree.data.Range;
|
||||
import org.jfree.data.xy.XYDataItem;
|
||||
import org.jfree.data.xy.XYSeries;
|
||||
import org.jfree.data.xy.XYSeriesCollection;
|
||||
import org.jfree.ui.Layer;
|
||||
import org.jfree.ui.RectangleAnchor;
|
||||
import org.jfree.ui.RefineryUtilities;
|
||||
import org.jfree.ui.TextAnchor;
|
||||
|
||||
public class LinePlot extends LinePlotBase {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(LinePlot.class.getName());
|
||||
|
||||
private ChartPanel chartPanel;
|
||||
|
||||
private static final int chartPanelWidth = 500;
|
||||
private static final int chartPanelHeight = 270;
|
||||
|
||||
//Defining Context Menu Label
|
||||
private static final String showLegendMenuLabel = "Show Legend";
|
||||
private static final String hideLegendMenuLabel = "Hide Legend";
|
||||
private static final String showTooltipsMenuLabel = "Show Tooltips";
|
||||
private static final String hideTooltipsMenuLabel = "Hide Tooltips";
|
||||
|
||||
private XYSeriesCollection data;
|
||||
|
||||
JFreeChart chart;
|
||||
|
||||
private boolean tooltips = false;
|
||||
|
||||
/**
|
||||
* @param title Title of plot
|
||||
*/
|
||||
public LinePlot() {
|
||||
super();
|
||||
data = new XYSeriesCollection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppendData(LinePlotSeries series, double x, double y) {
|
||||
XYSeries s = getXYSeries(series);
|
||||
s.add(new XYDataItem(x, y), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetData(LinePlotSeries series, double[] x, double[] y) {
|
||||
XYSeries s = getXYSeries(series);
|
||||
if (!s.isEmpty()) {
|
||||
s.clear();
|
||||
}
|
||||
for (int i = 0; i < y.length; i++) {
|
||||
s.add(new XYDataItem(x[i], y[i]), false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object onAddedSeries(LinePlotSeries series) {
|
||||
final XYSeries s = new XYSeries(series.getName());
|
||||
data.addSeries(s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemovedSeries(LinePlotSeries series) {
|
||||
/*
|
||||
for (Object s : data.getSeries()) {
|
||||
if (((XYSeries)s).getKey().equals(series.getName())) {
|
||||
data.removeSeries(((XYSeries)s));
|
||||
}
|
||||
}
|
||||
*/
|
||||
if ((series != null) && (series.getToken() != null)) {
|
||||
data.removeSeries((XYSeries) (series.getToken()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double[][] getSeriesData(final LinePlotSeries series) {
|
||||
final XYSeries s = getXYSeries(series);
|
||||
List<XYDataItem> items = s.getItems();
|
||||
double[] x = new double[items.size()];
|
||||
double[] y = new double[items.size()];
|
||||
for (int i = 0; i < y.length; i++) {
|
||||
x[i] = items.get(i).getXValue();
|
||||
y[i] = items.get(i).getYValue();
|
||||
}
|
||||
return new double[][]{x, y};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemovedAllSeries() {
|
||||
data.removeAllSeries();
|
||||
}
|
||||
|
||||
public void updateSeries(LinePlotSeries series) {
|
||||
XYSeries s = getXYSeries(series);
|
||||
s.fireSeriesChanged();
|
||||
}
|
||||
|
||||
XYSeries getXYSeries(LinePlotSeries series) {
|
||||
/*
|
||||
for (Object s : data.getSeries()) {
|
||||
if (((XYSeries)s).getKey().equals(series.getName())) {
|
||||
return ((XYSeries)s);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
*/
|
||||
return (XYSeries) (series.getToken());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the chart panel of this plot. The chart panel will be lazily created
|
||||
* the first time this function is called
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected JPanel createChartPanel() {
|
||||
// Create chart
|
||||
chart = ChartFactory.createXYLineChart(getTitle(), getAxis(AxisId.X).getLabel(), getAxis(AxisId.Y).getLabel(), data, PlotOrientation.VERTICAL, true, tooltips, false);
|
||||
|
||||
// Customize chart look and feel
|
||||
// Customize background (gray: new Color(238,238,238))
|
||||
chart.setBackgroundPaint(null);
|
||||
|
||||
// Customize legend
|
||||
chart.getLegend().setVisible(false);
|
||||
chart.getLegend().setBackgroundPaint(null);
|
||||
chart.getLegend().setBorder(0, 0, 0, 0);
|
||||
|
||||
// Customize plot area look and feel
|
||||
XYPlot plot = (XYPlot) chart.getPlot();
|
||||
plot.setBackgroundPaint(Color.white);
|
||||
plot.setDomainGridlinePaint(Color.gray);
|
||||
plot.setRangeGridlinePaint(Color.gray);
|
||||
|
||||
// Show data point
|
||||
((XYLineAndShapeRenderer) plot.getRenderer()).setBaseShapesVisible(true);
|
||||
|
||||
// Include zeros in range (x) axis
|
||||
((NumberAxis) plot.getRangeAxis()).setAutoRangeIncludesZero(false);
|
||||
|
||||
// Lazy creation of the chart panel
|
||||
chartPanel = new ChartPanel(chart);
|
||||
chartPanel.setName(getTitle());
|
||||
|
||||
// Remove border
|
||||
chartPanel.getChart().setBorderVisible(false);
|
||||
|
||||
// Set size of chart
|
||||
chartPanel.setPreferredSize(new java.awt.Dimension(chartPanelWidth, chartPanelHeight));
|
||||
|
||||
// Add more items to the context menu
|
||||
amendContextMenu();
|
||||
|
||||
//Activate (arrow) keys
|
||||
addKeyBindings();
|
||||
return chartPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change visible part of chart
|
||||
*
|
||||
* @param translationVector
|
||||
*/
|
||||
private void moverOverPlot(XYDataItem translationVector) {
|
||||
double translatedDomainIntervalMin = chart.getXYPlot().getDomainAxis().getRange().getLowerBound() + translationVector.getX().doubleValue();
|
||||
double translatedDomainIntervalMax = chart.getXYPlot().getDomainAxis().getRange().getUpperBound() + translationVector.getX().doubleValue();
|
||||
double translatedRangeIntervalMin = chart.getXYPlot().getRangeAxis().getRange().getLowerBound() + translationVector.getY().doubleValue();
|
||||
double translatedRangeIntervalMax = chart.getXYPlot().getRangeAxis().getRange().getUpperBound() + translationVector.getY().doubleValue();
|
||||
|
||||
Range domainAxisRange = new Range(translatedDomainIntervalMin, translatedDomainIntervalMax);
|
||||
Range rangeAxisRange = new Range(translatedRangeIntervalMin, translatedRangeIntervalMax);
|
||||
//We set notify to false in the first call..
|
||||
chart.getXYPlot().getDomainAxis().setRange(domainAxisRange, true, false);
|
||||
//...and true in the last
|
||||
chart.getXYPlot().getRangeAxis().setRange(rangeAxisRange, true, true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add key bindings to chart panel
|
||||
*/
|
||||
private void addKeyBindings() {
|
||||
final String moveUpKey = "move up";
|
||||
final String moveDownKey = "move down";
|
||||
final String moveRightKey = "move right";
|
||||
final String moveLeftKey = "move left";
|
||||
|
||||
// Up arrow
|
||||
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), moveUpKey);
|
||||
chartPanel.getActionMap().put(moveUpKey, new AbstractAction() {
|
||||
// Default serial id
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
moverOverPlot(new XYDataItem(0.0, ((NumberAxis) chart.getXYPlot().getRangeAxis()).getTickUnit().getSize()));
|
||||
}
|
||||
});
|
||||
|
||||
// Down arrow
|
||||
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), moveDownKey);
|
||||
chartPanel.getActionMap().put(moveDownKey, new AbstractAction() {
|
||||
// Default serial id
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
moverOverPlot(new XYDataItem(0.0, -((NumberAxis) chart.getXYPlot().getRangeAxis()).getTickUnit().getSize()));
|
||||
}
|
||||
});
|
||||
|
||||
// Right arrow
|
||||
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), moveRightKey);
|
||||
chartPanel.getActionMap().put(moveRightKey, new AbstractAction() {
|
||||
// Default serial id
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
moverOverPlot(new XYDataItem(((NumberAxis) chart.getXYPlot().getDomainAxis()).getTickUnit().getSize(), 0.0));
|
||||
}
|
||||
});
|
||||
|
||||
// Left arrow
|
||||
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), moveLeftKey);
|
||||
chartPanel.getActionMap().put(moveLeftKey, new AbstractAction() {
|
||||
// Default serial id
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
moverOverPlot(new XYDataItem(-((NumberAxis) chart.getXYPlot().getDomainAxis()).getTickUnit().getSize(), 0.0));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAxisRangeChanged(AxisId axis_id) {
|
||||
ValueAxis axis = null;
|
||||
|
||||
switch (axis_id) {
|
||||
case X:
|
||||
axis = chart.getXYPlot().getDomainAxis();
|
||||
break;
|
||||
case Y:
|
||||
axis = chart.getXYPlot().getRangeAxis();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if (getAxis(axis_id).isAutoRange()) {
|
||||
axis.setAutoRange(true);
|
||||
} else {
|
||||
axis.setRange(new Range(getAxis(axis_id).getMin(), getAxis(axis_id).getMax()), true, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional items to the context menu of the plot
|
||||
*/
|
||||
public void amendContextMenu() {
|
||||
|
||||
chartPanel.getPopupMenu().addSeparator();
|
||||
|
||||
JMenu toolsMenu = new JMenu("Tools");
|
||||
chartPanel.getPopupMenu().add(toolsMenu);
|
||||
|
||||
// Mark average
|
||||
JMenuItem averageMenuItem = new JMenuItem("Average");
|
||||
averageMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
for (LinePlotSeries series : getAllSeries()) {
|
||||
double a = series.getAverage();
|
||||
// Remove all range markers
|
||||
Collection<?> c = chartPanel.getChart().getXYPlot().getRangeMarkers(Layer.FOREGROUND);
|
||||
if (c != null) {
|
||||
for (final Object marker : c) {
|
||||
SwingUtilities.invokeLater(new Runnable() { // Avoid concurrent modification exception
|
||||
@Override
|
||||
public void run() {
|
||||
chartPanel.getChart().getXYPlot().removeRangeMarker((Marker) marker);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
final ValueMarker marker = new ValueMarker(a, Color.BLACK, new BasicStroke(1));
|
||||
marker.setLabel("Average [" + series.getName() + "]: " + String.format("%.6f", a));
|
||||
marker.setLabelAnchor(RectangleAnchor.CENTER);
|
||||
marker.setLabelTextAnchor(TextAnchor.TOP_RIGHT);
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() { // Avoid concurrent modification exception
|
||||
@Override
|
||||
public void run() {
|
||||
chartPanel.getChart().getXYPlot().addRangeMarker(marker, Layer.FOREGROUND);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
toolsMenu.add(averageMenuItem);
|
||||
|
||||
// Mark minimum value
|
||||
JMenuItem minimumMenuItem = new JMenuItem("Minimum");
|
||||
minimumMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
for (LinePlotSeries series : getAllSeries()) {
|
||||
double[] min = series.getMinimum();
|
||||
// System.out.println("Minimum: "+m.getXValue());
|
||||
// Remove all annotation for the series
|
||||
for (Object o : chartPanel.getChart().getXYPlot().getAnnotations()) {
|
||||
chartPanel.getChart().getXYPlot().removeAnnotation((XYAnnotation) o);
|
||||
}
|
||||
XYDrawableAnnotation cross = new XYDrawableAnnotation(min[0], min[1], 10.0, 10.0, new CrossAnnotation(Color.BLACK));
|
||||
cross.setToolTipText("Minimum: " + min[0] + " / " + min[1]);
|
||||
chartPanel.getChart().getXYPlot().addAnnotation(cross);
|
||||
}
|
||||
}
|
||||
});
|
||||
toolsMenu.add(minimumMenuItem);
|
||||
|
||||
// Mark maximum value
|
||||
JMenuItem maximumMenuItem = new JMenuItem("Maximum");
|
||||
maximumMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
for (LinePlotSeries series : getAllSeries()) {
|
||||
double[] max = series.getMaximum();
|
||||
// Remove all annotation for the series
|
||||
for (Object o : chartPanel.getChart().getXYPlot().getAnnotations()) {
|
||||
chartPanel.getChart().getXYPlot().removeAnnotation((XYAnnotation) o);
|
||||
}
|
||||
XYDrawableAnnotation cross = new XYDrawableAnnotation(max[0], max[1], 10.0, 10.0, new CrossAnnotation(Color.BLACK));
|
||||
cross.setToolTipText("Maximum: " + max[0] + " / " + max[1]);
|
||||
chartPanel.getChart().getXYPlot().addAnnotation(cross);
|
||||
}
|
||||
}
|
||||
});
|
||||
toolsMenu.add(maximumMenuItem);
|
||||
|
||||
// Show derivative
|
||||
JMenuItem derivativeMenuItem = new JMenuItem("Derivative");
|
||||
derivativeMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
LinePlot p = new LinePlot();
|
||||
p.setTitle("Derivative - " + getTitle());
|
||||
for (LinePlotSeries series : getAllSeries()) {
|
||||
double[][] derivative = series.getDerivative();
|
||||
LinePlotSeries dseries = new LinePlotSeries(series.getName() + "'");
|
||||
p.addSeries(dseries);
|
||||
dseries.setData(derivative[0], derivative[1]);
|
||||
}
|
||||
JFrame frame = new JFrame();
|
||||
frame.setContentPane(p.getChartPanel());
|
||||
frame.pack();
|
||||
RefineryUtilities.centerFrameOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
toolsMenu.add(derivativeMenuItem);
|
||||
|
||||
// Show integral
|
||||
JMenuItem integralMenuItem = new JMenuItem("Integral");
|
||||
integralMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
// Show new frame
|
||||
LinePlot p = new LinePlot();
|
||||
p.setTitle("Integral - " + getTitle());
|
||||
for (LinePlotSeries series : getAllSeries()) {
|
||||
double[][] integral = series.getIntegral();
|
||||
LinePlotSeries dseries = new LinePlotSeries("integral-" + series.getName());
|
||||
p.addSeries(dseries);
|
||||
dseries.setData(integral[0], integral[1]);
|
||||
}
|
||||
JFrame frame = new JFrame();
|
||||
frame.setContentPane(p.getChartPanel());
|
||||
frame.pack();
|
||||
RefineryUtilities.centerFrameOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
toolsMenu.add(integralMenuItem);
|
||||
|
||||
/*
|
||||
chartPanel.getPopupMenu().addSeparator();
|
||||
// Detach plot into a separate frame
|
||||
JMenuItem detachPlotMenuItem = new JMenuItem("Detach");
|
||||
detachPlotMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
LinePlot p = new LinePlot();
|
||||
p.setTitle(getTitle());
|
||||
for (LinePlotSeries series : LinePlot.this.getAllSeries()) {
|
||||
LinePlotSeries detachedSeries = new LinePlotSeries(series.getName(), series.getColor());
|
||||
p.addSeries(detachedSeries);
|
||||
detachedSeries.setData(series.getX(), series.getY());
|
||||
}
|
||||
|
||||
JFrame frame = new JFrame();
|
||||
frame.setContentPane(p.getChartPanel());
|
||||
frame.pack();
|
||||
RefineryUtilities.centerFrameOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
chartPanel.getPopupMenu().add(detachPlotMenuItem);
|
||||
*/
|
||||
// Hide/Show legend
|
||||
JMenuItem hideLegendMenuItem = new JMenuItem(showLegendMenuLabel);
|
||||
hideLegendMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuItem source = (JMenuItem) (e.getSource());
|
||||
|
||||
if (source.getText() == showLegendMenuLabel) {
|
||||
chart.getLegend().setVisible(true);
|
||||
source.setText(hideLegendMenuLabel);
|
||||
} else if (source.getText() == hideLegendMenuLabel) {
|
||||
chart.getLegend().setVisible(false);
|
||||
source.setText(showLegendMenuLabel);
|
||||
}
|
||||
}
|
||||
});
|
||||
chartPanel.getPopupMenu().add(hideLegendMenuItem);
|
||||
|
||||
// Hide/Show tooltips
|
||||
JMenuItem hideToolTipsMenuItem = new JMenuItem(hideTooltipsMenuLabel);
|
||||
if (!tooltips) {
|
||||
hideToolTipsMenuItem.setText(showTooltipsMenuLabel);
|
||||
}
|
||||
hideToolTipsMenuItem.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuItem source = (JMenuItem) (e.getSource());
|
||||
if (source.getText() == showTooltipsMenuLabel) {
|
||||
showTooltips();
|
||||
source.setText(hideTooltipsMenuLabel);
|
||||
} else if (source.getText() == hideTooltipsMenuLabel) {
|
||||
hideTooltips();
|
||||
source.setText(showTooltipsMenuLabel);
|
||||
}
|
||||
}
|
||||
});
|
||||
chartPanel.getPopupMenu().add(hideToolTipsMenuItem);
|
||||
|
||||
}
|
||||
|
||||
private void showTooltips() {
|
||||
tooltips = true;
|
||||
DecimalFormat dm = new DecimalFormat("0.##########");
|
||||
XYToolTipGenerator xYToolTipGenerator = new StandardXYToolTipGenerator("{1}/{2}", dm, dm);
|
||||
chart.getXYPlot().getRenderer().setBaseToolTipGenerator(xYToolTipGenerator);
|
||||
chartPanel.setDisplayToolTips(true);
|
||||
chartPanel.getChartRenderingInfo().setEntityCollection(new StandardEntityCollection());
|
||||
}
|
||||
|
||||
private void hideTooltips() {
|
||||
tooltips = false;
|
||||
// http://www.jfree.org/phpBB2/viewtopic.php?t=12788&highlight=redraw+speed+performance+problem
|
||||
chartPanel.getChartRenderingInfo().setEntityCollection(null);
|
||||
chart.getXYPlot().getRenderer().setBaseToolTipGenerator(null);
|
||||
}
|
||||
|
||||
protected void addPopupMenuItem(final JMenuItem item) {
|
||||
if (item == null) {
|
||||
chartPanel.getPopupMenu().addSeparator();
|
||||
} else {
|
||||
chartPanel.getPopupMenu().add(item);
|
||||
}
|
||||
}
|
||||
/*
|
||||
@Override
|
||||
protected void doUpdate()
|
||||
if (data != null) {
|
||||
SwingUtilities.invokeLater(new Runnable() { // Try to avoid concurrent modification exception
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
for (XYSeries s : data.getSeries()) {
|
||||
s.fireSeriesChanged();
|
||||
}
|
||||
} catch (ConcurrentModificationException e) {
|
||||
logger.log(Level.WARNING, "Series got modified concurrently: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
//Trash
|
||||
@Override
|
||||
public void setData(Object data) {
|
||||
super.setData(data);
|
||||
this.data = (XYSeriesCollection) data;
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot.jfree;
|
||||
|
||||
import ch.psi.plot.jfree.MatrixPlot;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.FlowLayout;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.JLabel;
|
||||
import java.awt.Font;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ActionEvent;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class ManualScaleDialog extends JDialog {
|
||||
|
||||
// Default serial id
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final JPanel contentPanel = new JPanel();
|
||||
private JTextField textFieldHighValue;
|
||||
private JTextField textFieldLowValue;
|
||||
|
||||
private MatrixPlot plot;
|
||||
|
||||
private int selectedOption;
|
||||
|
||||
/**
|
||||
* Launch the application.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
ManualScaleDialog dialog = new ManualScaleDialog();
|
||||
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
||||
dialog.setVisible(true);
|
||||
System.out.println("HERE");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the dialog.
|
||||
*/
|
||||
public ManualScaleDialog() {
|
||||
setModal(true); // Block until dialog is disposed.
|
||||
setBounds(100, 100, 450, 300);
|
||||
getContentPane().setLayout(new BorderLayout());
|
||||
contentPanel.setLayout(new FlowLayout());
|
||||
contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
getContentPane().add(contentPanel, BorderLayout.CENTER);
|
||||
{
|
||||
JLabel lblLowValue = new JLabel("Low Value:");
|
||||
lblLowValue.setFont(new Font("Lucida Grande", Font.BOLD, 13));
|
||||
contentPanel.add(lblLowValue);
|
||||
}
|
||||
{
|
||||
textFieldLowValue = new JTextField();
|
||||
contentPanel.add(textFieldLowValue);
|
||||
textFieldLowValue.setColumns(10);
|
||||
}
|
||||
{
|
||||
JLabel lblHighValue = new JLabel("High Value:");
|
||||
lblHighValue.setFont(new Font("Lucida Grande", Font.BOLD, 13));
|
||||
contentPanel.add(lblHighValue);
|
||||
}
|
||||
{
|
||||
textFieldHighValue = new JTextField();
|
||||
contentPanel.add(textFieldHighValue);
|
||||
textFieldHighValue.setColumns(10);
|
||||
}
|
||||
{
|
||||
JPanel buttonPane = new JPanel();
|
||||
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
|
||||
getContentPane().add(buttonPane, BorderLayout.SOUTH);
|
||||
{
|
||||
JButton okButton = new JButton("OK");
|
||||
okButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
// set OK
|
||||
selectedOption = JOptionPane.OK_OPTION;
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
{
|
||||
JButton btnApply = new JButton("Apply");
|
||||
btnApply.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
// TODO apply values
|
||||
if (plot != null) {
|
||||
plot.setColorScale(getLow(), getHigh());
|
||||
}
|
||||
}
|
||||
});
|
||||
buttonPane.add(btnApply);
|
||||
}
|
||||
okButton.setActionCommand("OK");
|
||||
buttonPane.add(okButton);
|
||||
getRootPane().setDefaultButton(okButton);
|
||||
}
|
||||
{
|
||||
JButton cancelButton = new JButton("Cancel");
|
||||
cancelButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
// set Cancel
|
||||
selectedOption = JOptionPane.CANCEL_OPTION;
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
cancelButton.setActionCommand("Cancel");
|
||||
buttonPane.add(cancelButton);
|
||||
}
|
||||
}
|
||||
|
||||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
pack();
|
||||
}
|
||||
|
||||
public void showDialog() {
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
public void setMatrixPlot(MatrixPlot p) {
|
||||
plot = p;
|
||||
}
|
||||
|
||||
public void setLow(double low) {
|
||||
textFieldLowValue.setText(String.format("%.4f", low));
|
||||
}
|
||||
|
||||
public void setHigh(double high) {
|
||||
textFieldHighValue.setText(String.format("%.4f", high));
|
||||
}
|
||||
|
||||
public double getLow() {
|
||||
double low = Double.NaN;
|
||||
try {
|
||||
low = Double.parseDouble(textFieldLowValue.getText());
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
return low;
|
||||
}
|
||||
|
||||
public double getHigh() {
|
||||
double high = Double.NaN;
|
||||
try {
|
||||
high = Double.parseDouble(textFieldHighValue.getText());
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
return high;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the selectedOption
|
||||
*/
|
||||
public int getSelectedOption() {
|
||||
return selectedOption;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,490 @@
|
||||
package ch.psi.plot.jfree;
|
||||
|
||||
import ch.psi.plot.MatrixPlotBase;
|
||||
import ch.psi.plot.MatrixPlotSeries;
|
||||
import java.awt.Color;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Arrays;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.axis.ValueAxis;
|
||||
import org.jfree.chart.event.AxisChangeEvent;
|
||||
import org.jfree.chart.event.AxisChangeListener;
|
||||
import org.jfree.chart.labels.StandardXYZToolTipGenerator;
|
||||
import org.jfree.chart.labels.XYZToolTipGenerator;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.renderer.LookupPaintScale;
|
||||
import org.jfree.chart.renderer.PaintScale;
|
||||
import org.jfree.chart.renderer.xy.XYBlockRenderer;
|
||||
import org.jfree.chart.title.PaintScaleLegend;
|
||||
import org.jfree.data.Range;
|
||||
import org.jfree.data.xy.DefaultXYZDataset;
|
||||
import org.jfree.ui.RectangleAnchor;
|
||||
import org.jfree.ui.RectangleEdge;
|
||||
import org.jfree.ui.RectangleInsets;
|
||||
|
||||
/**
|
||||
* Returns a matrix plot panel
|
||||
*/
|
||||
public class MatrixPlot extends MatrixPlotBase {
|
||||
|
||||
private static final int chartPanelWidth = 500;
|
||||
private static final int chartPanelHeight = 270;
|
||||
|
||||
private boolean grayScale = false;
|
||||
|
||||
private MatrixPlotSeries series;
|
||||
private DefaultXYZDataset data;
|
||||
private JFreeChart chart;
|
||||
private ChartPanel chartPanel;
|
||||
|
||||
double[] xvalues = new double[0];
|
||||
double[] yvalues = new double[0];
|
||||
double[] zvalues = new double[0];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param title
|
||||
* @param data
|
||||
*/
|
||||
XYPlot plot;
|
||||
final NumberAxis xAxis, yAxis;
|
||||
final XYBlockRenderer renderer;
|
||||
|
||||
public MatrixPlot() {
|
||||
super();
|
||||
// Create matrix chart
|
||||
// Init size of plot area according to min and max set in the datas metadata
|
||||
// Set axis: (plus half bin size on both sides), since we plot the bins centered.
|
||||
xAxis = new NumberAxis("");
|
||||
yAxis = new NumberAxis("");
|
||||
|
||||
// Configure block renderer to have the blocks rendered in the correct size
|
||||
renderer = new XYBlockRenderer();
|
||||
renderer.setBaseCreateEntities(false);
|
||||
plot = new XYPlot(null, xAxis, yAxis, renderer);
|
||||
|
||||
// Remove background paint/color
|
||||
plot.setBackgroundPaint(null);
|
||||
|
||||
// Set the maximum zoom out to the initial zoom rate This also
|
||||
// provides a workaround for dynamic plots because there zoom out does not work correctly (zoom out to infinity)
|
||||
plot.getRangeAxis().addChangeListener(new AxisChangeListener() {
|
||||
@Override
|
||||
public void axisChanged(AxisChangeEvent event) {
|
||||
if (series == null) {
|
||||
return;
|
||||
}
|
||||
ValueAxis axis = ((ValueAxis) event.getAxis());
|
||||
if (axis.getLowerBound() < yMin || axis.getUpperBound() > yMax) {
|
||||
Range range = new Range(yMin, yMax);
|
||||
axis.setRange(range, true, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
plot.getDomainAxis().addChangeListener(new AxisChangeListener() {
|
||||
@Override
|
||||
public void axisChanged(AxisChangeEvent event) {
|
||||
if (series == null) {
|
||||
return;
|
||||
}
|
||||
ValueAxis axis = ((ValueAxis) event.getAxis());
|
||||
if (axis.getLowerBound() < xMin || axis.getUpperBound() > xMax) {
|
||||
Range range = new Range(xMin, xMax);
|
||||
axis.setRange(range, true, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
double xMin, xMax, yMin, yMax;
|
||||
|
||||
@Override
|
||||
protected Object onAddedSeries(MatrixPlotSeries series) {
|
||||
this.series = series;
|
||||
int arraylength = series.getNumberOfBinsX() * series.getNumberOfBinsY();
|
||||
xvalues = new double[arraylength];
|
||||
yvalues = new double[arraylength];
|
||||
zvalues = new double[arraylength];
|
||||
Arrays.fill(xvalues, Double.NEGATIVE_INFINITY);
|
||||
Arrays.fill(yvalues, Double.NEGATIVE_INFINITY);
|
||||
Arrays.fill(zvalues, Double.NEGATIVE_INFINITY);
|
||||
double[][] dataArray = new double[][]{xvalues, yvalues, zvalues};
|
||||
//Create the XYDataset (org.jfree), not to be confused with the ch.psi dataSet)
|
||||
data = new DefaultXYZDataset();
|
||||
data.addSeries("Data", dataArray);
|
||||
|
||||
onAxisRangeChanged(AxisId.X);
|
||||
onAxisRangeChanged(AxisId.Y);
|
||||
xAxis.setLabel(getAxis(AxisId.X).getLabel());
|
||||
yAxis.setLabel(getAxis(AxisId.Y).getLabel());
|
||||
|
||||
renderer.setBlockWidth(series.getBinWidthX()); // If this is not set the default block size is 1
|
||||
renderer.setBlockHeight(series.getBinWidthY()); // If this is not set the default block size is 1
|
||||
renderer.setBlockAnchor(RectangleAnchor.CENTER);
|
||||
|
||||
// Remove background paint/color
|
||||
plot.setBackgroundPaint(null);
|
||||
|
||||
plot.setDataset(data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAxisRangeChanged(AxisId axis_id) {
|
||||
// The axis min and max values need to be half a bin larger. Otherwise the outer pixels
|
||||
// will not be plotted correctly (half of the pixel is missing)
|
||||
if (axis_id == AxisId.X) {
|
||||
if (getAxis(AxisId.X).isAutoRange()) {
|
||||
xMin = series.getMinX() - 0.5 * series.getBinWidthX();
|
||||
xMax = series.getMaxX() + 0.5 * series.getBinWidthX();
|
||||
} else {
|
||||
xMin = getAxis(AxisId.X).getMin();
|
||||
xMax = getAxis(AxisId.X).getMax();
|
||||
}
|
||||
xAxis.setLowerBound(xMin);
|
||||
xAxis.setUpperBound(xMax);
|
||||
}
|
||||
if (axis_id == AxisId.Y) {
|
||||
if (getAxis(AxisId.Y).isAutoRange()) {
|
||||
yMin = series.getMinY() - 0.5 * series.getBinWidthY();
|
||||
yMax = series.getMaxY() + 0.5 * series.getBinWidthY();
|
||||
} else {
|
||||
yMin = getAxis(AxisId.Y).getMin();
|
||||
yMax = getAxis(AxisId.Y).getMax();
|
||||
}
|
||||
yAxis.setLowerBound(yMin);
|
||||
yAxis.setUpperBound(yMax);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemovedSeries(MatrixPlotSeries s) {
|
||||
series = null;
|
||||
doUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAppendData(MatrixPlotSeries series, int indexX, int indexY, double x, double y, double z) {
|
||||
final int index = indexY * series.getNumberOfBinsX() + indexX;
|
||||
//x Value is column, y value is row
|
||||
xvalues[index] = x;
|
||||
yvalues[index] = y;
|
||||
zvalues[index] = z;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetData(MatrixPlotSeries series, double[][] data) {
|
||||
int index = 0;
|
||||
for (int y = 0; y < data.length; y++) {
|
||||
for (int x = 0; x < data[0].length; x++) {
|
||||
//final int index = y * series.getNumberOfBinsX() + x;
|
||||
xvalues[index] = series.getMinX() + series.getBinWidthX() * x;
|
||||
yvalues[index] = series.getMinY() + series.getBinWidthY() * y;
|
||||
zvalues[index++] = data[y][x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
if (series != null) {
|
||||
removeSeries(series);
|
||||
doUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double[][] getSeriesData(MatrixPlotSeries s) {
|
||||
int x = series.getNumberOfBinsX();
|
||||
int y = series.getNumberOfBinsY();
|
||||
double[][] ret = new double[y][x];
|
||||
int index = 0;
|
||||
for (int i = 0; i < y; i++) {
|
||||
for (int j = 0; j < x; j++) {
|
||||
ret[i][j] = data.getZValue(0, index++);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Action Classes that implement methods called after keyboard input
|
||||
/**
|
||||
* Adapt the context menu of the chart panel
|
||||
*/
|
||||
private void adaptContextMenu(final ChartPanel chartPanel) {
|
||||
|
||||
// Show hide tooltips
|
||||
final String tooltipsMenuLabel = "Tooltips";
|
||||
final String hideTooltipsMenuLabel = "Hide Tooltips";
|
||||
JMenuItem contextMenuItemToolTip = new JMenuItem(tooltipsMenuLabel);
|
||||
contextMenuItemToolTip.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuItem source = (JMenuItem) (e.getSource());
|
||||
if (source.getText() == tooltipsMenuLabel) {
|
||||
showTooltip();
|
||||
source.setText(hideTooltipsMenuLabel);
|
||||
} else if (source.getText() == hideTooltipsMenuLabel) {
|
||||
hideTooltip();
|
||||
source.setText(tooltipsMenuLabel);
|
||||
}
|
||||
}
|
||||
});
|
||||
chartPanel.getPopupMenu().add(contextMenuItemToolTip);
|
||||
|
||||
// Update colormap
|
||||
JMenuItem contextMenuItemAdaptScale = new JMenuItem("Update Scale");
|
||||
contextMenuItemAdaptScale.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
adaptColorMapScale();
|
||||
}
|
||||
});
|
||||
|
||||
// Set gray scale colormap
|
||||
JMenuItem contextMenuItemGrayScale = new JMenuItem("Gray Scale");
|
||||
contextMenuItemGrayScale.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
grayScale = true;
|
||||
adaptColorMapScale();
|
||||
}
|
||||
});
|
||||
|
||||
// Set color colormap
|
||||
JMenuItem contextMenuItemTemperatureColor = new JMenuItem("Color Scale");
|
||||
contextMenuItemTemperatureColor.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
grayScale = false;
|
||||
adaptColorMapScale();
|
||||
}
|
||||
});
|
||||
|
||||
// Set color colormap
|
||||
JMenuItem menuItemScale = new JMenuItem("Manual Scale");
|
||||
menuItemScale.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
ManualScaleDialog d = new ManualScaleDialog();
|
||||
d.setLocationRelativeTo(chartPanel);
|
||||
d.setLow(((PaintScaleLegend) chart.getSubtitles().get(0)).getScale().getLowerBound());
|
||||
d.setHigh(((PaintScaleLegend) chart.getSubtitles().get(0)).getScale().getUpperBound());
|
||||
d.setMatrixPlot(MatrixPlot.this);
|
||||
|
||||
d.showDialog();
|
||||
if (d.getSelectedOption() == JOptionPane.OK_OPTION) {
|
||||
setColorScale(d.getLow(), d.getHigh());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Group colormap related menu items
|
||||
JMenuItem contextMenuChooseColorMap = new JMenu("ColorMap");
|
||||
contextMenuChooseColorMap.add(contextMenuItemAdaptScale);
|
||||
contextMenuChooseColorMap.add(menuItemScale);
|
||||
contextMenuChooseColorMap.add(contextMenuItemGrayScale);
|
||||
contextMenuChooseColorMap.add(contextMenuItemTemperatureColor);
|
||||
chartPanel.getPopupMenu().add(contextMenuChooseColorMap);
|
||||
/*
|
||||
// Add separator
|
||||
chartPanel.getPopupMenu().addSeparator();
|
||||
|
||||
|
||||
// Detach plot into an own frame
|
||||
JMenuItem contextMenuItemDetach = new JMenuItem("Detach Plot");
|
||||
contextMenuItemDetach.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
MatrixPlot p = new MatrixPlot();
|
||||
p.setTitle(title);
|
||||
p.setSeries(series);
|
||||
|
||||
final JFrame frame = new JFrame(title);
|
||||
frame.getContentPane();
|
||||
frame.setContentPane(p.getChartPanel());
|
||||
frame.pack();
|
||||
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); // Close application if frame is closed
|
||||
|
||||
// Set color scale
|
||||
p.adaptColorMapScale();
|
||||
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
chartPanel.getPopupMenu().add(contextMenuItemDetach);
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Show Tooltips. This is not done per default since it makes the app slow
|
||||
* for datasize >= 1M
|
||||
*/
|
||||
private void showTooltip() {
|
||||
//Tooltips are quit expensive
|
||||
DecimalFormat dm = new DecimalFormat("0.##########");
|
||||
XYZToolTipGenerator xYZToolTipGenerator = new StandardXYZToolTipGenerator("{0}: ({1} / {2} / {3})", dm, dm, dm);
|
||||
|
||||
chart.getXYPlot().getRenderer().setBaseToolTipGenerator(xYZToolTipGenerator);
|
||||
((XYBlockRenderer) chart.getXYPlot().getRenderer()).setBaseCreateEntities(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear Tooltips
|
||||
*/
|
||||
private void hideTooltip() {
|
||||
//Tooltips are quit expensive
|
||||
((XYBlockRenderer) chart.getXYPlot().getRenderer()).setBaseToolTipGenerator(null);
|
||||
((XYBlockRenderer) chart.getXYPlot().getRenderer()).setBaseCreateEntities(false);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapt the lower and upper color map scale to the min and max data values
|
||||
* of the currently selected region Need to be called AFTER the chart panel
|
||||
* is created
|
||||
*/
|
||||
public void adaptColorMapScale() {
|
||||
double[] v = series.minMaxZValue();
|
||||
if (v[0] != Double.NaN && v[1] != Double.NaN && v[0] < v[1]) {
|
||||
setColorScale(v[0], v[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the min and max of color map scale to scaleMin and scaleMax
|
||||
*
|
||||
* @param scaleMin min value of scale
|
||||
* @param scaleMax max value of scale
|
||||
*/
|
||||
public void setColorScale(double scaleMin, double scaleMax) {
|
||||
|
||||
// Create scale for legend
|
||||
LookupPaintScale legendScale = new LookupPaintScale(scaleMin, scaleMax, Color.GRAY);
|
||||
setScaleColors(legendScale, scaleMin, scaleMax);
|
||||
|
||||
// Create legend
|
||||
PaintScaleLegend legend = new PaintScaleLegend(legendScale, new NumberAxis());
|
||||
legend.setPadding(new RectangleInsets(5, 5, 5, 5));
|
||||
// Width of the legend (colorbar)
|
||||
legend.setStripWidth(20);
|
||||
// Position of the legend
|
||||
legend.setPosition(RectangleEdge.RIGHT);
|
||||
// Remove background paint/color
|
||||
legend.setBackgroundPaint(null);
|
||||
|
||||
// Add legend to plot panel
|
||||
chart.clearSubtitles();
|
||||
chart.addSubtitle(legend);
|
||||
|
||||
//We need a second scale for rendering only, where the 'infinities' are in correct color
|
||||
LookupPaintScale rendererScale = new LookupPaintScale(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Color.GRAY);
|
||||
setScaleColors(rendererScale, scaleMin, scaleMax);
|
||||
// Make the paint scale range from - to + infinity
|
||||
if (grayScale) {
|
||||
rendererScale.add(Double.NEGATIVE_INFINITY, ColorManager.getGrayForValue(scaleMin, scaleMin, scaleMax));
|
||||
rendererScale.add(Double.POSITIVE_INFINITY, ColorManager.getGrayForValue(scaleMax, scaleMin, scaleMax));
|
||||
} else {
|
||||
rendererScale.add(Double.NEGATIVE_INFINITY, ColorManager.getColourForValue(scaleMin, scaleMin, scaleMax));
|
||||
rendererScale.add(Double.POSITIVE_INFINITY, ColorManager.getColourForValue(scaleMax, scaleMin, scaleMax));
|
||||
}
|
||||
((XYBlockRenderer) chart.getXYPlot().getRenderer()).setPaintScale(rendererScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the colors for the colored Paint Scale (either single color or
|
||||
* temperature color)
|
||||
*
|
||||
* @param paintScale
|
||||
* @param scaleMin
|
||||
* @param scaleMax
|
||||
*/
|
||||
private void setScaleColors(PaintScale paintScale, double scaleMin, double scaleMax) {
|
||||
if (grayScale) {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
double value = scaleMin + (i / 255.0) * (scaleMax - scaleMin);
|
||||
((LookupPaintScale) paintScale).add(value, ColorManager.getGrayForValue(value, scaleMin, scaleMax));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
double value = scaleMin + (i / 255.0) * (scaleMax - scaleMin);
|
||||
((LookupPaintScale) paintScale).add(value, ColorManager.getColourForValue(value, scaleMin, scaleMax));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the chart panel
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected JPanel createChartPanel() {
|
||||
chart = new JFreeChart(getTitle(), plot);
|
||||
|
||||
//Remove the series label (also called legend)
|
||||
chart.removeLegend();
|
||||
//AntiAliasing is used to speed up rendering
|
||||
// chart.setAntiAlias(false);
|
||||
|
||||
// Init PaintScale
|
||||
setColorScale(0, 1);
|
||||
|
||||
//Create the Chartpanel where the chart will be plotted
|
||||
chartPanel = new ChartPanel(chart);
|
||||
|
||||
chartPanel.setPreferredSize(new java.awt.Dimension(chartPanelWidth, chartPanelHeight));
|
||||
|
||||
//All interactive menu items
|
||||
adaptContextMenu(chartPanel);
|
||||
return chartPanel;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.plot.Plot#update()
|
||||
*/
|
||||
@Override
|
||||
public void doUpdate() {
|
||||
if (chart != null) {
|
||||
chart.fireChartChanged();
|
||||
adaptColorMapScale();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSeries(MatrixPlotSeries series) {
|
||||
doUpdate();
|
||||
}
|
||||
|
||||
protected void addPopupMenuItem(final JMenuItem item) {
|
||||
if (item == null) {
|
||||
chartPanel.getPopupMenu().addSeparator();
|
||||
} else {
|
||||
chartPanel.getPopupMenu().add(item);
|
||||
}
|
||||
}
|
||||
|
||||
//public JFreeChart getChart() {
|
||||
// return chart;
|
||||
//}
|
||||
//@Override
|
||||
//public void setData(Object data){
|
||||
// super.setData(data);
|
||||
// this.data=(MatrixPlotSeries) data;
|
||||
//}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot.jlchart;
|
||||
|
||||
import ch.psi.plot.LinePlotBase;
|
||||
import ch.psi.plot.LinePlotSeries;
|
||||
import ch.psi.plot.utils.MonitoredPanel;
|
||||
import fr.esrf.tangoatk.widget.util.chart.DataList;
|
||||
import fr.esrf.tangoatk.widget.util.chart.JLAxis;
|
||||
import fr.esrf.tangoatk.widget.util.chart.JLChart;
|
||||
import fr.esrf.tangoatk.widget.util.chart.JLDataView;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.util.ArrayList;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class LinePlot extends LinePlotBase {
|
||||
|
||||
final JLChart plot;
|
||||
|
||||
final ArrayList<JLDataView> views = new ArrayList<>();
|
||||
|
||||
public LinePlot() {
|
||||
super();
|
||||
plot = new JLChart();
|
||||
plot.getXAxis().setAnnotation(JLAxis.VALUE_ANNO);
|
||||
//plot.getXAxis().setLabelFormat(JLAxis.SCIENTIFIC_FORMAT);
|
||||
plot.getY1Axis().setAutoScale(true);
|
||||
plot.getY2Axis().setAutoScale(true);
|
||||
plot.getXAxis().setAutoScale(true);
|
||||
plot.getY1Axis().setGridVisible(true);
|
||||
plot.getXAxis().setGridVisible(true);
|
||||
|
||||
/*
|
||||
plot.getY1Axis().setAutoScale(false);
|
||||
plot.getY2Axis().setAutoScale(false);
|
||||
plot.getXAxis().setAutoScale(false);
|
||||
plot.getY1Axis().setMinimum(0);
|
||||
plot.getY1Axis().setMaximum(10);
|
||||
plot.getY2Axis().setMinimum(0);
|
||||
plot.getY2Axis().setMaximum(10);
|
||||
plot.getXAxis().setMinimum(0);
|
||||
plot.getXAxis().setMaximum(10);
|
||||
*/
|
||||
plot.setLabelVisible(false);
|
||||
plot.setBackground(new Color(240, 240, 240));
|
||||
setRequireUpdateOnAppend(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAxisRangeChanged(AxisId axis_id) {
|
||||
JLAxis axis = null;
|
||||
switch (axis_id) {
|
||||
case X:
|
||||
axis = plot.getXAxis();
|
||||
break;
|
||||
case Y:
|
||||
axis = plot.getY1Axis();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
axis.setAutoScale(getAxis(axis_id).isAutoRange());
|
||||
axis.setMinimum(getAxis(axis_id).getMin());
|
||||
axis.setMaximum(getAxis(axis_id).getMax());
|
||||
update(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object onAddedSeries(LinePlotSeries series) {
|
||||
JLDataView view = new JLDataView();
|
||||
|
||||
view.setColor(series.getColor());
|
||||
//view.setLineWidth(1);
|
||||
|
||||
int markerSize = 4;
|
||||
view.setName(series.getName());
|
||||
view.setMarkerSize(markerSize);
|
||||
view.setMarkerColor(series.getColor());
|
||||
|
||||
view.setViewType(JLDataView.TYPE_LINE);
|
||||
|
||||
if (markerSize > 0) {
|
||||
view.setMarker(JLDataView.MARKER_DOT);
|
||||
} else {
|
||||
view.setMarker(JLDataView.MARKER_NONE);
|
||||
}
|
||||
|
||||
if (series.getAxisY() == 2) {
|
||||
plot.getY2Axis().addDataView(view);
|
||||
} else {
|
||||
plot.getY1Axis().addDataView(view);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
JLDataView getDataView(LinePlotSeries series) {
|
||||
return (JLDataView) (series.getToken());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemovedSeries(LinePlotSeries series) {
|
||||
JLDataView view = getDataView(series);
|
||||
for (int i = 0; i < plot.getY1Axis().getViewNumber(); i++) {
|
||||
if (view.getName().equals(plot.getY1Axis().getDataView(i).getName())) {
|
||||
plot.getY1Axis().removeDataView(view);
|
||||
}
|
||||
|
||||
}
|
||||
for (int i = 0; i < plot.getY2Axis().getViewNumber(); i++) {
|
||||
if (view.getName().equals(plot.getY2Axis().getDataView(i).getName())) {
|
||||
plot.getY2Axis().removeDataView(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAppendData(LinePlotSeries series, double x, double y) {
|
||||
JLDataView view = getDataView(series);
|
||||
if (view != null) //view.add(x, y);
|
||||
{
|
||||
plot.addData(view, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetData(LinePlotSeries series, double[] x, double[] y) {
|
||||
JLDataView view = getDataView(series);
|
||||
if (view != null) {
|
||||
view.setData(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double[][] getSeriesData(LinePlotSeries series) {
|
||||
JLDataView view = getDataView(series);
|
||||
double[] x = new double[view.getDataLength()];
|
||||
double[] y = new double[x.length];
|
||||
int index = 0;
|
||||
DataList data = view.getData();
|
||||
while (data != null) {
|
||||
if (index >= x.length) {
|
||||
break;
|
||||
}
|
||||
x[index] = data.x;
|
||||
y[index] = data.y;
|
||||
index++;
|
||||
data = data.next;
|
||||
}
|
||||
return new double[][]{x, y};
|
||||
}
|
||||
|
||||
JPanel chartPanel;
|
||||
|
||||
@Override
|
||||
protected JPanel createChartPanel() {
|
||||
JPanel chartPanel = new MonitoredPanel() {
|
||||
protected void onShown() {
|
||||
addKeyBindings();
|
||||
}
|
||||
};
|
||||
|
||||
chartPanel.setLayout(new BorderLayout());
|
||||
chartPanel.add(plot);
|
||||
chartPanel.setPreferredSize(new Dimension(480, 240));
|
||||
|
||||
plot.setHeader(getTitle());
|
||||
plot.getY1Axis().setName(getAxis(AxisId.Y).getLabel());
|
||||
plot.getXAxis().setName(getAxis(AxisId.Y).getLabel());
|
||||
return chartPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSeries(LinePlotSeries series) {
|
||||
doUpdate();//TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doUpdate() {
|
||||
plot.repaint();
|
||||
}
|
||||
|
||||
private void addKeyBindings() {
|
||||
//The zoom method ois not doing what I expecte, and no documentation...
|
||||
/*
|
||||
plot.setFocusable( true );
|
||||
plot.requestFocusInWindow();
|
||||
plot.addKeyListener(new KeyListener() {
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
doUpdate();
|
||||
System.out.println("Total " + plot.getXAxis().getMinimum() + "->" + plot.getXAxis().getMaximum());
|
||||
System.out.println("Zoom " + plot.getXAxis().getMin() + "->" + plot.getXAxis().getMax());
|
||||
if (plot.isZoomed()){
|
||||
if (e.getKeyCode()==KeyEvent.VK_RIGHT){
|
||||
double w = plot.getXAxis().getMax()-plot.getXAxis().getMin();
|
||||
double r = plot.getXAxis().getMax() + w/10;
|
||||
//r = Math.min(r,plot.getXAxis().getMaximum());
|
||||
plot.getXAxis().zoom((int)(r-w),(int)r);
|
||||
System.out.println("Zooming to " + ((int)(r-w)) + "-" + ((int)r));
|
||||
requestUpdate();
|
||||
|
||||
}
|
||||
else if (e.getKeyCode()==KeyEvent.VK_LEFT){
|
||||
double w = plot.getXAxis().getMax()-plot.getXAxis().getMin();
|
||||
double l = plot.getXAxis().getMin() - w/10;
|
||||
//l = Math.max(l,plot.getXAxis().getMinimum());
|
||||
plot.getXAxis().zoom((int)l,(int)(l+w));
|
||||
System.out.println("Zooming to " + ((int)l) + "-" + ((int)(l+w)));
|
||||
requestUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
|
||||
}
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
protected void addPopupMenuItem(final JMenuItem item) {
|
||||
if (item == null) {
|
||||
plot.addSeparator();
|
||||
} else {
|
||||
plot.addMenuItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,856 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot.jzy3d;
|
||||
|
||||
import ch.psi.plot.MatrixPlotBase;
|
||||
import ch.psi.plot.MatrixPlotSeries;
|
||||
import ch.psi.plot.utils.IO;
|
||||
import ch.psi.plot.utils.MonitoredPanel;
|
||||
import ch.psi.plot.utils.SwingUtils;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.JCheckBoxMenuItem;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JRadioButtonMenuItem;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.jzy3d.chart.Chart;
|
||||
import org.jzy3d.chart.Settings;
|
||||
import org.jzy3d.colors.Color;
|
||||
import org.jzy3d.colors.ColorMapper;
|
||||
import org.jzy3d.colors.colormaps.ColorMapGrayscale;
|
||||
import org.jzy3d.colors.colormaps.ColorMapRainbow;
|
||||
import org.jzy3d.contour.DefaultContourColoringPolicy;
|
||||
import org.jzy3d.contour.IContourColoringPolicy;
|
||||
import org.jzy3d.contour.MapperContourPictureGenerator;
|
||||
import org.jzy3d.maths.BoundingBox3d;
|
||||
import org.jzy3d.maths.Coord3d;
|
||||
import org.jzy3d.maths.Range;
|
||||
import org.jzy3d.plot3d.builder.Builder;
|
||||
import org.jzy3d.plot3d.builder.Mapper;
|
||||
import org.jzy3d.plot3d.builder.concrete.OrthonormalGrid;
|
||||
import org.jzy3d.plot3d.primitives.AbstractDrawable;
|
||||
import org.jzy3d.plot3d.primitives.Point;
|
||||
import org.jzy3d.plot3d.primitives.Polygon;
|
||||
import org.jzy3d.plot3d.primitives.ScatterMultiColor;
|
||||
import org.jzy3d.plot3d.primitives.Shape;
|
||||
import org.jzy3d.plot3d.primitives.axes.ContourAxeBox;
|
||||
import org.jzy3d.plot3d.rendering.legends.colorbars.AWTColorbarLegend;
|
||||
import org.jzy3d.plot3d.rendering.view.modes.ViewBoundMode;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class MatrixPlot extends MatrixPlotBase {
|
||||
|
||||
JPanel panel;
|
||||
private Chart chart;
|
||||
private Mapper mapper;
|
||||
private Shape surface;
|
||||
private MatrixPlotSeries series;
|
||||
private double[][] data;
|
||||
|
||||
public MatrixPlot() {
|
||||
super();
|
||||
panel = new MonitoredPanel() {
|
||||
protected void onShown() {
|
||||
checkBounds(true);
|
||||
}
|
||||
};
|
||||
panel.setLayout(new BorderLayout());
|
||||
//panel.setLayout(new GridLayout(1,1));
|
||||
setColormap(Colormap.TEMPERATURE);
|
||||
Settings.getInstance().setHardwareAccelerated(true);
|
||||
panel.setPreferredSize(new Dimension(640, 480));
|
||||
setupPopupMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object onAddedSeries(final MatrixPlotSeries s) {
|
||||
if (!SwingUtilities.isEventDispatchThread()) {
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
onAddedSeries(s);
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(MatrixPlot.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
synchronized (chartLock) {
|
||||
if (s != null) {
|
||||
if (chart != null) {
|
||||
chart.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (s == null) {
|
||||
//if (chart != null) {
|
||||
//chart.clear();
|
||||
//}
|
||||
series = null;
|
||||
data = null;
|
||||
} else {
|
||||
if (getAxis(AxisId.X).isAutoRange()) {
|
||||
rangeX = new Range(s.getMinX(), s.getMaxX());
|
||||
} else {
|
||||
rangeX = new Range(getAxis(AxisId.X).getMin(), getAxis(AxisId.X).getMax());
|
||||
}
|
||||
if (getAxis(AxisId.Y).isAutoRange()) {
|
||||
rangeY = new Range(s.getMinY(), s.getMaxY());
|
||||
} else {
|
||||
rangeY = new Range(getAxis(AxisId.Y).getMin(), getAxis(AxisId.Y).getMax());
|
||||
}
|
||||
//If same series & same dimensions then preserve data
|
||||
if ((data == null) || (series != s) || (s.getNumberOfBinsY() != data.length) || (s.getNumberOfBinsX() != data[0].length)) {
|
||||
data = new double[s.getNumberOfBinsY()][s.getNumberOfBinsX()];
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
Arrays.fill(data[i], Double.NaN);
|
||||
}
|
||||
}
|
||||
series = s;
|
||||
}
|
||||
}
|
||||
createGraph();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAxisRangeChanged(AxisId axis_id) {
|
||||
if (series != null) {
|
||||
updateGraph(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemovedSeries(MatrixPlotSeries s) {
|
||||
series = null;
|
||||
if (chart != null) {
|
||||
chart.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAppendData(MatrixPlotSeries s, int indexX, int indexY, double x, double y, double z) {
|
||||
data[indexY][indexX] = z;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetData(MatrixPlotSeries s, double[][] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doUpdate() {
|
||||
updateGraph(false);
|
||||
}
|
||||
|
||||
public void updateSeries(MatrixPlotSeries s) {
|
||||
updateGraph(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double[][] getSeriesData(MatrixPlotSeries s) {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JPanel createChartPanel() {
|
||||
return panel;
|
||||
}
|
||||
|
||||
private Range rangeX;
|
||||
private Range rangeY;
|
||||
double[] rangeZ = null;
|
||||
|
||||
boolean showLegend = true;
|
||||
|
||||
public void setShowLegend(boolean value) {
|
||||
if (value != showLegend) {
|
||||
showLegend = value;
|
||||
if ((panel != null) && (panel.isShowing())) {
|
||||
updateGraph(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getShowLegend() {
|
||||
return showLegend;
|
||||
}
|
||||
|
||||
boolean showFace = true;
|
||||
|
||||
public void setShowFace(boolean value) {
|
||||
if (value != showFace) {
|
||||
showFace = value;
|
||||
if ((panel != null) && (panel.isShowing())) {
|
||||
updateGraph(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getShowFace() {
|
||||
return showFace;
|
||||
}
|
||||
|
||||
boolean showFrame = false;
|
||||
|
||||
public void setShowFrame(boolean value) {
|
||||
if (value != showFrame) {
|
||||
showFrame = value;
|
||||
if ((panel != null) && (panel.isShowing())) {
|
||||
updateGraph(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getShowFrame() {
|
||||
return showFrame;
|
||||
}
|
||||
|
||||
boolean showAxis = true;
|
||||
|
||||
public void setShowAxis(boolean value) {
|
||||
if (value != showAxis) {
|
||||
showAxis = value;
|
||||
if ((panel != null) && (panel.isShowing())) {
|
||||
updateGraph(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getShowAxis() {
|
||||
return showAxis;
|
||||
}
|
||||
|
||||
public enum Colormap {
|
||||
|
||||
GRAYSCALE,
|
||||
TEMPERATURE,
|
||||
}
|
||||
Colormap colormap = Colormap.TEMPERATURE;
|
||||
|
||||
public void setColormap(Colormap value) {
|
||||
if (value != colormap) {
|
||||
colormap = value;
|
||||
if ((panel != null) && (panel.isShowing())) {
|
||||
updateGraph(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Colormap getColormap() {
|
||||
return colormap;
|
||||
}
|
||||
|
||||
public enum Quality {
|
||||
|
||||
LOW,
|
||||
MEDIUM,
|
||||
HIGH,
|
||||
HIGHEST;
|
||||
|
||||
private org.jzy3d.plot3d.rendering.canvas.Quality toJzy3dQuality() {
|
||||
switch (this) {
|
||||
case LOW:
|
||||
return org.jzy3d.plot3d.rendering.canvas.Quality.Fastest;
|
||||
case MEDIUM:
|
||||
return org.jzy3d.plot3d.rendering.canvas.Quality.Intermediate;
|
||||
case HIGH:
|
||||
return org.jzy3d.plot3d.rendering.canvas.Quality.Advanced;
|
||||
case HIGHEST:
|
||||
return org.jzy3d.plot3d.rendering.canvas.Quality.Nicest;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Quality quality = Quality.HIGH;
|
||||
|
||||
public void setQuality(Quality quality) {
|
||||
this.quality = quality;
|
||||
if (series != null) {
|
||||
createGraph();
|
||||
}
|
||||
}
|
||||
|
||||
public Quality getQuality() {
|
||||
return quality;
|
||||
}
|
||||
|
||||
public enum Mode {
|
||||
|
||||
TOP,
|
||||
PROFILE,
|
||||
FREE;
|
||||
|
||||
private org.jzy3d.plot3d.rendering.view.modes.ViewPositionMode toJzy3dMode() {
|
||||
switch (this) {
|
||||
case TOP:
|
||||
return org.jzy3d.plot3d.rendering.view.modes.ViewPositionMode.TOP;
|
||||
case PROFILE:
|
||||
return org.jzy3d.plot3d.rendering.view.modes.ViewPositionMode.PROFILE;
|
||||
case FREE:
|
||||
return org.jzy3d.plot3d.rendering.view.modes.ViewPositionMode.FREE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Mode mode = Mode.FREE;
|
||||
|
||||
public void setMode(Mode mode) {
|
||||
this.mode = mode;
|
||||
if (series != null) {
|
||||
updateGraph(true);
|
||||
}
|
||||
}
|
||||
|
||||
public Mode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public enum Contour {
|
||||
|
||||
NONE,
|
||||
NORMAL,
|
||||
FILLED,
|
||||
HEIGHT_MAP,
|
||||
CONTOUR_3D
|
||||
|
||||
}
|
||||
Contour contour = Contour.NONE;
|
||||
|
||||
public void setContour(Contour contour) {
|
||||
this.contour = contour;
|
||||
if (series != null) {
|
||||
createGraph();
|
||||
}
|
||||
}
|
||||
|
||||
public Contour getContour() {
|
||||
return contour;
|
||||
}
|
||||
|
||||
int contourLevels = 10;
|
||||
|
||||
public void setContourLevels(int value) {
|
||||
contourLevels = value;
|
||||
updateGraph(true);
|
||||
}
|
||||
|
||||
public int getContourLevels() {
|
||||
return contourLevels;
|
||||
}
|
||||
|
||||
int contourDensity = 400;
|
||||
|
||||
public void setContourDensity(int value) {
|
||||
contourDensity = value;
|
||||
updateGraph(true);
|
||||
}
|
||||
|
||||
public int getContourDensity() {
|
||||
return contourDensity;
|
||||
}
|
||||
|
||||
java.awt.Color frameColor = java.awt.Color.BLACK;
|
||||
|
||||
public void setFrameColor(java.awt.Color value) {
|
||||
frameColor = value;
|
||||
updateGraph(true);
|
||||
}
|
||||
|
||||
public java.awt.Color getFrameColor() {
|
||||
return frameColor;
|
||||
}
|
||||
|
||||
JPopupMenu menuPopup;
|
||||
|
||||
void setupPopupMenu() {
|
||||
menuPopup = new JPopupMenu();
|
||||
JMenuItem menuUpdate = new JMenuItem("Update");
|
||||
final JCheckBoxMenuItem menuShowAxis = new JCheckBoxMenuItem("Show Axis");
|
||||
final JCheckBoxMenuItem menuShowLegend = new JCheckBoxMenuItem("Show Legend");
|
||||
final JCheckBoxMenuItem menuShowFace = new JCheckBoxMenuItem("Show Face");
|
||||
final JCheckBoxMenuItem menuShowFrame = new JCheckBoxMenuItem("Show Frame");
|
||||
JMenuItem frameColor = new JMenuItem("Set Frame Color");
|
||||
|
||||
final JMenu menuColormap = new JMenu("Colormap");
|
||||
final JMenu menuMode = new JMenu("Mode");
|
||||
final JMenu menuContour = new JMenu("Contour");
|
||||
final JMenu menuQuality = new JMenu("Quality");
|
||||
menuPopup.add(menuShowAxis);
|
||||
menuPopup.add(menuShowLegend);
|
||||
menuPopup.add(menuShowFace);
|
||||
menuPopup.add(menuShowFrame);
|
||||
menuPopup.add(frameColor);
|
||||
menuPopup.add(menuColormap);
|
||||
menuPopup.add(menuMode);
|
||||
menuPopup.add(menuContour);
|
||||
menuPopup.add(menuQuality);
|
||||
menuPopup.add(menuUpdate);
|
||||
menuUpdate.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
updateGraph(true);
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frameColor.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
String ret = SwingUtils.getString(panel, "Enter frame color (name or R,G,B):", getFrameColor().getRed() + "," + getFrameColor().getGreen() + "," + getFrameColor().getBlue());
|
||||
if (ret != null) {
|
||||
java.awt.Color color = null;
|
||||
if (ret.contains(",")) {
|
||||
String[] tokens = ret.split(",");
|
||||
color = new java.awt.Color(Integer.valueOf(tokens[0]), Integer.valueOf(tokens[1]), Integer.valueOf(tokens[2]));
|
||||
} else {
|
||||
Field field = java.awt.Color.class.getField(ret);
|
||||
color = (java.awt.Color) field.get(null);
|
||||
}
|
||||
setFrameColor(color);
|
||||
updateGraph(true);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
SwingUtils.showException(panel, ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
menuShowFrame.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
setShowFrame(!getShowFrame());
|
||||
menuShowFrame.setSelected(getShowFrame());
|
||||
}
|
||||
});
|
||||
menuShowFrame.setSelected(getShowFrame());
|
||||
|
||||
menuShowLegend.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
setShowLegend(!getShowLegend());
|
||||
menuShowLegend.setSelected(getShowLegend());
|
||||
}
|
||||
});
|
||||
menuShowLegend.setSelected(getShowLegend());
|
||||
|
||||
menuShowFace.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
setShowFace(!getShowFace());
|
||||
menuShowLegend.setSelected(getShowFace());
|
||||
}
|
||||
});
|
||||
menuShowFace.setSelected(getShowFace());
|
||||
|
||||
menuShowAxis.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
setShowAxis(!getShowAxis());
|
||||
menuShowAxis.setSelected(getShowAxis());
|
||||
}
|
||||
});
|
||||
menuShowAxis.setSelected(getShowAxis());
|
||||
|
||||
ButtonGroup colormapGroup = new ButtonGroup();
|
||||
for (Colormap c : Colormap.values()) {
|
||||
final JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(c.toString());
|
||||
colormapGroup.add(menuItem);
|
||||
menuItem.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
setColormap(Colormap.valueOf(e.getActionCommand()));
|
||||
}
|
||||
});
|
||||
menuItem.setSelected(getColormap().toString().equals(menuItem.getText()));
|
||||
menuColormap.add(menuItem);
|
||||
}
|
||||
|
||||
ButtonGroup modeGroup = new ButtonGroup();
|
||||
for (Mode q : Mode.values()) {
|
||||
final JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(q.toString());
|
||||
modeGroup.add(menuItem);
|
||||
menuItem.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
setMode(Mode.valueOf(e.getActionCommand()));
|
||||
}
|
||||
});
|
||||
menuItem.setSelected(getMode().toString().equals(menuItem.getText()));
|
||||
menuMode.add(menuItem);
|
||||
}
|
||||
|
||||
ButtonGroup contourGroup = new ButtonGroup();
|
||||
for (Contour q : Contour.values()) {
|
||||
final JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(q.toString());
|
||||
contourGroup.add(menuItem);
|
||||
menuItem.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
setContour(Contour.valueOf(e.getActionCommand()));
|
||||
}
|
||||
});
|
||||
menuItem.setSelected(getContour().toString().equals(menuItem.getText()));
|
||||
menuContour.add(menuItem);
|
||||
}
|
||||
menuContour.addSeparator();
|
||||
JMenuItem levels = new JMenuItem("Set Levels");
|
||||
levels.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
String ret = SwingUtils.getString(panel, "Enter number of contour levels:", getContourLevels());
|
||||
if (ret != null) {
|
||||
Integer levels = Integer.valueOf(ret);
|
||||
setContourLevels(levels);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
SwingUtils.showException(panel, ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
menuContour.add(levels);
|
||||
|
||||
JMenuItem density = new JMenuItem("Set Density");
|
||||
density.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
String ret = SwingUtils.getString(panel, "Enter contour density:", getContourDensity());
|
||||
if (ret != null) {
|
||||
Integer density = Integer.valueOf(ret);
|
||||
setContourDensity(density);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
SwingUtils.showException(panel, ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
menuContour.add(density);
|
||||
|
||||
ButtonGroup qualityGroup = new ButtonGroup();
|
||||
for (Quality q : Quality.values()) {
|
||||
final JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(q.toString());
|
||||
qualityGroup.add(menuItem);
|
||||
menuItem.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
setQuality(Quality.valueOf(e.getActionCommand()));
|
||||
}
|
||||
});
|
||||
menuItem.setSelected(getQuality().toString().equals(menuItem.getText()));
|
||||
menuQuality.add(menuItem);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void remap(Shape shape, Mapper mapper) {
|
||||
List<AbstractDrawable> polygons = shape.getDrawables();
|
||||
for (AbstractDrawable d : polygons) {
|
||||
if (d instanceof Polygon) {
|
||||
Polygon p = (Polygon) d;
|
||||
for (int i = 0; i < p.size(); i++) {
|
||||
Point pt = p.get(i);
|
||||
Coord3d c = pt.xyz;
|
||||
c.z = (float) mapper.f(c.x, c.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Object chartLock = new Object();
|
||||
|
||||
void createGraph() { /*
|
||||
if (!SwingUtilities.isEventDispatchThread()) {
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
createGraph();
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(MatrixPlot.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
synchronized (chartLock) {
|
||||
if (series != null) {
|
||||
if ((getContour() == Contour.NONE) || (getContour() == Contour.CONTOUR_3D)) {
|
||||
chart = org.jzy3d.chart.factories.ContourChartComponentFactory.chart(getQuality().toJzy3dQuality(), "awt");
|
||||
} else {
|
||||
chart = new org.jzy3d.chart.factories.ContourChartComponentFactory().newChart(getQuality().toJzy3dQuality(), "awt");
|
||||
}
|
||||
|
||||
if (rangeY == null) {
|
||||
rangeY = new Range(0, data.length - 1);
|
||||
}
|
||||
if (rangeX == null) {
|
||||
rangeX = new Range(0, data[0].length - 1);
|
||||
}
|
||||
mapper = new Mapper() {
|
||||
@Override
|
||||
public double f(double x, double y) {
|
||||
if (data == null) {
|
||||
return Double.NaN;
|
||||
}
|
||||
return data[(int) Math.round((y - rangeY.getMin()) / ((rangeY.getMax() - rangeY.getMin()) / (data.length - 1)))][(int) Math.round((x - rangeX.getMin()) / ((rangeX.getMax() - rangeX.getMin()) / (data[0].length - 1)))];
|
||||
|
||||
}
|
||||
};
|
||||
Component canvas = (Component) chart.getCanvas();
|
||||
panel.removeAll();
|
||||
panel.add(canvas);
|
||||
|
||||
//Todo: why it is not displyed if I don'r pack the Window?
|
||||
if (panel.isVisible()) {
|
||||
panel.validate();
|
||||
}
|
||||
|
||||
chart.addMouseController();
|
||||
chart.getAxeLayout().setXAxeLabel(getAxis(AxisId.X).getLabel());
|
||||
chart.getAxeLayout().setYAxeLabel(getAxis(AxisId.Y).getLabel());
|
||||
chart.getAxeLayout().setZAxeLabel(getAxis(AxisId.Z).getLabel());
|
||||
|
||||
chart.getCanvas().addMouseController(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
checkPopup(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
checkPopup(e);
|
||||
}
|
||||
|
||||
private void checkPopup(MouseEvent e) {
|
||||
if (e.isPopupTrigger()) {
|
||||
menuPopup.show(e.getComponent(), e.getX(), e.getY());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateGraph(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void updateGraph(final boolean newSeries) {
|
||||
if (!SwingUtilities.isEventDispatchThread()) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateGraph(newSeries);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
//long start = System.currentTimeMillis();
|
||||
synchronized (chartLock) {
|
||||
Shape former = surface;
|
||||
if (series == null) {
|
||||
if (surface != null) {
|
||||
chart.getScene().getGraph().remove(former, false);
|
||||
}
|
||||
surface = null;
|
||||
} else {
|
||||
|
||||
//TODO: Not succeding having the partial updates - and they are not performing much better neither
|
||||
boolean changedBoundsZ = checkBounds(false);
|
||||
if ((surface == null) || (newSeries) || getAxis(AxisId.Z).isAutoRange() || changedBoundsZ) {
|
||||
//if (true) {
|
||||
surface = (Shape) Builder.buildOrthonormal(
|
||||
new OrthonormalGrid(rangeX, series.getNumberOfBinsX(), rangeY, series.getNumberOfBinsY()), mapper);
|
||||
ColorMapper colorMapper = new ColorMapper((colormap == Colormap.TEMPERATURE) ? new ColorMapRainbow() : new ColorMapGrayscale(),
|
||||
(float) ((getAxis(AxisId.Z).isAutoRange()) ? surface.getBounds().getZmin() : getAxis(AxisId.Z).getMin()),
|
||||
(float) ((getAxis(AxisId.Z).isAutoRange()) ? surface.getBounds().getZmax() : getAxis(AxisId.Z).getMax()),
|
||||
new Color(1, 1, 1, .5f));
|
||||
surface.setColorMapper(colorMapper);
|
||||
surface.setFaceDisplayed(true);
|
||||
surface.setWireframeDisplayed(getShowFrame());
|
||||
|
||||
surface.setWireframeColor(new Color(frameColor.getRed(), frameColor.getGreen(), frameColor.getBlue(), frameColor.getAlpha()));
|
||||
surface.setFaceDisplayed(getShowFace());
|
||||
if (getShowLegend()) {
|
||||
AWTColorbarLegend cbar = new AWTColorbarLegend(surface, chart.getView().getAxe().getLayout());
|
||||
surface.setLegend(cbar);
|
||||
}
|
||||
|
||||
if (getContour() != Contour.NONE) {
|
||||
int xRes = getContourDensity();
|
||||
int yRes = getContourDensity();
|
||||
|
||||
MapperContourPictureGenerator contour = new MapperContourPictureGenerator(mapper, rangeX, rangeY);
|
||||
IContourColoringPolicy policy = new DefaultContourColoringPolicy(colorMapper);
|
||||
ContourAxeBox cab = (getContour() == Contour.CONTOUR_3D) ? null : (ContourAxeBox) chart.getView().getAxe();
|
||||
|
||||
switch (getContour()) {
|
||||
case NORMAL:
|
||||
cab.setContourImg(contour.getContourImage(policy, xRes, yRes, getContourLevels()), rangeX, rangeY);
|
||||
break;
|
||||
case FILLED:
|
||||
cab.setContourImg(contour.getFilledContourImage(policy, xRes, yRes, getContourLevels()), rangeX, rangeY);
|
||||
break;
|
||||
case HEIGHT_MAP:
|
||||
cab.setContourImg(contour.getHeightMap(policy, xRes, yRes, getContourLevels()), rangeX, rangeY);
|
||||
break;
|
||||
case CONTOUR_3D:
|
||||
//int nx=series.getNumberOfBinsX();
|
||||
//int ny=series.getNumberOfBinsY();
|
||||
|
||||
float dx = ((float) series.getNumberOfBinsX()) / xRes;
|
||||
float dy = ((float) series.getNumberOfBinsY()) / yRes;
|
||||
double[][] contours = contour.getContourMatrix(xRes, yRes, getContourLevels());
|
||||
// Create the dot cloud scene and fill with data
|
||||
int size = xRes * yRes;
|
||||
Coord3d[] points = new Coord3d[size];
|
||||
for (int x = 0; x < xRes; x++) {
|
||||
for (int y = 0; y < yRes; y++) {
|
||||
float px = (float) ((float) x * dx * series.getBinWidthX() + series.getMinX());
|
||||
float py = (float) ((float) y * dy * series.getBinWidthY() + series.getMinY());
|
||||
|
||||
if (contours[x][y] > -Double.MAX_VALUE) { // Non contours points are -Double.MAX_VALUE and are not painted
|
||||
points[x * yRes + y] = new Coord3d(px, py, (float) contours[x][y]);
|
||||
} else {
|
||||
points[x * yRes + y] = new Coord3d(px, py, Float.NaN);
|
||||
//points[x*ny+y] = new Coord3d((float)x * series.getBinWidthX()+ series.getMinX(),(float)y* series.getBinWidthY()+ series.getMinY(),(float)0.0);
|
||||
|
||||
//points[x*ny+y] = new Coord3d((float)x * series.getBinWidthX()+ series.getMinX(),(float)y* series.getBinWidthY()+ series.getMinY(),(float)mapper.f((float)x * series.getBinWidthX()+ series.getMinX(), (float)y* series.getBinWidthY()+ series.getMinY()));
|
||||
}
|
||||
}
|
||||
}
|
||||
//ScatterMultiColor scatter = new ScatterMultiColor( points, new ColorMapper( new ColorMapRainbow(), -600.0f, 600.0f ) );
|
||||
ScatterMultiColor scatter = new ScatterMultiColor(points, colorMapper);
|
||||
surface.add(scatter);
|
||||
//chart.getScene().add(scatter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
chart.setViewMode(getMode().toJzy3dMode());
|
||||
chart.setAxeDisplayed(getShowAxis());
|
||||
}
|
||||
|
||||
if (surface == former) {
|
||||
remap(surface, mapper);
|
||||
chart.render();
|
||||
} else {
|
||||
|
||||
chart.getScene().getGraph().add(surface, false);
|
||||
if (former != null) {
|
||||
chart.getScene().getGraph().remove(former, false);
|
||||
}
|
||||
boolean changed = checkBounds(true);
|
||||
//if (!changed)
|
||||
// chart.getView().updateBounds();
|
||||
|
||||
}
|
||||
}
|
||||
//System.out.println(System.currentTimeMillis()-start);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean checkBounds(boolean updateBounds) {
|
||||
if (chart == null) {
|
||||
return false;
|
||||
}
|
||||
boolean changed = false;
|
||||
//If manual bounds
|
||||
if (!getAxis(AxisId.X).isAutoRange() || !getAxis(AxisId.Y).isAutoRange() || !getAxis(AxisId.Z).isAutoRange()) {
|
||||
//Deferring setting bounds untiul the panel is displayed
|
||||
if (panel.isShowing() && (chart != null)) {
|
||||
if (chart.getView().getBoundsMode() != ViewBoundMode.MANUAL) {
|
||||
changed = true;
|
||||
}
|
||||
BoundingBox3d bounds = chart.getView().getBounds();
|
||||
if (!getAxis(AxisId.X).isAutoRange()) {
|
||||
if (bounds.getXmin() != getAxis(AxisId.X).getMin()) {
|
||||
bounds.setXmin((float) getAxis(AxisId.X).getMin());
|
||||
changed = true;
|
||||
}
|
||||
if (bounds.getXmax() != getAxis(AxisId.X).getMax()) {
|
||||
bounds.setXmax((float) getAxis(AxisId.X).getMax());
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (!getAxis(AxisId.Y).isAutoRange()) {
|
||||
if (bounds.getYmin() != getAxis(AxisId.Y).getMin()) {
|
||||
bounds.setYmin((float) getAxis(AxisId.Y).getMin());
|
||||
changed = true;
|
||||
}
|
||||
if (bounds.getYmax() != getAxis(AxisId.Y).getMax()) {
|
||||
bounds.setYmax((float) getAxis(AxisId.Y).getMax());
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (!getAxis(AxisId.Z).isAutoRange()) {
|
||||
if (bounds.getZmin() != getAxis(AxisId.Z).getMin()) {
|
||||
bounds.setZmin((float) getAxis(AxisId.Z).getMin());
|
||||
changed = true;
|
||||
}
|
||||
if (bounds.getZmax() != getAxis(AxisId.Z).getMax()) {
|
||||
bounds.setZmax((float) getAxis(AxisId.Z).getMax());
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed && updateBounds) {
|
||||
chart.getView().setBoundManual(bounds);
|
||||
}
|
||||
}
|
||||
} else if (chart.getView().getBoundsMode() != ViewBoundMode.AUTO_FIT) {
|
||||
if (updateBounds) {
|
||||
chart.getView().setBoundMode(ViewBoundMode.AUTO_FIT);
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
protected void addPopupMenuItem(final JMenuItem item) {
|
||||
if (item == null) {
|
||||
menuPopup.addSeparator();
|
||||
} else {
|
||||
menuPopup.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage getSnapshot() {
|
||||
|
||||
File temp=null;
|
||||
try{
|
||||
temp = File.createTempFile("snapshot", ".bmp");
|
||||
chart.screenshot(temp);
|
||||
return IO.readImageFromFile(temp.getAbsolutePath());
|
||||
}
|
||||
catch (Exception ex){
|
||||
return null;
|
||||
}
|
||||
finally{
|
||||
if (temp!=null)
|
||||
temp.delete();
|
||||
}
|
||||
}
|
||||
|
||||
public void saveSnapshot(String filename, String format) throws IOException {
|
||||
if (chart!=null){
|
||||
chart.screenshot(new File(filename));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot.utils;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class IO {
|
||||
|
||||
public static void writeArrayToFile(String filename, byte arr[]) throws IOException {
|
||||
|
||||
OutputStream fout = null;
|
||||
try {
|
||||
fout = new BufferedOutputStream(new FileOutputStream(filename, false));
|
||||
if (arr != null) {
|
||||
new PrintStream(fout).write(arr, 0, arr.length);
|
||||
}
|
||||
fout.flush();
|
||||
} finally {
|
||||
if (fout != null) {
|
||||
fout.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeStringToFile(String filename, String str) throws IOException {
|
||||
writeArrayToFile(filename, str.getBytes("UTF-8"));
|
||||
}
|
||||
|
||||
public static void writeImageToFile(BufferedImage image, String filename, String format) throws IOException {
|
||||
if (image != null) {
|
||||
ImageIO.write(image, format, new File(filename));
|
||||
}
|
||||
}
|
||||
|
||||
public static BufferedImage readImageFromFile(String filename) throws IOException {
|
||||
return ImageIO.read(new File(filename));
|
||||
}
|
||||
|
||||
public static String getExtension(File f) {
|
||||
String ext = null;
|
||||
String s = f.getName();
|
||||
int i = s.lastIndexOf('.');
|
||||
|
||||
if (i > 0 && i < s.length() - 1) {
|
||||
ext = s.substring(i + 1).toLowerCase();
|
||||
}
|
||||
return ext;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package ch.psi.plot.utils;
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
import java.awt.event.HierarchyEvent;
|
||||
import java.awt.event.HierarchyListener;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class MonitoredPanel extends JPanel {
|
||||
|
||||
public MonitoredPanel() {
|
||||
addHierarchyListener(new HierarchyListener() {
|
||||
@Override
|
||||
public void hierarchyChanged(HierarchyEvent e) {
|
||||
if ((HierarchyEvent.SHOWING_CHANGED & e.getChangeFlags()) != 0) {
|
||||
if (isShowing()) {
|
||||
try {
|
||||
onShown();
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
onHidden();
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void onShown() {
|
||||
}
|
||||
|
||||
protected void onHidden() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot.utils;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Random;
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class SwingUtils {
|
||||
|
||||
public static void centerOnParent(Component parent, Component component) {
|
||||
Rectangle r = parent.getBounds();
|
||||
Dimension w = component.getSize();
|
||||
int x = Math.max(r.x + (r.width - w.width) / 2, 4);
|
||||
int y = Math.max(r.y + (r.height - w.height) / 2, 4);
|
||||
component.setLocation(x, y);
|
||||
}
|
||||
|
||||
public static void centerOnScreen(Component component) {
|
||||
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
|
||||
component.setLocation(dim.width / 2 - component.getSize().width / 2, dim.height / 2 - component.getSize().height / 2);
|
||||
}
|
||||
|
||||
public static Color generateRandomColor() {
|
||||
Random random = new Random();
|
||||
|
||||
Color mix = Color.WHITE;
|
||||
int red = (random.nextInt(256) + mix.getRed()) / 2;
|
||||
int green = (random.nextInt(256) + mix.getGreen()) / 2;
|
||||
int blue = (random.nextInt(256) + mix.getBlue()) / 2;
|
||||
|
||||
Color color = new Color(red, green, blue);
|
||||
return color;
|
||||
}
|
||||
|
||||
public static void showMessage(Component parent, String title, String msg) {
|
||||
JOptionPane.showMessageDialog(parent, msg, title, JOptionPane.INFORMATION_MESSAGE, null);
|
||||
}
|
||||
|
||||
public static void showException(Component parent, Exception ex) {
|
||||
JOptionPane.showMessageDialog(parent, ex.getMessage(), "Exception", JOptionPane.WARNING_MESSAGE, null);
|
||||
}
|
||||
|
||||
public static String getString(Component parent, String msg, Object current_value) {
|
||||
return JOptionPane.showInputDialog(parent, msg, String.valueOf(current_value));
|
||||
}
|
||||
|
||||
public static BufferedImage createImage(Component panel) {
|
||||
if (panel == null) {
|
||||
return null;
|
||||
}
|
||||
Dimension size = panel.getSize();
|
||||
BufferedImage image = new BufferedImage(
|
||||
size.width, size.height, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g2 = image.createGraphics();
|
||||
panel.paint(g2);
|
||||
return image;
|
||||
}
|
||||
}
|
||||
@@ -1,472 +0,0 @@
|
||||
package ch.psi.plot.xy;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import org.jfree.chart.ChartFactory;
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.annotations.XYAnnotation;
|
||||
import org.jfree.chart.annotations.XYDrawableAnnotation;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.entity.StandardEntityCollection;
|
||||
import org.jfree.chart.labels.StandardXYToolTipGenerator;
|
||||
import org.jfree.chart.labels.XYToolTipGenerator;
|
||||
import org.jfree.chart.plot.Marker;
|
||||
import org.jfree.chart.plot.PlotOrientation;
|
||||
import org.jfree.chart.plot.ValueMarker;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
|
||||
import org.jfree.data.Range;
|
||||
import org.jfree.data.xy.XYDataItem;
|
||||
import org.jfree.ui.Layer;
|
||||
import org.jfree.ui.RectangleAnchor;
|
||||
import org.jfree.ui.RefineryUtilities;
|
||||
import org.jfree.ui.TextAnchor;
|
||||
|
||||
import ch.psi.plot.Plot;
|
||||
import ch.psi.plot.xy.tools.Average;
|
||||
import ch.psi.plot.xy.tools.CrossAnnotation;
|
||||
import ch.psi.plot.xy.tools.Derivative;
|
||||
import ch.psi.plot.xy.tools.Integral;
|
||||
import ch.psi.plot.xy.tools.Maximum;
|
||||
import ch.psi.plot.xy.tools.Minimum;
|
||||
|
||||
public class LinePlot implements Plot {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(LinePlot.class.getName());
|
||||
|
||||
private ChartPanel chartPanel;
|
||||
|
||||
private static final int chartPanelWidth = 500;
|
||||
private static final int chartPanelHeight = 270;
|
||||
|
||||
//Defining Context Menu Label
|
||||
private static final String showLegendMenuLabel = "Show Legend";
|
||||
private static final String hideLegendMenuLabel = "Hide Legend";
|
||||
private static final String showTooltipsMenuLabel = "Show Tooltips";
|
||||
private static final String hideTooltipsMenuLabel = "Hide Tooltips";
|
||||
|
||||
|
||||
private XYSeriesCollectionP data;
|
||||
|
||||
JFreeChart chart;
|
||||
|
||||
private String title;
|
||||
private String xAxisLabel = "X";
|
||||
private String yAxisLabel = "Y";
|
||||
|
||||
private boolean tooltips = false;
|
||||
|
||||
/**
|
||||
* @param title Title of plot
|
||||
*/
|
||||
public LinePlot(String title){
|
||||
this(title, new XYSeriesCollectionP());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param title Title of plot
|
||||
* @param data Data of plot
|
||||
*/
|
||||
public LinePlot(String title, XYSeriesCollectionP data){
|
||||
this.title = title;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the chart panel of this plot. The chart panel will be lazily created
|
||||
* the first time this function is called
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public ChartPanel getChartPanel() {
|
||||
if(chartPanel == null){
|
||||
|
||||
// Create chart
|
||||
chart = ChartFactory.createXYLineChart(this.title, xAxisLabel, yAxisLabel, data, PlotOrientation.VERTICAL, true, tooltips, false);
|
||||
|
||||
// Customize chart look and feel
|
||||
// Customize background (gray: new Color(238,238,238))
|
||||
chart.setBackgroundPaint(null);
|
||||
|
||||
// Customize legend
|
||||
chart.getLegend().setVisible(false);
|
||||
chart.getLegend().setBackgroundPaint(null);
|
||||
chart.getLegend().setBorder(0, 0, 0, 0);
|
||||
|
||||
// Customize plot area look and feel
|
||||
XYPlot plot = (XYPlot) chart.getPlot();
|
||||
plot.setBackgroundPaint(Color.white);
|
||||
plot.setDomainGridlinePaint(Color.gray);
|
||||
plot.setRangeGridlinePaint(Color.gray);
|
||||
|
||||
// Show data point
|
||||
((XYLineAndShapeRenderer)plot.getRenderer()).setBaseShapesVisible(true);
|
||||
|
||||
// Include zeros in range (x) axis
|
||||
((NumberAxis) plot.getRangeAxis()).setAutoRangeIncludesZero(false);
|
||||
|
||||
// Lazy creation of the chart panel
|
||||
chartPanel = new ChartPanel(chart);
|
||||
chartPanel.setName(title);
|
||||
|
||||
// Remove border
|
||||
chartPanel.getChart().setBorderVisible(false);
|
||||
|
||||
// Set size of chart
|
||||
chartPanel.setPreferredSize(new java.awt.Dimension(chartPanelWidth, chartPanelHeight));
|
||||
|
||||
// Add more items to the context menu
|
||||
amendContextMenu();
|
||||
|
||||
//Activate (arrow) keys
|
||||
addKeyBindings();
|
||||
}
|
||||
return chartPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change visible part of chart
|
||||
* @param translationVector
|
||||
*/
|
||||
private void moverOverPlot(XYDataItem translationVector) {
|
||||
double translatedDomainIntervalMin = chart.getXYPlot().getDomainAxis().getRange().getLowerBound() + translationVector.getX().doubleValue();
|
||||
double translatedDomainIntervalMax = chart.getXYPlot().getDomainAxis().getRange().getUpperBound() + translationVector.getX().doubleValue();
|
||||
double translatedRangeIntervalMin = chart.getXYPlot().getRangeAxis().getRange().getLowerBound() + translationVector.getY().doubleValue();
|
||||
double translatedRangeIntervalMax = chart.getXYPlot().getRangeAxis().getRange().getUpperBound() + translationVector.getY().doubleValue();
|
||||
|
||||
Range domainAxisRange = new Range(translatedDomainIntervalMin, translatedDomainIntervalMax);
|
||||
Range rangeAxisRange = new Range(translatedRangeIntervalMin, translatedRangeIntervalMax);
|
||||
//We set notify to false in the first call..
|
||||
chart.getXYPlot().getDomainAxis().setRange(domainAxisRange, true, false);
|
||||
//...and true in the last
|
||||
chart.getXYPlot().getRangeAxis().setRange(rangeAxisRange, true, true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add key bindings to chart panel
|
||||
*/
|
||||
private void addKeyBindings(){
|
||||
final String moveUpKey = "move up";
|
||||
final String moveDownKey = "move down";
|
||||
final String moveRightKey = "move right";
|
||||
final String moveLeftKey = "move left";
|
||||
|
||||
// Up arrow
|
||||
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), moveUpKey);
|
||||
chartPanel.getActionMap().put(moveUpKey, new AbstractAction() {
|
||||
// Default serial id
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
moverOverPlot(new XYDataItem(0.0, ((NumberAxis)chart.getXYPlot().getRangeAxis()).getTickUnit().getSize()));
|
||||
}
|
||||
});
|
||||
|
||||
// Down arrow
|
||||
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),moveDownKey);
|
||||
chartPanel.getActionMap().put(moveDownKey, new AbstractAction() {
|
||||
// Default serial id
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
moverOverPlot(new XYDataItem(0.0, - ((NumberAxis)chart.getXYPlot().getRangeAxis()).getTickUnit().getSize()));
|
||||
}
|
||||
});
|
||||
|
||||
// Right arrow
|
||||
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),moveRightKey);
|
||||
chartPanel.getActionMap().put(moveRightKey, new AbstractAction() {
|
||||
// Default serial id
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
moverOverPlot(new XYDataItem(((NumberAxis)chart.getXYPlot().getDomainAxis()).getTickUnit().getSize(), 0.0));
|
||||
}
|
||||
});
|
||||
|
||||
// Left arrow
|
||||
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),moveLeftKey);
|
||||
chartPanel.getActionMap().put(moveLeftKey, new AbstractAction() {
|
||||
// Default serial id
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
moverOverPlot(new XYDataItem(- ((NumberAxis)chart.getXYPlot().getDomainAxis()).getTickUnit().getSize(), 0.0));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional items to the context menu of the plot
|
||||
*/
|
||||
public void amendContextMenu(){
|
||||
|
||||
chartPanel.getPopupMenu().addSeparator();
|
||||
|
||||
JMenu toolsMenu = new JMenu("Tools");
|
||||
chartPanel.getPopupMenu().add(toolsMenu);
|
||||
|
||||
// Mark average
|
||||
JMenuItem averageMenuItem = new JMenuItem("Average");
|
||||
averageMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Average average = new Average();
|
||||
for (XYSeriesP series : data.getSeries()) {
|
||||
double a = average.average(series);
|
||||
// Remove all range markers
|
||||
Collection<?> c = chartPanel.getChart().getXYPlot().getRangeMarkers(Layer.FOREGROUND);
|
||||
if(c!=null){
|
||||
for(final Object marker: c){
|
||||
SwingUtilities.invokeLater(new Runnable() { // Avoid concurrent modification exception
|
||||
@Override
|
||||
public void run() {
|
||||
chartPanel.getChart().getXYPlot().removeRangeMarker((Marker) marker);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
final ValueMarker marker = new ValueMarker(a, Color.BLACK, new BasicStroke(1));
|
||||
marker.setLabel("Average ["+series.getKey()+"]: "+String.format("%.6f", a));
|
||||
marker.setLabelAnchor(RectangleAnchor.CENTER);
|
||||
marker.setLabelTextAnchor(TextAnchor.TOP_RIGHT);
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() { // Avoid concurrent modification exception
|
||||
@Override
|
||||
public void run() {
|
||||
chartPanel.getChart().getXYPlot().addRangeMarker(marker, Layer.FOREGROUND);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
toolsMenu.add(averageMenuItem);
|
||||
|
||||
|
||||
// Mark minimum value
|
||||
JMenuItem minimumMenuItem = new JMenuItem("Minimum");
|
||||
minimumMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Minimum minimum = new Minimum();
|
||||
for (XYSeriesP series : data.getSeries()) {
|
||||
XYDataItem m = minimum.minimum(series);
|
||||
// System.out.println("Minimum: "+m.getXValue());
|
||||
// Remove all annotation for the series
|
||||
for(Object o: chartPanel.getChart().getXYPlot().getAnnotations()){
|
||||
chartPanel.getChart().getXYPlot().removeAnnotation((XYAnnotation) o);
|
||||
}
|
||||
XYDrawableAnnotation cross = new XYDrawableAnnotation(m.getXValue(), m.getYValue(), 10.0, 10.0, new CrossAnnotation(Color.BLACK));
|
||||
cross.setToolTipText("Minimum: "+m.getXValue() +" / "+ m.getYValue());
|
||||
chartPanel.getChart().getXYPlot().addAnnotation(cross);
|
||||
}
|
||||
}
|
||||
});
|
||||
toolsMenu.add(minimumMenuItem);
|
||||
|
||||
|
||||
// Mark maximum value
|
||||
JMenuItem maximumMenuItem = new JMenuItem("Maximum");
|
||||
maximumMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Maximum maximum = new Maximum();
|
||||
for (XYSeriesP series : data.getSeries()) {
|
||||
XYDataItem m = maximum.maximum(series);
|
||||
// Remove all annotation for the series
|
||||
for(Object o: chartPanel.getChart().getXYPlot().getAnnotations()){
|
||||
chartPanel.getChart().getXYPlot().removeAnnotation((XYAnnotation) o);
|
||||
}
|
||||
XYDrawableAnnotation cross = new XYDrawableAnnotation(m.getXValue(), m.getYValue(), 10.0, 10.0, new CrossAnnotation(Color.BLACK));
|
||||
cross.setToolTipText("Maximum: "+m.getXValue() +" / "+ m.getYValue());
|
||||
chartPanel.getChart().getXYPlot().addAnnotation(cross);
|
||||
}
|
||||
}
|
||||
});
|
||||
toolsMenu.add(maximumMenuItem);
|
||||
|
||||
|
||||
// Show derivative
|
||||
JMenuItem derivativeMenuItem = new JMenuItem("Derivative");
|
||||
derivativeMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Derivative derivative = new Derivative();
|
||||
LinePlot p = new LinePlot("Derivative - " + title, derivative.derivative(data));
|
||||
|
||||
JFrame frame = new JFrame();
|
||||
frame.setContentPane(p.getChartPanel());
|
||||
frame.pack();
|
||||
RefineryUtilities.centerFrameOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
toolsMenu.add(derivativeMenuItem);
|
||||
|
||||
// Show integral
|
||||
JMenuItem integralMenuItem = new JMenuItem("Integral");
|
||||
integralMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Integral integral = new Integral();
|
||||
|
||||
// Show new frame
|
||||
LinePlot p = new LinePlot("Integral - "+title, integral.integral(data));
|
||||
|
||||
JFrame frame = new JFrame();
|
||||
frame.setContentPane(p.getChartPanel());
|
||||
frame.pack();
|
||||
RefineryUtilities.centerFrameOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
toolsMenu.add(integralMenuItem);
|
||||
|
||||
chartPanel.getPopupMenu().addSeparator();
|
||||
|
||||
// Detach plot into a separate frame
|
||||
JMenuItem detachPlotMenuItem = new JMenuItem("Detach");
|
||||
detachPlotMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
LinePlot p = new LinePlot(title, data);
|
||||
|
||||
JFrame frame = new JFrame();
|
||||
frame.setContentPane(p.getChartPanel());
|
||||
frame.pack();
|
||||
RefineryUtilities.centerFrameOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
chartPanel.getPopupMenu().add(detachPlotMenuItem);
|
||||
|
||||
// Hide/Show legend
|
||||
JMenuItem hideLegendMenuItem = new JMenuItem(showLegendMenuLabel);
|
||||
hideLegendMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuItem source = (JMenuItem)(e.getSource());
|
||||
|
||||
if(source.getText() == showLegendMenuLabel){
|
||||
chart.getLegend().setVisible(true);
|
||||
source.setText(hideLegendMenuLabel);
|
||||
}
|
||||
|
||||
else if(source.getText() == hideLegendMenuLabel){
|
||||
chart.getLegend().setVisible(false);
|
||||
source.setText(showLegendMenuLabel);
|
||||
}
|
||||
}
|
||||
});
|
||||
chartPanel.getPopupMenu().add(hideLegendMenuItem);
|
||||
|
||||
// Hide/Show tooltips
|
||||
JMenuItem hideToolTipsMenuItem = new JMenuItem(hideTooltipsMenuLabel);
|
||||
if(!tooltips){
|
||||
hideToolTipsMenuItem.setText(showTooltipsMenuLabel);
|
||||
}
|
||||
hideToolTipsMenuItem.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuItem source = (JMenuItem)(e.getSource());
|
||||
if(source.getText() == showTooltipsMenuLabel){
|
||||
showTooltips();
|
||||
source.setText(hideTooltipsMenuLabel);
|
||||
}
|
||||
|
||||
else if(source.getText() == hideTooltipsMenuLabel){
|
||||
hideTooltips();
|
||||
source.setText(showTooltipsMenuLabel);
|
||||
}
|
||||
}
|
||||
});
|
||||
chartPanel.getPopupMenu().add(hideToolTipsMenuItem);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void showTooltips(){
|
||||
tooltips = true;
|
||||
DecimalFormat dm = new DecimalFormat("0.##########");
|
||||
XYToolTipGenerator xYToolTipGenerator = new StandardXYToolTipGenerator( "{1}/{2}", dm, dm);
|
||||
chart.getXYPlot().getRenderer().setBaseToolTipGenerator(xYToolTipGenerator);
|
||||
chartPanel.setDisplayToolTips(true);
|
||||
chartPanel.getChartRenderingInfo().setEntityCollection(new StandardEntityCollection());
|
||||
}
|
||||
|
||||
private void hideTooltips(){
|
||||
tooltips = false;
|
||||
// http://www.jfree.org/phpBB2/viewtopic.php?t=12788&highlight=redraw+speed+performance+problem
|
||||
chartPanel.getChartRenderingInfo().setEntityCollection(null);
|
||||
chart.getXYPlot().getRenderer().setBaseToolTipGenerator(null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
if(data != null){
|
||||
SwingUtilities.invokeLater(new Runnable() { // Try to avoid concurrent modification exception
|
||||
@Override
|
||||
public void run() {
|
||||
try{
|
||||
for(XYSeriesP s:data.getSeries()){
|
||||
s.fireSeriesChanged();
|
||||
}
|
||||
}
|
||||
catch(ConcurrentModificationException e){
|
||||
logger.log(Level.WARNING, "Series got modified concurrently: "+e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public JFreeChart getChart() {
|
||||
return chart;
|
||||
}
|
||||
|
||||
// Getter and setter
|
||||
public XYSeriesCollectionP getData() {
|
||||
return data;
|
||||
}
|
||||
public String getxAxisLabel() {
|
||||
return xAxisLabel;
|
||||
}
|
||||
public void setxAxisLabel(String xAxisLabel) {
|
||||
this.xAxisLabel = xAxisLabel;
|
||||
}
|
||||
public String getyAxisLabel() {
|
||||
return yAxisLabel;
|
||||
}
|
||||
public void setyAxisLabel(String yAxisLabel) {
|
||||
this.yAxisLabel = yAxisLabel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,626 +0,0 @@
|
||||
/* ===========================================================
|
||||
* JFreeChart : a free chart library for the Java(tm) platform
|
||||
* ===========================================================
|
||||
*
|
||||
* (C) Copyright 2000-2009, by Object Refinery Limited and Contributors.
|
||||
*
|
||||
* Project Info: http://www.jfree.org/jfreechart/index.html
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
|
||||
* in the United States and other countries.]
|
||||
*
|
||||
* -----------------------
|
||||
* XYSeriesCollection.java
|
||||
* -----------------------
|
||||
* (C) Copyright 2001-2009, by Object Refinery Limited and Contributors.
|
||||
*
|
||||
* Original Author: David Gilbert (for Object Refinery Limited);
|
||||
* Contributor(s): Aaron Metzger;
|
||||
*
|
||||
* Changes
|
||||
* -------
|
||||
* 15-Nov-2001 : Version 1 (DG);
|
||||
* 03-Apr-2002 : Added change listener code (DG);
|
||||
* 29-Apr-2002 : Added removeSeries, removeAllSeries methods (ARM);
|
||||
* 07-Oct-2002 : Fixed errors reported by Checkstyle (DG);
|
||||
* 26-Mar-2003 : Implemented Serializable (DG);
|
||||
* 04-Aug-2003 : Added getSeries() method (DG);
|
||||
* 31-Mar-2004 : Modified to use an XYIntervalDelegate.
|
||||
* 05-May-2004 : Now extends AbstractIntervalXYDataset (DG);
|
||||
* 18-Aug-2004 : Moved from org.jfree.data --> org.jfree.data.xy (DG);
|
||||
* 17-Nov-2004 : Updated for changes to DomainInfo interface (DG);
|
||||
* 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
|
||||
* 28-Mar-2005 : Fixed bug in getSeries(int) method (1170825) (DG);
|
||||
* 05-Oct-2005 : Made the interval delegate a dataset listener (DG);
|
||||
* ------------- JFREECHART 1.0.x ---------------------------------------------
|
||||
* 27-Nov-2006 : Added clone() override (DG);
|
||||
* 08-May-2007 : Added indexOf(XYSeries) method (DG);
|
||||
* 03-Dec-2007 : Added getSeries(Comparable) method (DG);
|
||||
* 22-Apr-2008 : Implemented PublicCloneable (DG);
|
||||
* 27-Feb-2009 : Overridden getDomainOrder() to detect when all series are
|
||||
* sorted in ascending order (DG);
|
||||
* 06-Mar-2009 : Implemented RangeInfo (DG);
|
||||
* 06-Mar-2009 : Fixed equals() implementation (DG);
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xy;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.jfree.data.DomainInfo;
|
||||
import org.jfree.data.DomainOrder;
|
||||
import org.jfree.data.Range;
|
||||
import org.jfree.data.RangeInfo;
|
||||
import org.jfree.data.UnknownKeyException;
|
||||
import org.jfree.data.general.DatasetChangeEvent;
|
||||
import org.jfree.data.xy.AbstractIntervalXYDataset;
|
||||
import org.jfree.data.xy.IntervalXYDataset;
|
||||
import org.jfree.data.xy.IntervalXYDelegate;
|
||||
import org.jfree.data.xy.XYDataItem;
|
||||
|
||||
/**
|
||||
* Represents a collection of {@link XYSeries} objects that can be used as a
|
||||
* dataset.
|
||||
*/
|
||||
public class XYSeriesCollectionP extends AbstractIntervalXYDataset
|
||||
implements IntervalXYDataset, DomainInfo, RangeInfo,
|
||||
Serializable {
|
||||
|
||||
/** For serialization. */
|
||||
private static final long serialVersionUID = -7590013825931496766L;
|
||||
|
||||
/** The series that are included in the collection. */
|
||||
private List<XYSeriesP> data;
|
||||
|
||||
/** The interval delegate (used to calculate the start and end x-values). */
|
||||
private IntervalXYDelegate intervalDelegate;
|
||||
|
||||
/**
|
||||
* Constructs an empty dataset.
|
||||
*/
|
||||
public XYSeriesCollectionP() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a dataset and populates it with a single series.
|
||||
*
|
||||
* @param series the series (<code>null</code> ignored).
|
||||
*/
|
||||
public XYSeriesCollectionP(XYSeriesP series) {
|
||||
this.data = new ArrayList<XYSeriesP>();
|
||||
this.intervalDelegate = new IntervalXYDelegate(this, false);
|
||||
addChangeListener(this.intervalDelegate);
|
||||
if (series != null) {
|
||||
this.data.add(series);
|
||||
series.addChangeListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the order of the domain (X) values, if this is known.
|
||||
*
|
||||
* @return The domain order.
|
||||
*/
|
||||
public DomainOrder getDomainOrder() {
|
||||
return DomainOrder.NONE; // No specific order
|
||||
// return DomainOrder.ASCENDING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a series to the collection and sends a {@link DatasetChangeEvent}
|
||||
* to all registered listeners.
|
||||
*
|
||||
* @param series the series (<code>null</code> not permitted).
|
||||
*/
|
||||
public void addSeries(XYSeriesP series) {
|
||||
if (series == null) {
|
||||
throw new IllegalArgumentException("Null 'series' argument.");
|
||||
}
|
||||
this.data.add(series);
|
||||
series.addChangeListener(this);
|
||||
fireDatasetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a series from the collection and sends a
|
||||
* {@link DatasetChangeEvent} to all registered listeners.
|
||||
*
|
||||
* @param series the series index (zero-based).
|
||||
*/
|
||||
public void removeSeries(int series) {
|
||||
if ((series < 0) || (series >= getSeriesCount())) {
|
||||
throw new IllegalArgumentException("Series index out of bounds.");
|
||||
}
|
||||
|
||||
// fetch the series, remove the change listener, then remove the series.
|
||||
XYSeriesP ts = (XYSeriesP) this.data.get(series);
|
||||
ts.removeChangeListener(this);
|
||||
this.data.remove(series);
|
||||
fireDatasetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a series from the collection and sends a
|
||||
* {@link DatasetChangeEvent} to all registered listeners.
|
||||
*
|
||||
* @param series the series (<code>null</code> not permitted).
|
||||
*/
|
||||
public void removeSeries(XYSeriesP series) {
|
||||
if (series == null) {
|
||||
throw new IllegalArgumentException("Null 'series' argument.");
|
||||
}
|
||||
if (this.data.contains(series)) {
|
||||
series.removeChangeListener(this);
|
||||
this.data.remove(series);
|
||||
fireDatasetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all the series from the collection and sends a
|
||||
* {@link DatasetChangeEvent} to all registered listeners.
|
||||
*/
|
||||
public void removeAllSeries() {
|
||||
// Unregister the collection as a change listener to each series in
|
||||
// the collection.
|
||||
for (int i = 0; i < this.data.size(); i++) {
|
||||
XYSeriesP series = (XYSeriesP) this.data.get(i);
|
||||
series.removeChangeListener(this);
|
||||
}
|
||||
|
||||
// Remove all the series from the collection and notify listeners.
|
||||
this.data.clear();
|
||||
fireDatasetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of series in the collection.
|
||||
*
|
||||
* @return The series count.
|
||||
*/
|
||||
public int getSeriesCount() {
|
||||
return this.data.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all the series in the collection.
|
||||
*
|
||||
* @return The list (which is unmodifiable).
|
||||
*/
|
||||
public List<XYSeriesP> getSeries() {
|
||||
return Collections.unmodifiableList(this.data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the specified series, or -1 if that series is not
|
||||
* present in the dataset.
|
||||
*
|
||||
* @param series the series (<code>null</code> not permitted).
|
||||
*
|
||||
* @return The series index.
|
||||
*
|
||||
* @since 1.0.6
|
||||
*/
|
||||
public int indexOf(XYSeriesP series) {
|
||||
if (series == null) {
|
||||
throw new IllegalArgumentException("Null 'series' argument.");
|
||||
}
|
||||
return this.data.indexOf(series);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a series from the collection.
|
||||
*
|
||||
* @param series the series index (zero-based).
|
||||
*
|
||||
* @return The series.
|
||||
*
|
||||
* @throws IllegalArgumentException if <code>series</code> is not in the
|
||||
* range <code>0</code> to <code>getSeriesCount() - 1</code>.
|
||||
*/
|
||||
public XYSeriesP getSeries(int series) {
|
||||
if ((series < 0) || (series >= getSeriesCount())) {
|
||||
throw new IllegalArgumentException("Series index out of bounds");
|
||||
}
|
||||
return (XYSeriesP) this.data.get(series);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a series from the collection.
|
||||
*
|
||||
* @param key the key (<code>null</code> not permitted).
|
||||
*
|
||||
* @return The series with the specified key.
|
||||
*
|
||||
* @throws UnknownKeyException if <code>key</code> is not found in the
|
||||
* collection.
|
||||
*
|
||||
* @since 1.0.9
|
||||
*/
|
||||
public XYSeriesP getSeries(Comparable<?> key) {
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException("Null 'key' argument.");
|
||||
}
|
||||
for (XYSeriesP series: this.data) {
|
||||
if (key.equals(series.getKey())) {
|
||||
return series;
|
||||
}
|
||||
}
|
||||
throw new UnknownKeyException("Key not found: " + key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key for a series.
|
||||
*
|
||||
* @param series the series index (in the range <code>0</code> to
|
||||
* <code>getSeriesCount() - 1</code>).
|
||||
*
|
||||
* @return The key for a series.
|
||||
*
|
||||
* @throws IllegalArgumentException if <code>series</code> is not in the
|
||||
* specified range.
|
||||
*/
|
||||
public Comparable<?> getSeriesKey(int series) {
|
||||
// defer argument checking
|
||||
return getSeries(series).getKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of items in the specified series.
|
||||
*
|
||||
* @param series the series (zero-based index).
|
||||
*
|
||||
* @return The item count.
|
||||
*
|
||||
* @throws IllegalArgumentException if <code>series</code> is not in the
|
||||
* range <code>0</code> to <code>getSeriesCount() - 1</code>.
|
||||
*/
|
||||
public int getItemCount(int series) {
|
||||
// defer argument checking
|
||||
return getSeries(series).getItemCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the x-value for the specified series and item.
|
||||
*
|
||||
* @param series the series (zero-based index).
|
||||
* @param item the item (zero-based index).
|
||||
*
|
||||
* @return The value.
|
||||
*/
|
||||
public Number getX(int series, int item) {
|
||||
XYSeriesP ts = (XYSeriesP) this.data.get(series);
|
||||
XYDataItem xyItem = ts.getDataItem(item);
|
||||
return xyItem.getX();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the starting X value for the specified series and item.
|
||||
*
|
||||
* @param series the series (zero-based index).
|
||||
* @param item the item (zero-based index).
|
||||
*
|
||||
* @return The starting X value.
|
||||
*/
|
||||
public Number getStartX(int series, int item) {
|
||||
return this.intervalDelegate.getStartX(series, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ending X value for the specified series and item.
|
||||
*
|
||||
* @param series the series (zero-based index).
|
||||
* @param item the item (zero-based index).
|
||||
*
|
||||
* @return The ending X value.
|
||||
*/
|
||||
public Number getEndX(int series, int item) {
|
||||
return this.intervalDelegate.getEndX(series, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the y-value for the specified series and item.
|
||||
*
|
||||
* @param series the series (zero-based index).
|
||||
* @param index the index of the item of interest (zero-based).
|
||||
*
|
||||
* @return The value (possibly <code>null</code>).
|
||||
*/
|
||||
public Number getY(int series, int index) {
|
||||
XYSeriesP ts = (XYSeriesP) this.data.get(series);
|
||||
XYDataItem xyItem = ts.getDataItem(index);
|
||||
return xyItem.getY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the starting Y value for the specified series and item.
|
||||
*
|
||||
* @param series the series (zero-based index).
|
||||
* @param item the item (zero-based index).
|
||||
*
|
||||
* @return The starting Y value.
|
||||
*/
|
||||
public Number getStartY(int series, int item) {
|
||||
return getY(series, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ending Y value for the specified series and item.
|
||||
*
|
||||
* @param series the series (zero-based index).
|
||||
* @param item the item (zero-based index).
|
||||
*
|
||||
* @return The ending Y value.
|
||||
*/
|
||||
public Number getEndY(int series, int item) {
|
||||
return getY(series, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum x-value in the dataset.
|
||||
*
|
||||
* @param includeInterval a flag that determines whether or not the
|
||||
* x-interval is taken into account.
|
||||
*
|
||||
* @return The minimum value.
|
||||
*/
|
||||
public double getDomainLowerBound(boolean includeInterval) {
|
||||
if (includeInterval) {
|
||||
return this.intervalDelegate.getDomainLowerBound(includeInterval);
|
||||
}
|
||||
else {
|
||||
double result = Double.NaN;
|
||||
int seriesCount = getSeriesCount();
|
||||
for (int s = 0; s < seriesCount; s++) {
|
||||
XYSeriesP series = getSeries(s);
|
||||
double lowX = series.getMinX();
|
||||
if (Double.isNaN(result)) {
|
||||
result = lowX;
|
||||
}
|
||||
else {
|
||||
if (!Double.isNaN(lowX)) {
|
||||
result = Math.min(result, lowX);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum x-value in the dataset.
|
||||
*
|
||||
* @param includeInterval a flag that determines whether or not the
|
||||
* x-interval is taken into account.
|
||||
*
|
||||
* @return The maximum value.
|
||||
*/
|
||||
public double getDomainUpperBound(boolean includeInterval) {
|
||||
if (includeInterval) {
|
||||
return this.intervalDelegate.getDomainUpperBound(includeInterval);
|
||||
}
|
||||
else {
|
||||
double result = Double.NaN;
|
||||
int seriesCount = getSeriesCount();
|
||||
for (int s = 0; s < seriesCount; s++) {
|
||||
XYSeriesP series = getSeries(s);
|
||||
double hiX = series.getMaxX();
|
||||
if (Double.isNaN(result)) {
|
||||
result = hiX;
|
||||
}
|
||||
else {
|
||||
if (!Double.isNaN(hiX)) {
|
||||
result = Math.max(result, hiX);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the range of the values in this dataset's domain.
|
||||
*
|
||||
* @param includeInterval a flag that determines whether or not the
|
||||
* x-interval is taken into account.
|
||||
*
|
||||
* @return The range (or <code>null</code> if the dataset contains no
|
||||
* values).
|
||||
*/
|
||||
public Range getDomainBounds(boolean includeInterval) {
|
||||
if (includeInterval) {
|
||||
return this.intervalDelegate.getDomainBounds(includeInterval);
|
||||
}
|
||||
else {
|
||||
double lower = Double.POSITIVE_INFINITY;
|
||||
double upper = Double.NEGATIVE_INFINITY;
|
||||
int seriesCount = getSeriesCount();
|
||||
for (int s = 0; s < seriesCount; s++) {
|
||||
XYSeriesP series = getSeries(s);
|
||||
double minX = series.getMinX();
|
||||
if (!Double.isNaN(minX)) {
|
||||
lower = Math.min(lower, minX);
|
||||
}
|
||||
double maxX = series.getMaxX();
|
||||
if (!Double.isNaN(maxX)) {
|
||||
upper = Math.max(upper, maxX);
|
||||
}
|
||||
}
|
||||
if (lower > upper) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return new Range(lower, upper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the interval width. This is used to calculate the start and end
|
||||
* x-values, if/when the dataset is used as an {@link IntervalXYDataset}.
|
||||
*
|
||||
* @return The interval width.
|
||||
*/
|
||||
public double getIntervalWidth() {
|
||||
return this.intervalDelegate.getIntervalWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the interval width and sends a {@link DatasetChangeEvent} to all
|
||||
* registered listeners.
|
||||
*
|
||||
* @param width the width (negative values not permitted).
|
||||
*/
|
||||
public void setIntervalWidth(double width) {
|
||||
if (width < 0.0) {
|
||||
throw new IllegalArgumentException("Negative 'width' argument.");
|
||||
}
|
||||
this.intervalDelegate.setFixedIntervalWidth(width);
|
||||
fireDatasetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the interval position factor.
|
||||
*
|
||||
* @return The interval position factor.
|
||||
*/
|
||||
public double getIntervalPositionFactor() {
|
||||
return this.intervalDelegate.getIntervalPositionFactor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the interval position factor. This controls where the x-value is in
|
||||
* relation to the interval surrounding the x-value (0.0 means the x-value
|
||||
* will be positioned at the start, 0.5 in the middle, and 1.0 at the end).
|
||||
*
|
||||
* @param factor the factor.
|
||||
*/
|
||||
public void setIntervalPositionFactor(double factor) {
|
||||
this.intervalDelegate.setIntervalPositionFactor(factor);
|
||||
fireDatasetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the interval width is automatically calculated or not.
|
||||
*
|
||||
* @return Whether the width is automatically calculated or not.
|
||||
*/
|
||||
public boolean isAutoWidth() {
|
||||
return this.intervalDelegate.isAutoWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flag that indicates wether the interval width is automatically
|
||||
* calculated or not.
|
||||
*
|
||||
* @param b a boolean.
|
||||
*/
|
||||
public void setAutoWidth(boolean b) {
|
||||
this.intervalDelegate.setAutoWidth(b);
|
||||
fireDatasetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the range of the values in this dataset's range.
|
||||
*
|
||||
* @param includeInterval ignored.
|
||||
*
|
||||
* @return The range (or <code>null</code> if the dataset contains no
|
||||
* values).
|
||||
*/
|
||||
public Range getRangeBounds(boolean includeInterval) {
|
||||
double lower = Double.POSITIVE_INFINITY;
|
||||
double upper = Double.NEGATIVE_INFINITY;
|
||||
int seriesCount = getSeriesCount();
|
||||
for (int s = 0; s < seriesCount; s++) {
|
||||
XYSeriesP series = getSeries(s);
|
||||
double minY = series.getMinY();
|
||||
if (!Double.isNaN(minY)) {
|
||||
lower = Math.min(lower, minY);
|
||||
}
|
||||
double maxY = series.getMaxY();
|
||||
if (!Double.isNaN(maxY)) {
|
||||
upper = Math.max(upper, maxY);
|
||||
}
|
||||
}
|
||||
if (lower > upper) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return new Range(lower, upper);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum y-value in the dataset.
|
||||
*
|
||||
* @param includeInterval a flag that determines whether or not the
|
||||
* y-interval is taken into account.
|
||||
*
|
||||
* @return The minimum value.
|
||||
*/
|
||||
public double getRangeLowerBound(boolean includeInterval) {
|
||||
double result = Double.NaN;
|
||||
int seriesCount = getSeriesCount();
|
||||
for (int s = 0; s < seriesCount; s++) {
|
||||
XYSeriesP series = getSeries(s);
|
||||
double lowY = series.getMinY();
|
||||
if (Double.isNaN(result)) {
|
||||
result = lowY;
|
||||
}
|
||||
else {
|
||||
if (!Double.isNaN(lowY)) {
|
||||
result = Math.min(result, lowY);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum y-value in the dataset.
|
||||
*
|
||||
* @param includeInterval a flag that determines whether or not the
|
||||
* y-interval is taken into account.
|
||||
*
|
||||
* @return The maximum value.
|
||||
*/
|
||||
public double getRangeUpperBound(boolean includeInterval) {
|
||||
double result = Double.NaN;
|
||||
int seriesCount = getSeriesCount();
|
||||
for (int s = 0; s < seriesCount; s++) {
|
||||
XYSeriesP series = getSeries(s);
|
||||
double hiY = series.getMaxY();
|
||||
if (Double.isNaN(result)) {
|
||||
result = hiY;
|
||||
}
|
||||
else {
|
||||
if (!Double.isNaN(hiY)) {
|
||||
result = Math.max(result, hiY);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,454 +0,0 @@
|
||||
package ch.psi.plot.xy;
|
||||
|
||||
/* ===========================================================
|
||||
* JFreeChart : a free chart library for the Java(tm) platform
|
||||
* ===========================================================
|
||||
*
|
||||
* (C) Copyright 2000-2009, by Object Refinery Limited and Contributors.
|
||||
*
|
||||
* Project Info: http://www.jfree.org/jfreechart/index.html
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
|
||||
* in the United States and other countries.]
|
||||
*
|
||||
* -------------
|
||||
* XYSeries.java
|
||||
* -------------
|
||||
* (C) Copyright 2001-2009, Object Refinery Limited and Contributors.
|
||||
*
|
||||
* Original Author: David Gilbert (for Object Refinery Limited);
|
||||
* Contributor(s): Aaron Metzger;
|
||||
* Jonathan Gabbai;
|
||||
* Richard Atkinson;
|
||||
* Michel Santos;
|
||||
* Ted Schwartz (fix for bug 1955483);
|
||||
*
|
||||
* Changes
|
||||
* -------
|
||||
* 15-Nov-2001 : Version 1 (DG);
|
||||
* 03-Apr-2002 : Added an add(double, double) method (DG);
|
||||
* 29-Apr-2002 : Added a clear() method (ARM);
|
||||
* 06-Jun-2002 : Updated Javadoc comments (DG);
|
||||
* 29-Aug-2002 : Modified to give user control over whether or not duplicate
|
||||
* x-values are allowed (DG);
|
||||
* 07-Oct-2002 : Fixed errors reported by Checkstyle (DG);
|
||||
* 11-Nov-2002 : Added maximum item count, code contributed by Jonathan
|
||||
* Gabbai (DG);
|
||||
* 26-Mar-2003 : Implemented Serializable (DG);
|
||||
* 04-Aug-2003 : Added getItems() method (DG);
|
||||
* 15-Aug-2003 : Changed 'data' from private to protected, added new add()
|
||||
* methods with a 'notify' argument (DG);
|
||||
* 22-Sep-2003 : Added getAllowDuplicateXValues() method (RA);
|
||||
* 29-Jan-2004 : Added autoSort attribute, based on a contribution by
|
||||
* Michel Santos - see patch 886740 (DG);
|
||||
* 03-Feb-2004 : Added indexOf() method (DG);
|
||||
* 16-Feb-2004 : Added remove() method (DG);
|
||||
* 18-Aug-2004 : Moved from org.jfree.data --> org.jfree.data.xy (DG);
|
||||
* 21-Feb-2005 : Added update(Number, Number) and addOrUpdate(Number, Number)
|
||||
* methods (DG);
|
||||
* 03-May-2005 : Added a new constructor, fixed the setMaximumItemCount()
|
||||
* method to remove items (and notify listeners) if necessary,
|
||||
* fixed the add() and addOrUpdate() methods to handle unsorted
|
||||
* series (DG);
|
||||
* ------------- JFreeChart 1.0.x ---------------------------------------------
|
||||
* 11-Jan-2005 : Renamed update(int, Number) --> updateByIndex() (DG);
|
||||
* 15-Jan-2007 : Added toArray() method (DG);
|
||||
* 31-Oct-2007 : Implemented faster hashCode() (DG);
|
||||
* 22-Nov-2007 : Reimplemented clone() (DG);
|
||||
* 01-May-2008 : Fixed bug 1955483 in addOrUpdate() method, thanks to
|
||||
* Ted Schwartz (DG);
|
||||
* 24-Nov-2008 : Further fix for 1955483 (DG);
|
||||
* 06-Mar-2009 : Added minX, maxX, minY and maxY fields (DG);
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.jfree.data.general.Series;
|
||||
import org.jfree.data.general.SeriesChangeEvent;
|
||||
import org.jfree.data.general.SeriesException;
|
||||
import org.jfree.data.xy.XYDataItem;
|
||||
|
||||
/**
|
||||
* Represents a sequence of zero or more data items in the form (x, y). By
|
||||
* default, items in the series will be sorted into ascending order by x-value,
|
||||
* and duplicate x-values are permitted. Both the sorting and duplicate
|
||||
* defaults can be changed in the constructor. Y-values can be
|
||||
* <code>null</code> to represent missing values.
|
||||
*/
|
||||
public class XYSeriesP extends Series implements Cloneable, Serializable {
|
||||
|
||||
/** For serialization. */
|
||||
static final long serialVersionUID = -5908509288197150436L;
|
||||
|
||||
// In version 0.9.12, in response to several developer requests, I changed
|
||||
// the 'data' attribute from 'private' to 'protected', so that others can
|
||||
// make subclasses that work directly with the underlying data structure.
|
||||
|
||||
/** Storage for the data items in the series. */
|
||||
protected List<XYDataItem> data;
|
||||
|
||||
/** The maximum number of items for the series. */
|
||||
private int maximumItemCount = Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* A flag that controls whether the items are automatically sorted
|
||||
* (by x-value ascending).
|
||||
*/
|
||||
|
||||
/** The lowest x-value in the series, excluding Double.NaN values. */
|
||||
private double minX;
|
||||
|
||||
/** The highest x-value in the series, excluding Double.NaN values. */
|
||||
private double maxX;
|
||||
|
||||
/** The lowest y-value in the series, excluding Double.NaN values. */
|
||||
private double minY;
|
||||
|
||||
/** The highest y-value in the series, excluding Double.NaN values. */
|
||||
private double maxY;
|
||||
|
||||
/**
|
||||
* Creates a new empty series. By default, items added to the series will
|
||||
* be sorted into ascending order by x-value, and duplicate x-values will
|
||||
* be allowed (these defaults can be modified with another constructor.
|
||||
*
|
||||
* @param key the series key (<code>null</code> not permitted).
|
||||
*/
|
||||
public XYSeriesP(Comparable<?> key) {
|
||||
this(key, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new empty series, with the auto-sort flag set as requested,
|
||||
* and duplicate values allowed.
|
||||
*
|
||||
* @param key the series key (<code>null</code> not permitted).
|
||||
* @param autoSort a flag that controls whether or not the items in the
|
||||
* series are sorted.
|
||||
*/
|
||||
public XYSeriesP(Comparable<?> key, boolean autoSort) {
|
||||
this(key, autoSort, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new xy-series that contains no data. You can specify
|
||||
* whether or not duplicate x-values are allowed for the series.
|
||||
*
|
||||
* @param key the series key (<code>null</code> not permitted).
|
||||
* @param autoSort a flag that controls whether or not the items in the
|
||||
* series are sorted.
|
||||
* @param allowDuplicateXValues a flag that controls whether duplicate
|
||||
* x-values are allowed.
|
||||
*/
|
||||
public XYSeriesP(Comparable<?> key, boolean autoSort,
|
||||
boolean allowDuplicateXValues) {
|
||||
super(key);
|
||||
this.data = new ArrayList<XYDataItem>(1000); // allocate memory already for 1000 items
|
||||
this.minX = Double.NaN;
|
||||
this.maxX = Double.NaN;
|
||||
this.minY = Double.NaN;
|
||||
this.maxY = Double.NaN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the smallest x-value in the series, ignoring any Double.NaN
|
||||
* values. This method returns Double.NaN if there is no smallest x-value
|
||||
* (for example, when the series is empty).
|
||||
*
|
||||
* @return The smallest x-value.
|
||||
*
|
||||
* @see #getMaxX()
|
||||
*
|
||||
* @since 1.0.13
|
||||
*/
|
||||
public double getMinX() {
|
||||
return this.minX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the largest x-value in the series, ignoring any Double.NaN
|
||||
* values. This method returns Double.NaN if there is no largest x-value
|
||||
* (for example, when the series is empty).
|
||||
*
|
||||
* @return The largest x-value.
|
||||
*
|
||||
* @see #getMinX()
|
||||
*
|
||||
* @since 1.0.13
|
||||
*/
|
||||
public double getMaxX() {
|
||||
return this.maxX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the smallest y-value in the series, ignoring any null and
|
||||
* Double.NaN values. This method returns Double.NaN if there is no
|
||||
* smallest y-value (for example, when the series is empty).
|
||||
*
|
||||
* @return The smallest y-value.
|
||||
*
|
||||
* @see #getMaxY()
|
||||
*
|
||||
* @since 1.0.13
|
||||
*/
|
||||
public double getMinY() {
|
||||
return this.minY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the largest y-value in the series, ignoring any Double.NaN
|
||||
* values. This method returns Double.NaN if there is no largest y-value
|
||||
* (for example, when the series is empty).
|
||||
*
|
||||
* @return The largest y-value.
|
||||
*
|
||||
* @see #getMinY()
|
||||
*
|
||||
* @since 1.0.13
|
||||
*/
|
||||
public double getMaxY() {
|
||||
return this.maxY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the cached values for the minimum and maximum data values.
|
||||
*
|
||||
* @param item the item added (<code>null</code> not permitted).
|
||||
*
|
||||
* @since 1.0.13
|
||||
*/
|
||||
private void updateBoundsForAddedItem(XYDataItem item) {
|
||||
double x = item.getXValue();
|
||||
this.minX = minIgnoreNaN(this.minX, x);
|
||||
this.maxX = maxIgnoreNaN(this.maxX, x);
|
||||
if (item.getY() != null) {
|
||||
double y = item.getYValue();
|
||||
this.minY = minIgnoreNaN(this.minY, y);
|
||||
this.maxY = maxIgnoreNaN(this.maxY, y);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the bounds of the x and y values for the series, by iterating
|
||||
* through all the data items.
|
||||
*
|
||||
* @since 1.0.13
|
||||
*/
|
||||
private void findBoundsByIteration() {
|
||||
this.minX = Double.NaN;
|
||||
this.maxX = Double.NaN;
|
||||
this.minY = Double.NaN;
|
||||
this.maxY = Double.NaN;
|
||||
for(XYDataItem item: data){
|
||||
updateBoundsForAddedItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of items in the series.
|
||||
*
|
||||
* @return The item count.
|
||||
*
|
||||
* @see #getItems()
|
||||
*/
|
||||
public int getItemCount() {
|
||||
return this.data.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of data items for the series (the list contains
|
||||
* {@link XYDataItem} objects and is unmodifiable).
|
||||
*
|
||||
* @return The list of data items.
|
||||
*/
|
||||
public List<XYDataItem> getItems() {
|
||||
return Collections.unmodifiableList(this.data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of items that will be retained in the series.
|
||||
* The default value is <code>Integer.MAX_VALUE</code>.
|
||||
*
|
||||
* @return The maximum item count.
|
||||
*
|
||||
* @see #setMaximumItemCount(int)
|
||||
*/
|
||||
public int getMaximumItemCount() {
|
||||
return this.maximumItemCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of items that will be retained in the series.
|
||||
* If you add a new item to the series such that the number of items will
|
||||
* exceed the maximum item count, then the first element in the series is
|
||||
* automatically removed, ensuring that the maximum item count is not
|
||||
* exceeded.
|
||||
* <p>
|
||||
* Typically this value is set before the series is populated with data,
|
||||
* but if it is applied later, it may cause some items to be removed from
|
||||
* the series (in which case a {@link SeriesChangeEvent} will be sent to
|
||||
* all registered listeners).
|
||||
*
|
||||
* @param maximum the maximum number of items for the series.
|
||||
*/
|
||||
public void setMaximumItemCount(int maximum) {
|
||||
this.maximumItemCount = maximum;
|
||||
int remove = this.data.size() - maximum;
|
||||
if (remove > 0) {
|
||||
this.data.subList(0, remove).clear();
|
||||
findBoundsByIteration();
|
||||
fireSeriesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new data item to the series (in the correct position if the
|
||||
* <code>autoSort</code> flag is set for the series) and sends a
|
||||
* {@link SeriesChangeEvent} to all registered listeners.
|
||||
* <P>
|
||||
* Throws an exception if the x-value is a duplicate AND the
|
||||
* allowDuplicateXValues flag is false.
|
||||
*
|
||||
* @param x the x-value (<code>null</code> not permitted).
|
||||
* @param y the y-value (<code>null</code> permitted).
|
||||
*
|
||||
* @throws SeriesException if the x-value is a duplicate and the
|
||||
* <code>allowDuplicateXValues</code> flag is not set for this series.
|
||||
*/
|
||||
public void add(Number x, Number y) {
|
||||
// argument checking delegated...
|
||||
add(new XYDataItem(x, y), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new data to the series and, if requested, sends a
|
||||
* {@link SeriesChangeEvent} to all registered listeners.
|
||||
* <P>
|
||||
* Throws an exception if the x-value is a duplicate AND the
|
||||
* allowDuplicateXValues flag is false.
|
||||
*
|
||||
* @param x the x-value (<code>null</code> not permitted).
|
||||
* @param y the y-value (<code>null</code> permitted).
|
||||
* @param notify a flag the controls whether or not a
|
||||
* {@link SeriesChangeEvent} is sent to all registered
|
||||
* listeners.
|
||||
*/
|
||||
public void add(Number x, Number y, boolean notify) {
|
||||
// delegate argument checking to XYDataItem...
|
||||
XYDataItem item = new XYDataItem(x, y);
|
||||
add(item, notify);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a data item to the series and, if requested, sends a
|
||||
* {@link SeriesChangeEvent} to all registered listeners.
|
||||
*
|
||||
* @param item the (x, y) item (<code>null</code> not permitted).
|
||||
* @param notify a flag that controls whether or not a
|
||||
* {@link SeriesChangeEvent} is sent to all registered
|
||||
* listeners.
|
||||
*/
|
||||
public void add(XYDataItem item, boolean notify) {
|
||||
if (item == null) {
|
||||
throw new IllegalArgumentException("Null 'item' argument.");
|
||||
}
|
||||
|
||||
this.data.add(item);
|
||||
|
||||
if (notify) {
|
||||
fireSeriesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all data items from the series and sends a
|
||||
* {@link SeriesChangeEvent} to all registered listeners.
|
||||
*/
|
||||
public void clear() {
|
||||
if (this.data.size() > 0) {
|
||||
this.data.clear();
|
||||
this.minX = Double.NaN;
|
||||
this.maxX = Double.NaN;
|
||||
this.minY = Double.NaN;
|
||||
this.maxY = Double.NaN;
|
||||
fireSeriesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the data item with the specified index.
|
||||
*
|
||||
* @param index the index.
|
||||
*
|
||||
* @return The data item with the specified index.
|
||||
*/
|
||||
public XYDataItem getDataItem(int index) {
|
||||
return (XYDataItem) this.data.get(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* A function to find the minimum of two values, but ignoring any
|
||||
* Double.NaN values.
|
||||
*
|
||||
* @param a the first value.
|
||||
* @param b the second value.
|
||||
*
|
||||
* @return The minimum of the two values.
|
||||
*/
|
||||
private double minIgnoreNaN(double a, double b) {
|
||||
if (Double.isNaN(a)) {
|
||||
return b;
|
||||
}
|
||||
else {
|
||||
if (Double.isNaN(b)) {
|
||||
return a;
|
||||
}
|
||||
else {
|
||||
return Math.min(a, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A function to find the maximum of two values, but ignoring any
|
||||
* Double.NaN values.
|
||||
*
|
||||
* @param a the first value.
|
||||
* @param b the second value.
|
||||
*
|
||||
* @return The maximum of the two values.
|
||||
*/
|
||||
private double maxIgnoreNaN(double a, double b) {
|
||||
if (Double.isNaN(a)) {
|
||||
return b;
|
||||
}
|
||||
else {
|
||||
if (Double.isNaN(b)) {
|
||||
return a;
|
||||
}
|
||||
else {
|
||||
return Math.max(a, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xy.tools;
|
||||
|
||||
import org.jfree.data.xy.XYDataItem;
|
||||
|
||||
import ch.psi.plot.xy.XYSeriesCollectionP;
|
||||
import ch.psi.plot.xy.XYSeriesP;
|
||||
|
||||
|
||||
/**
|
||||
* Calculate average of series
|
||||
*/
|
||||
public class Average {
|
||||
|
||||
/**
|
||||
* Calculate average of the passed series collection
|
||||
*
|
||||
* @param collection
|
||||
* @return Average value of the collection
|
||||
*/
|
||||
public double average(XYSeriesCollectionP collection){
|
||||
double average = 0.0;
|
||||
for (XYSeriesP series : collection.getSeries()) {
|
||||
average = average + average(series);
|
||||
}
|
||||
|
||||
return average/collection.getSeriesCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate average value for a series
|
||||
* @param series
|
||||
* @return
|
||||
*/
|
||||
public double average(XYSeriesP series){
|
||||
double average = 0.0;
|
||||
for(XYDataItem item: series.getItems()){
|
||||
average = average+item.getYValue();
|
||||
}
|
||||
|
||||
return average/series.getItemCount();
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xy.tools;
|
||||
|
||||
import org.jfree.data.xy.XYDataItem;
|
||||
|
||||
import ch.psi.plot.xy.XYSeriesCollectionP;
|
||||
import ch.psi.plot.xy.XYSeriesP;
|
||||
|
||||
/**
|
||||
* Calculate derivative of series
|
||||
*/
|
||||
public class Derivative {
|
||||
|
||||
/**
|
||||
* Calculate derivatives for all series in the passed collection
|
||||
* @param collection
|
||||
* @return Collection of series holding the derivatives
|
||||
*/
|
||||
public XYSeriesCollectionP derivative(XYSeriesCollectionP collection){
|
||||
XYSeriesCollectionP dcollection = new XYSeriesCollectionP();
|
||||
for (XYSeriesP series : collection.getSeries()) {
|
||||
dcollection.addSeries(derivative(series));
|
||||
}
|
||||
|
||||
return dcollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate derivative (first and/or second order) of a given function.
|
||||
* derivative is based upon 3 points.
|
||||
*
|
||||
* @param series
|
||||
* @return
|
||||
*/
|
||||
public XYSeriesP derivative(XYSeriesP series){
|
||||
|
||||
XYSeriesP derivative = new XYSeriesP(series.getKey() + "'");
|
||||
|
||||
for (int i = 1; i < series.getItemCount() - 1; i++) { // do not start at 0 but 1 - stop 1 before end
|
||||
XYDataItem m = series.getDataItem(i - 1);
|
||||
XYDataItem p = series.getDataItem(i + 1);
|
||||
|
||||
double xi = series.getDataItem(i).getXValue();
|
||||
|
||||
double ximinus1 = m.getXValue();
|
||||
double xiplus1 = p.getXValue();
|
||||
|
||||
double yiminus1 = m.getYValue();
|
||||
double yiplus1 = p.getYValue();
|
||||
|
||||
if (xiplus1-ximinus1 != 0.0) {
|
||||
double di = (yiplus1 - yiminus1) / (xiplus1-ximinus1);
|
||||
derivative.add(xi, di);
|
||||
}
|
||||
else{
|
||||
derivative.add(xi, Double.NaN);
|
||||
}
|
||||
}
|
||||
|
||||
return derivative;
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xy.tools;
|
||||
|
||||
import org.jfree.data.xy.XYDataItem;
|
||||
|
||||
import ch.psi.plot.xy.XYSeriesCollectionP;
|
||||
import ch.psi.plot.xy.XYSeriesP;
|
||||
|
||||
/**
|
||||
* Calculate integral of series
|
||||
*/
|
||||
public class Integral {
|
||||
|
||||
/**
|
||||
* Calculate integral for all series in passed collection
|
||||
* @param collection
|
||||
* @return Collection of series
|
||||
*/
|
||||
public XYSeriesCollectionP integral(XYSeriesCollectionP collection){
|
||||
XYSeriesCollectionP icollection = new XYSeriesCollectionP();
|
||||
for (XYSeriesP series : collection.getSeries()) {
|
||||
icollection.addSeries(integral(series));
|
||||
}
|
||||
|
||||
return icollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate integral of the function
|
||||
* @param series
|
||||
* @return
|
||||
*/
|
||||
public XYSeriesP integral(XYSeriesP series) {
|
||||
XYSeriesP integral = new XYSeriesP("integral-" + series.getKey());
|
||||
|
||||
double value = 0.0;
|
||||
for (int i = 1; i < series.getItemCount(); i++) { // Leave out 1. point
|
||||
XYDataItem item = series.getDataItem(i);
|
||||
XYDataItem itemM = series.getDataItem(i - 1);
|
||||
|
||||
value += (item.getXValue() - itemM.getXValue()) * (item.getYValue() + itemM.getYValue()) / 2.0;
|
||||
|
||||
integral.add(item.getXValue(), value);
|
||||
}
|
||||
return integral;
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xy.tools;
|
||||
|
||||
import org.jfree.data.xy.XYDataItem;
|
||||
import ch.psi.plot.xy.XYSeriesP;
|
||||
|
||||
/**
|
||||
* Find maximum of series
|
||||
*/
|
||||
public class Maximum {
|
||||
|
||||
/**
|
||||
* Find maximum in series
|
||||
* @param series
|
||||
* @return maximum data point
|
||||
*/
|
||||
public XYDataItem maximum(XYSeriesP series){
|
||||
XYDataItem maximum = null;
|
||||
for(XYDataItem item: series.getItems()){
|
||||
if(maximum==null){ // set first item as maximum
|
||||
maximum = item;
|
||||
}
|
||||
else{
|
||||
if(item.getYValue()>maximum.getYValue()){
|
||||
maximum = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return maximum;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xy.tools;
|
||||
|
||||
import org.jfree.data.xy.XYDataItem;
|
||||
import ch.psi.plot.xy.XYSeriesP;
|
||||
|
||||
/**
|
||||
* Find minimum of series
|
||||
*/
|
||||
public class Minimum {
|
||||
|
||||
/**
|
||||
* Find minimum in series
|
||||
* @param series
|
||||
* @return minimum data point
|
||||
*/
|
||||
public XYDataItem minimum(XYSeriesP series){
|
||||
XYDataItem minimum = null;
|
||||
for(XYDataItem item: series.getItems()){
|
||||
if(minimum == null){
|
||||
minimum = item;
|
||||
}
|
||||
else{
|
||||
if(item.getYValue()<minimum.getYValue()){
|
||||
minimum = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return minimum;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* Utility class for applying a color map
|
||||
*/
|
||||
public class ColorManager {
|
||||
|
||||
/**
|
||||
* Get color for a given value
|
||||
* @param v Value to get the color for
|
||||
* @param vmin Lower end value mapped to the lower end of the color map
|
||||
* @param vmax Upper end value mapped to the upper end of the color map
|
||||
* @return Mapped color for the specified value
|
||||
*/
|
||||
public static Color getColourForValue(double v, double vmin, double vmax)
|
||||
{
|
||||
// Standard algorithm for hot-cold color gradient (copied from
|
||||
// http://local.wasp.uwa.edu.au/~pbourke/texture_colour/colourramp/)
|
||||
|
||||
//Init color to white
|
||||
double r = 1.0;
|
||||
double g = 1.0;
|
||||
double b = 1.0;
|
||||
|
||||
double dv;
|
||||
|
||||
if (v < vmin)
|
||||
v = vmin;
|
||||
if (v > vmax)
|
||||
v = vmax;
|
||||
dv = vmax - vmin;
|
||||
|
||||
if (v < (vmin + 0.25 * dv)) {
|
||||
r = 0.0;
|
||||
g = 4 * (v - vmin) / dv;
|
||||
} else if (v < (vmin + 0.5 * dv)) {
|
||||
r = 0.0;
|
||||
b = 1 + 4 * (vmin + 0.25 * dv - v) / dv;
|
||||
} else if (v < (vmin + 0.75 * dv)) {
|
||||
r = 4 * (v - vmin - 0.5 * dv) / dv;
|
||||
b = 0.0;
|
||||
} else {
|
||||
g = 1 + 4 * (vmin + 0.75 * dv - v) / dv;
|
||||
b = 0.0;
|
||||
}
|
||||
|
||||
return new Color( new Double(255.0*r).intValue(), new Double(255.0*g).intValue(), new Double(255.0*b).intValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a gray value for a given value
|
||||
* @param value the value (must be within the range specified by the
|
||||
* lower and upper bounds for the scale).
|
||||
*
|
||||
* @return a gray scale color.
|
||||
*/
|
||||
public static Color getGrayForValue(double value, double vmin, double vmax) {
|
||||
double v = Math.max(value, vmin);
|
||||
v = Math.min(v, vmax);
|
||||
int g = (int) ((v - vmin) / (vmax- vmin) * 255.0);
|
||||
// FIXME: it probably makes sense to allocate an array of 256 Colors
|
||||
// and lazily populate this array...
|
||||
return new Color(g, g, g);
|
||||
}
|
||||
}
|
||||
@@ -1,245 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2011 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but without any
|
||||
* warranty; without even the implied warranty of merchantability or fitness for
|
||||
* a particular purpose. See the GNU Lesser General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.renderer.xy.XYBlockRenderer;
|
||||
import org.jfree.data.DomainOrder;
|
||||
import org.jfree.data.general.DatasetChangeListener;
|
||||
import org.jfree.data.general.DatasetGroup;
|
||||
import org.jfree.data.xy.XYZDataset;
|
||||
import org.jfree.ui.RectangleAnchor;
|
||||
|
||||
/**
|
||||
* Dynamic dataset
|
||||
*/
|
||||
public class DynamicXYZDataset implements XYZDataset{
|
||||
|
||||
private final double xResolution;
|
||||
private final double yResolution;
|
||||
|
||||
private final NumberAxis xAxis = new NumberAxis();
|
||||
private double xLowerBound = Double.NaN;
|
||||
private double xUpperBound = Double.NaN;
|
||||
private final NumberAxis yAxis = new NumberAxis();
|
||||
private double yLowerBound = Double.NaN;
|
||||
private double yUpperBound = Double.NaN;
|
||||
private double zLowerBound = Double.NaN;
|
||||
|
||||
|
||||
private double zUpperBound = Double.NaN;
|
||||
|
||||
private final XYBlockRenderer renderer = new XYBlockRenderer();
|
||||
|
||||
|
||||
private List<DynamicXYZDataset.Vector> items = new ArrayList<DynamicXYZDataset.Vector>();
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public DynamicXYZDataset(){
|
||||
xResolution = 1.0;
|
||||
yResolution = 1.0;
|
||||
|
||||
xAxis.setRange(xLowerBound, xUpperBound);
|
||||
yAxis.setRange(yLowerBound, yUpperBound);
|
||||
|
||||
renderer.setBlockWidth(xResolution); // If this is not set the default block size is 1
|
||||
renderer.setBlockHeight(yResolution); // If this is not set the default block size is 1
|
||||
renderer.setBlockAnchor(RectangleAnchor.CENTER);
|
||||
renderer.setBaseCreateEntities(false);
|
||||
}
|
||||
|
||||
public void addData(double x, double y, double z){
|
||||
items.add(new DynamicXYZDataset.Vector(x,y,z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount(int series) {
|
||||
return items.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number getX(int series, int item) {
|
||||
return items.get(item).getX();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getXValue(int series, int item) {
|
||||
return items.get(item).getX();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number getY(int series, int item) {
|
||||
return items.get(item).getY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getYValue(int series, int item) {
|
||||
return items.get(item).getY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number getZ(int series, int item) {
|
||||
return items.get(item).getZ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getZValue(int series, int item) {
|
||||
return items.get(item).getZ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainOrder getDomainOrder() {
|
||||
return DomainOrder.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSeriesCount() {
|
||||
// Series not implemented/used - dataset only holds one series
|
||||
return 1;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Comparable getSeriesKey(int series) {
|
||||
// Series not implemented/used
|
||||
return "";
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public int indexOf(Comparable seriesKey) {
|
||||
// Series not implemented/used
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DatasetGroup getGroup() {
|
||||
// Not implemented/used
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroup(DatasetGroup group) {
|
||||
// Not implemented/used
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addChangeListener(DatasetChangeListener listener) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeChangeListener(DatasetChangeListener listener) {
|
||||
}
|
||||
|
||||
// Convenient methods
|
||||
|
||||
public double getzLowerBound() {
|
||||
return zLowerBound;
|
||||
}
|
||||
public double getzUpperBound() {
|
||||
return zUpperBound;
|
||||
}
|
||||
public NumberAxis getxAxis() {
|
||||
return xAxis;
|
||||
}
|
||||
public NumberAxis getyAxis() {
|
||||
return yAxis;
|
||||
}
|
||||
public XYBlockRenderer getRenderer() {
|
||||
return renderer;
|
||||
}
|
||||
public double getxLowerBound() {
|
||||
return xLowerBound;
|
||||
}
|
||||
public double getxUpperBound() {
|
||||
return xUpperBound;
|
||||
}
|
||||
public double getyLowerBound() {
|
||||
return yLowerBound;
|
||||
}
|
||||
public double getyUpperBound() {
|
||||
return yUpperBound;
|
||||
}
|
||||
|
||||
|
||||
class Vector{
|
||||
private double x;
|
||||
private double y;
|
||||
private double z;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public Vector(){
|
||||
}
|
||||
|
||||
/**
|
||||
* @param x2
|
||||
* @param y2
|
||||
* @param z2
|
||||
*/
|
||||
public Vector(double x, double y, double z) {
|
||||
// Right now x and xvalue are the same. This might change if we introduce a virtual grid ...
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
/**
|
||||
* @return the x
|
||||
*/
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
/**
|
||||
* @param x the x to set
|
||||
*/
|
||||
public void setX(double x) {
|
||||
this.x = x;
|
||||
}
|
||||
/**
|
||||
* @return the y
|
||||
*/
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
/**
|
||||
* @param y the y to set
|
||||
*/
|
||||
public void setY(double y) {
|
||||
this.y = y;
|
||||
}
|
||||
/**
|
||||
* @return the z
|
||||
*/
|
||||
public double getZ() {
|
||||
return z;
|
||||
}
|
||||
/**
|
||||
* @param z the z to set
|
||||
*/
|
||||
public void setZ(double z) {
|
||||
this.z = z;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,374 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2011 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but without any
|
||||
* warranty; without even the implied warranty of merchantability or fitness for
|
||||
* a particular purpose. See the GNU Lesser General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.renderer.xy.XYBlockRenderer;
|
||||
import org.jfree.data.DomainOrder;
|
||||
import org.jfree.data.general.DatasetChangeListener;
|
||||
import org.jfree.data.general.DatasetGroup;
|
||||
import org.jfree.data.xy.XYZDataset;
|
||||
import org.jfree.ui.RectangleAnchor;
|
||||
|
||||
/**
|
||||
* Dynamic dataset
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class DynamicXYZDatasetList implements XYZDataset{
|
||||
|
||||
private final double xResolution;
|
||||
private final double yResolution;
|
||||
|
||||
private final NumberAxis xAxis = new NumberAxis();
|
||||
private final NumberAxis yAxis = new NumberAxis();
|
||||
private double zLowerBound = Double.NaN;
|
||||
private double zUpperBound = Double.NaN;
|
||||
|
||||
private final XYBlockRenderer renderer = new XYBlockRenderer();
|
||||
|
||||
|
||||
private final List<DatasetChangeListener> listeners = new ArrayList<DatasetChangeListener>();
|
||||
private List<Double> xitems = new ArrayList<Double>(100000);
|
||||
private List<Double> yitems = new ArrayList<Double>(100000);
|
||||
private List<Double> zitems = new ArrayList<Double>(100000);
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public DynamicXYZDatasetList(){
|
||||
xResolution = 1.0;
|
||||
yResolution = 1.0;
|
||||
xAxis.setRange(0, 100);
|
||||
yAxis.setRange(0, 100);
|
||||
|
||||
renderer.setBlockWidth(xResolution); // If this is not set the default block size is 1
|
||||
renderer.setBlockHeight(yResolution); // If this is not set the default block size is 1
|
||||
renderer.setBlockAnchor(RectangleAnchor.CENTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add datapoint
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*/
|
||||
public void addData(Double x, Double y, Double z){
|
||||
System.out.println(x +" "+ y +" "+ z);
|
||||
xitems.add(x);
|
||||
yitems.add(y);
|
||||
zitems.add(z);
|
||||
// items.add(new DynamicXYZDatasetList.Vector(x,y,z));
|
||||
|
||||
// Update axis
|
||||
|
||||
// final double xv = x.doubleValue();
|
||||
// final double yv = y.doubleValue();
|
||||
// final double zv = z.doubleValue();
|
||||
//
|
||||
// if(Double.isNaN(xLowerBound) && Double.isNaN(xUpperBound)){
|
||||
// xLowerBound = xv-incX;
|
||||
// xUpperBound = xv+incX;
|
||||
// xAxis.setRange(xLowerBound, xUpperBound);
|
||||
// }
|
||||
// else{
|
||||
// if(xv>(xUpperBound+incX)){
|
||||
// xUpperBound = xv+incX;
|
||||
// xAxis.setUpperBound(xUpperBound);
|
||||
// }
|
||||
// else if(xv<xLowerBound-incX){
|
||||
// xLowerBound = xv-incX;
|
||||
// xAxis.setLowerBound(xLowerBound);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if(Double.isNaN(yLowerBound) && Double.isNaN(yUpperBound)){
|
||||
// yLowerBound = y.doubleValue()-incY;
|
||||
// yUpperBound = y.doubleValue()+incY;
|
||||
// yAxis.setRange(yLowerBound, yUpperBound);
|
||||
// }
|
||||
// else{
|
||||
// if(yv>(yUpperBound+incY)){
|
||||
// yUpperBound = yv+incY;
|
||||
// yAxis.setUpperBound(yUpperBound);
|
||||
// }
|
||||
// else if(yv<yLowerBound-incY){
|
||||
// yLowerBound = yv-incY;
|
||||
// yAxis.setLowerBound(yLowerBound);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if(Double.isNaN(zLowerBound) && Double.isNaN(zUpperBound)){
|
||||
// zLowerBound = zv;
|
||||
// zUpperBound = zv;
|
||||
// }
|
||||
// else{
|
||||
// if(zv>zUpperBound){
|
||||
// zUpperBound = zv;
|
||||
// }
|
||||
// else if(zv<zLowerBound){
|
||||
// zLowerBound = zv;
|
||||
// }
|
||||
// }
|
||||
|
||||
// Inform change listeners
|
||||
// DatasetChangeEvent event = new DatasetChangeEvent(this, this);
|
||||
// for(DatasetChangeListener l: listeners){
|
||||
// l.datasetChanged(event );
|
||||
// }
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.xy.XYDataset#getItemCount(int)
|
||||
*/
|
||||
@Override
|
||||
public int getItemCount(int series) {
|
||||
return xitems.size();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.xy.XYDataset#getX(int, int)
|
||||
*/
|
||||
@Override
|
||||
public Number getX(int series, int item) {
|
||||
return xitems.get(item);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.xy.XYDataset#getXValue(int, int)
|
||||
*/
|
||||
@Override
|
||||
public double getXValue(int series, int item) {
|
||||
return xitems.get(item);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.xy.XYDataset#getY(int, int)
|
||||
*/
|
||||
@Override
|
||||
public Number getY(int series, int item) {
|
||||
return yitems.get(item);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.xy.XYDataset#getYValue(int, int)
|
||||
*/
|
||||
@Override
|
||||
public double getYValue(int series, int item) {
|
||||
return yitems.get(item);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.xy.XYZDataset#getZ(int, int)
|
||||
*/
|
||||
@Override
|
||||
public Number getZ(int series, int item) {
|
||||
return zitems.get(item);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.xy.XYZDataset#getZValue(int, int)
|
||||
*/
|
||||
@Override
|
||||
public double getZValue(int series, int item) {
|
||||
return zitems.get(item);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.xy.XYDataset#getDomainOrder()
|
||||
*/
|
||||
@Override
|
||||
public DomainOrder getDomainOrder() {
|
||||
return DomainOrder.NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.general.SeriesDataset#getSeriesCount()
|
||||
*/
|
||||
@Override
|
||||
public int getSeriesCount() {
|
||||
// Series not implemented/used - dataset only holds one series
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.general.SeriesDataset#getSeriesKey(int)
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Comparable getSeriesKey(int series) {
|
||||
// Series not implemented/used
|
||||
return "";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.general.SeriesDataset#indexOf(java.lang.Comparable)
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public int indexOf(Comparable seriesKey) {
|
||||
// Series not implemented/used
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.general.Dataset#getGroup()
|
||||
*/
|
||||
@Override
|
||||
public DatasetGroup getGroup() {
|
||||
// Not implemented/used
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.general.Dataset#setGroup(org.jfree.data.general.DatasetGroup)
|
||||
*/
|
||||
@Override
|
||||
public void setGroup(DatasetGroup group) {
|
||||
// Not implemented/used
|
||||
}
|
||||
|
||||
// Listener concept implementation
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.general.Dataset#addChangeListener(org.jfree.data.general.DatasetChangeListener)
|
||||
*/
|
||||
@Override
|
||||
public void addChangeListener(DatasetChangeListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.general.Dataset#removeChangeListener(org.jfree.data.general.DatasetChangeListener)
|
||||
*/
|
||||
@Override
|
||||
public void removeChangeListener(DatasetChangeListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
|
||||
// Convenient methods
|
||||
|
||||
/**
|
||||
* @return the zLowerBound
|
||||
*/
|
||||
public double getzLowerBound() {
|
||||
return zLowerBound;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the zUpperBound
|
||||
*/
|
||||
public double getzUpperBound() {
|
||||
return zUpperBound;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the xAxis
|
||||
*/
|
||||
public NumberAxis getxAxis() {
|
||||
return xAxis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the yAxis
|
||||
*/
|
||||
public NumberAxis getyAxis() {
|
||||
return yAxis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the renderer
|
||||
*/
|
||||
public XYBlockRenderer getRenderer() {
|
||||
return renderer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class Vector{
|
||||
private Number x;
|
||||
private Number y;
|
||||
private Number z;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public Vector(){
|
||||
}
|
||||
|
||||
/**
|
||||
* @param x2
|
||||
* @param y2
|
||||
* @param z2
|
||||
*/
|
||||
public Vector(Number x, Number y, Number z) {
|
||||
// Right now x and xvalue are the same. This might change if we introduce a virtual grid ...
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
/**
|
||||
* @return the x
|
||||
*/
|
||||
public Number getX() {
|
||||
return x;
|
||||
}
|
||||
/**
|
||||
* @param x the x to set
|
||||
*/
|
||||
public void setX(Number x) {
|
||||
this.x = x;
|
||||
}
|
||||
/**
|
||||
* @return the y
|
||||
*/
|
||||
public Number getY() {
|
||||
return y;
|
||||
}
|
||||
/**
|
||||
* @param y the y to set
|
||||
*/
|
||||
public void setY(Number y) {
|
||||
this.y = y;
|
||||
}
|
||||
/**
|
||||
* @return the z
|
||||
*/
|
||||
public Number getZ() {
|
||||
return z;
|
||||
}
|
||||
/**
|
||||
* @param z the z to set
|
||||
*/
|
||||
public void setZ(Number z) {
|
||||
this.z = z;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,378 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2011 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but without any
|
||||
* warranty; without even the implied warranty of merchantability or fitness for
|
||||
* a particular purpose. See the GNU Lesser General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.renderer.xy.XYBlockRenderer;
|
||||
import org.jfree.data.DomainOrder;
|
||||
import org.jfree.data.general.DatasetChangeListener;
|
||||
import org.jfree.data.general.DatasetGroup;
|
||||
import org.jfree.data.xy.XYZDataset;
|
||||
import org.jfree.ui.RectangleAnchor;
|
||||
|
||||
/**
|
||||
* Dynamic dataset
|
||||
*/
|
||||
public class DynamicXYZDatasetNumber implements XYZDataset{
|
||||
|
||||
private final double xResolution;
|
||||
private final double yResolution;
|
||||
private final double incX;
|
||||
private final double incY;
|
||||
|
||||
private final NumberAxis xAxis = new NumberAxis();
|
||||
private double xLowerBound = Double.NaN;
|
||||
private double xUpperBound = Double.NaN;
|
||||
private final NumberAxis yAxis = new NumberAxis();
|
||||
private double yLowerBound = Double.NaN;
|
||||
private double yUpperBound = Double.NaN;
|
||||
private double zLowerBound = Double.NaN;
|
||||
|
||||
|
||||
private double zUpperBound = Double.NaN;
|
||||
|
||||
private final XYBlockRenderer renderer = new XYBlockRenderer();
|
||||
|
||||
|
||||
private final List<DatasetChangeListener> listeners = new ArrayList<DatasetChangeListener>();
|
||||
private List<DynamicXYZDatasetNumber.Vector> items = new ArrayList<DynamicXYZDatasetNumber.Vector>();
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public DynamicXYZDatasetNumber(){
|
||||
xResolution = 1.0;
|
||||
yResolution = 1.0;
|
||||
incX = xResolution/2;
|
||||
incY = yResolution/2;
|
||||
|
||||
xAxis.setRange(xLowerBound, xUpperBound);
|
||||
yAxis.setRange(yLowerBound, yUpperBound);
|
||||
|
||||
renderer.setBlockWidth(xResolution); // If this is not set the default block size is 1
|
||||
renderer.setBlockHeight(yResolution); // If this is not set the default block size is 1
|
||||
renderer.setBlockAnchor(RectangleAnchor.CENTER);
|
||||
renderer.setBaseCreateEntities(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add datapoint
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*/
|
||||
public void addData(Number x, Number y, Number z){
|
||||
items.add(new DynamicXYZDatasetNumber.Vector(x,y,z));
|
||||
|
||||
// Update axis
|
||||
|
||||
final double xv = x.doubleValue();
|
||||
final double yv = y.doubleValue();
|
||||
final double zv = z.doubleValue();
|
||||
|
||||
if(Double.isNaN(xLowerBound) && Double.isNaN(xUpperBound)){
|
||||
xLowerBound = xv-incX;
|
||||
xUpperBound = xv+incX;
|
||||
xAxis.setRange(xLowerBound, xUpperBound);
|
||||
}
|
||||
else{
|
||||
if(xv>(xUpperBound+incX)){
|
||||
xUpperBound = xv+incX;
|
||||
xAxis.setUpperBound(xUpperBound);
|
||||
}
|
||||
else if(xv<xLowerBound-incX){
|
||||
xLowerBound = xv-incX;
|
||||
xAxis.setLowerBound(xLowerBound);
|
||||
}
|
||||
}
|
||||
|
||||
if(Double.isNaN(yLowerBound) && Double.isNaN(yUpperBound)){
|
||||
yLowerBound = y.doubleValue()-incY;
|
||||
yUpperBound = y.doubleValue()+incY;
|
||||
yAxis.setRange(yLowerBound, yUpperBound);
|
||||
}
|
||||
else{
|
||||
if(yv>(yUpperBound+incY)){
|
||||
yUpperBound = yv+incY;
|
||||
yAxis.setUpperBound(yUpperBound);
|
||||
}
|
||||
else if(yv<yLowerBound-incY){
|
||||
yLowerBound = yv-incY;
|
||||
yAxis.setLowerBound(yLowerBound);
|
||||
}
|
||||
}
|
||||
|
||||
if(Double.isNaN(zLowerBound) && Double.isNaN(zUpperBound)){
|
||||
zLowerBound = zv;
|
||||
zUpperBound = zv;
|
||||
}
|
||||
else{
|
||||
if(zv>zUpperBound){
|
||||
zUpperBound = zv;
|
||||
}
|
||||
else if(zv<zLowerBound){
|
||||
zLowerBound = zv;
|
||||
}
|
||||
}
|
||||
|
||||
// Inform change listeners
|
||||
// DatasetChangeEvent event = new DatasetChangeEvent(this, this);
|
||||
// for(DatasetChangeListener l: listeners){
|
||||
// l.datasetChanged(event );
|
||||
// }
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.xy.XYDataset#getItemCount(int)
|
||||
*/
|
||||
@Override
|
||||
public int getItemCount(int series) {
|
||||
return items.size();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.xy.XYDataset#getX(int, int)
|
||||
*/
|
||||
@Override
|
||||
public Number getX(int series, int item) {
|
||||
return items.get(item).getX();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.xy.XYDataset#getXValue(int, int)
|
||||
*/
|
||||
@Override
|
||||
public double getXValue(int series, int item) {
|
||||
return items.get(item).getX().doubleValue();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.xy.XYDataset#getY(int, int)
|
||||
*/
|
||||
@Override
|
||||
public Number getY(int series, int item) {
|
||||
return items.get(item).getY();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.xy.XYDataset#getYValue(int, int)
|
||||
*/
|
||||
@Override
|
||||
public double getYValue(int series, int item) {
|
||||
return items.get(item).getY().doubleValue();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.xy.XYZDataset#getZ(int, int)
|
||||
*/
|
||||
@Override
|
||||
public Number getZ(int series, int item) {
|
||||
return items.get(item).getZ();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.xy.XYZDataset#getZValue(int, int)
|
||||
*/
|
||||
@Override
|
||||
public double getZValue(int series, int item) {
|
||||
return items.get(item).getZ().doubleValue();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.xy.XYDataset#getDomainOrder()
|
||||
*/
|
||||
@Override
|
||||
public DomainOrder getDomainOrder() {
|
||||
return DomainOrder.NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.general.SeriesDataset#getSeriesCount()
|
||||
*/
|
||||
@Override
|
||||
public int getSeriesCount() {
|
||||
// Series not implemented/used - dataset only holds one series
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.general.SeriesDataset#getSeriesKey(int)
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Comparable getSeriesKey(int series) {
|
||||
// Series not implemented/used
|
||||
return "";
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.general.SeriesDataset#indexOf(java.lang.Comparable)
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public int indexOf(Comparable seriesKey) {
|
||||
// Series not implemented/used
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.general.Dataset#getGroup()
|
||||
*/
|
||||
@Override
|
||||
public DatasetGroup getGroup() {
|
||||
// Not implemented/used
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.general.Dataset#setGroup(org.jfree.data.general.DatasetGroup)
|
||||
*/
|
||||
@Override
|
||||
public void setGroup(DatasetGroup group) {
|
||||
// Not implemented/used
|
||||
}
|
||||
|
||||
// Listener concept implementation
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.general.Dataset#addChangeListener(org.jfree.data.general.DatasetChangeListener)
|
||||
*/
|
||||
@Override
|
||||
public void addChangeListener(DatasetChangeListener listener) {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.jfree.data.general.Dataset#removeChangeListener(org.jfree.data.general.DatasetChangeListener)
|
||||
*/
|
||||
@Override
|
||||
public void removeChangeListener(DatasetChangeListener listener) {
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
|
||||
// Convenient methods
|
||||
|
||||
/**
|
||||
* @return the zLowerBound
|
||||
*/
|
||||
public double getzLowerBound() {
|
||||
return zLowerBound;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the zUpperBound
|
||||
*/
|
||||
public double getzUpperBound() {
|
||||
return zUpperBound;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the xAxis
|
||||
*/
|
||||
public NumberAxis getxAxis() {
|
||||
return xAxis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the yAxis
|
||||
*/
|
||||
public NumberAxis getyAxis() {
|
||||
return yAxis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the renderer
|
||||
*/
|
||||
public XYBlockRenderer getRenderer() {
|
||||
return renderer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class Vector{
|
||||
private Number x;
|
||||
private Number y;
|
||||
private Number z;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public Vector(){
|
||||
}
|
||||
|
||||
/**
|
||||
* @param x2
|
||||
* @param y2
|
||||
* @param z2
|
||||
*/
|
||||
public Vector(Number x, Number y, Number z) {
|
||||
// Right now x and xvalue are the same. This might change if we introduce a virtual grid ...
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
/**
|
||||
* @return the x
|
||||
*/
|
||||
public Number getX() {
|
||||
return x;
|
||||
}
|
||||
/**
|
||||
* @param x the x to set
|
||||
*/
|
||||
public void setX(Number x) {
|
||||
this.x = x;
|
||||
}
|
||||
/**
|
||||
* @return the y
|
||||
*/
|
||||
public Number getY() {
|
||||
return y;
|
||||
}
|
||||
/**
|
||||
* @param y the y to set
|
||||
*/
|
||||
public void setY(Number y) {
|
||||
this.y = y;
|
||||
}
|
||||
/**
|
||||
* @return the z
|
||||
*/
|
||||
public Number getZ() {
|
||||
return z;
|
||||
}
|
||||
/**
|
||||
* @param z the z to set
|
||||
*/
|
||||
public void setZ(Number z) {
|
||||
this.z = z;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.FlowLayout;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.JLabel;
|
||||
import java.awt.Font;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ActionEvent;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class ManualScaleDialog extends JDialog {
|
||||
// Default serial id
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final JPanel contentPanel = new JPanel();
|
||||
private JTextField textFieldHighValue;
|
||||
private JTextField textFieldLowValue;
|
||||
|
||||
private MatrixPlot plot;
|
||||
|
||||
private int selectedOption;
|
||||
|
||||
/**
|
||||
* Launch the application.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
ManualScaleDialog dialog = new ManualScaleDialog();
|
||||
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
||||
dialog.setVisible(true);
|
||||
System.out.println("HERE");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the dialog.
|
||||
*/
|
||||
public ManualScaleDialog() {
|
||||
setModal(true); // Block until dialog is disposed.
|
||||
setBounds(100, 100, 450, 300);
|
||||
getContentPane().setLayout(new BorderLayout());
|
||||
contentPanel.setLayout(new FlowLayout());
|
||||
contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
getContentPane().add(contentPanel, BorderLayout.CENTER);
|
||||
{
|
||||
JLabel lblLowValue = new JLabel("Low Value:");
|
||||
lblLowValue.setFont(new Font("Lucida Grande", Font.BOLD, 13));
|
||||
contentPanel.add(lblLowValue);
|
||||
}
|
||||
{
|
||||
textFieldLowValue = new JTextField();
|
||||
contentPanel.add(textFieldLowValue);
|
||||
textFieldLowValue.setColumns(10);
|
||||
}
|
||||
{
|
||||
JLabel lblHighValue = new JLabel("High Value:");
|
||||
lblHighValue.setFont(new Font("Lucida Grande", Font.BOLD, 13));
|
||||
contentPanel.add(lblHighValue);
|
||||
}
|
||||
{
|
||||
textFieldHighValue = new JTextField();
|
||||
contentPanel.add(textFieldHighValue);
|
||||
textFieldHighValue.setColumns(10);
|
||||
}
|
||||
{
|
||||
JPanel buttonPane = new JPanel();
|
||||
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
|
||||
getContentPane().add(buttonPane, BorderLayout.SOUTH);
|
||||
{
|
||||
JButton okButton = new JButton("OK");
|
||||
okButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
// set OK
|
||||
selectedOption = JOptionPane.OK_OPTION;
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
{
|
||||
JButton btnApply = new JButton("Apply");
|
||||
btnApply.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
// TODO apply values
|
||||
if(plot!=null){
|
||||
plot.setColorScale(getLow(), getHigh());
|
||||
}
|
||||
}
|
||||
});
|
||||
buttonPane.add(btnApply);
|
||||
}
|
||||
okButton.setActionCommand("OK");
|
||||
buttonPane.add(okButton);
|
||||
getRootPane().setDefaultButton(okButton);
|
||||
}
|
||||
{
|
||||
JButton cancelButton = new JButton("Cancel");
|
||||
cancelButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
// set Cancel
|
||||
selectedOption = JOptionPane.CANCEL_OPTION;
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
cancelButton.setActionCommand("Cancel");
|
||||
buttonPane.add(cancelButton);
|
||||
}
|
||||
}
|
||||
|
||||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
pack();
|
||||
}
|
||||
|
||||
public void showDialog(){
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
public void setMatrixPlot(MatrixPlot p){
|
||||
plot = p;
|
||||
}
|
||||
|
||||
public void setLow(double low){
|
||||
textFieldLowValue.setText(String.format("%.4f", low));
|
||||
}
|
||||
public void setHigh(double high){
|
||||
textFieldHighValue.setText(String.format("%.4f", high));
|
||||
}
|
||||
|
||||
public double getLow(){
|
||||
double low = Double.NaN;
|
||||
try{
|
||||
low = Double.parseDouble(textFieldLowValue.getText());
|
||||
}
|
||||
catch(NumberFormatException e){
|
||||
}
|
||||
return low;
|
||||
}
|
||||
|
||||
public double getHigh(){
|
||||
double high = Double.NaN;
|
||||
try{
|
||||
high = Double.parseDouble(textFieldHighValue.getText());
|
||||
}
|
||||
catch(NumberFormatException e){
|
||||
}
|
||||
return high;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the selectedOption
|
||||
*/
|
||||
public int getSelectedOption() {
|
||||
return selectedOption;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,379 +0,0 @@
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.WindowConstants;
|
||||
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.axis.ValueAxis;
|
||||
import org.jfree.chart.event.AxisChangeEvent;
|
||||
import org.jfree.chart.event.AxisChangeListener;
|
||||
import org.jfree.chart.labels.StandardXYZToolTipGenerator;
|
||||
import org.jfree.chart.labels.XYZToolTipGenerator;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.renderer.LookupPaintScale;
|
||||
import org.jfree.chart.renderer.PaintScale;
|
||||
import org.jfree.chart.renderer.xy.XYBlockRenderer;
|
||||
import org.jfree.chart.title.PaintScaleLegend;
|
||||
import org.jfree.data.Range;
|
||||
import org.jfree.ui.RectangleAnchor;
|
||||
import org.jfree.ui.RectangleEdge;
|
||||
import org.jfree.ui.RectangleInsets;
|
||||
|
||||
import ch.psi.plot.Plot;
|
||||
|
||||
|
||||
/**
|
||||
* Returns a matrix plot panel
|
||||
*/
|
||||
public class MatrixPlot implements Plot {
|
||||
|
||||
private static final int chartPanelWidth = 500;
|
||||
private static final int chartPanelHeight = 270;
|
||||
|
||||
private String title;
|
||||
private String xAxisLabel = "X";
|
||||
private String yAxisLabel = "Y";
|
||||
|
||||
private boolean grayScale = false;
|
||||
|
||||
private MatrixPlotData data;
|
||||
private JFreeChart chart;
|
||||
private ChartPanel chartPanel;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param title
|
||||
* @param data
|
||||
*/
|
||||
public MatrixPlot(String title, final MatrixPlotData data) {
|
||||
this.title = title;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
// Action Classes that implement methods called after keyboard input
|
||||
|
||||
/**
|
||||
* Adapt the context menu of the chart panel
|
||||
*/
|
||||
private void adaptContextMenu(final ChartPanel chartPanel){
|
||||
|
||||
// Show hide tooltips
|
||||
final String tooltipsMenuLabel = "Tooltips";
|
||||
final String hideTooltipsMenuLabel = "Hide Tooltips";
|
||||
JMenuItem contextMenuItemToolTip = new JMenuItem(tooltipsMenuLabel);
|
||||
contextMenuItemToolTip.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuItem source = (JMenuItem)(e.getSource());
|
||||
if (source.getText() == tooltipsMenuLabel){
|
||||
showTooltip();
|
||||
source.setText(hideTooltipsMenuLabel);
|
||||
}
|
||||
|
||||
else if (source.getText() == hideTooltipsMenuLabel){
|
||||
hideTooltip();
|
||||
source.setText(tooltipsMenuLabel);
|
||||
}
|
||||
}
|
||||
});
|
||||
chartPanel.getPopupMenu().add(contextMenuItemToolTip);
|
||||
|
||||
// Update colormap
|
||||
JMenuItem contextMenuItemAdaptScale = new JMenuItem("Update Scale");
|
||||
contextMenuItemAdaptScale.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
adaptColorMapScale();
|
||||
}
|
||||
});
|
||||
|
||||
// Set gray scale colormap
|
||||
JMenuItem contextMenuItemGrayScale = new JMenuItem("Gray Scale");
|
||||
contextMenuItemGrayScale.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
grayScale = true;
|
||||
adaptColorMapScale();
|
||||
}
|
||||
});
|
||||
|
||||
// Set color colormap
|
||||
JMenuItem contextMenuItemTemperatureColor = new JMenuItem("Color Scale");
|
||||
contextMenuItemTemperatureColor.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
grayScale = false;
|
||||
adaptColorMapScale();
|
||||
}
|
||||
});
|
||||
|
||||
// Set color colormap
|
||||
JMenuItem menuItemScale = new JMenuItem("Manual Scale");
|
||||
menuItemScale.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
ManualScaleDialog d = new ManualScaleDialog();
|
||||
d.setLocationRelativeTo(chartPanel);
|
||||
d.setLow(((PaintScaleLegend) chart.getSubtitles().get(0)).getScale().getLowerBound());
|
||||
d.setHigh(((PaintScaleLegend) chart.getSubtitles().get(0)).getScale().getUpperBound());
|
||||
d.setMatrixPlot(MatrixPlot.this);
|
||||
|
||||
d.showDialog();
|
||||
if(d.getSelectedOption()==JOptionPane.OK_OPTION){
|
||||
setColorScale(d.getLow(), d.getHigh());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Group colormap related menu items
|
||||
JMenuItem contextMenuChooseColorMap = new JMenu("ColorMap");
|
||||
contextMenuChooseColorMap.add(contextMenuItemAdaptScale);
|
||||
contextMenuChooseColorMap.add(menuItemScale);
|
||||
contextMenuChooseColorMap.add(contextMenuItemGrayScale);
|
||||
contextMenuChooseColorMap.add(contextMenuItemTemperatureColor);
|
||||
chartPanel.getPopupMenu().add(contextMenuChooseColorMap);
|
||||
|
||||
// Add separator
|
||||
chartPanel.getPopupMenu().addSeparator();
|
||||
|
||||
// Detach plot into an own frame
|
||||
JMenuItem contextMenuItemDetach = new JMenuItem("Detach Plot");
|
||||
contextMenuItemDetach.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
MatrixPlot p = new MatrixPlot(title, data);
|
||||
|
||||
final JFrame frame = new JFrame(title);
|
||||
frame.getContentPane();
|
||||
frame.setContentPane(p.getChartPanel());
|
||||
frame.pack();
|
||||
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); // Close application if frame is closed
|
||||
|
||||
// Set color scale
|
||||
p.adaptColorMapScale();
|
||||
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
chartPanel.getPopupMenu().add(contextMenuItemDetach);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show Tooltips. This is not done per default since it makes the app slow for datasize >= 1M
|
||||
*/
|
||||
private void showTooltip(){
|
||||
//Tooltips are quit expensive
|
||||
DecimalFormat dm = new DecimalFormat("0.##########");
|
||||
XYZToolTipGenerator xYZToolTipGenerator = new StandardXYZToolTipGenerator("{0}: ({1} / {2} / {3})", dm, dm, dm);
|
||||
|
||||
chart.getXYPlot().getRenderer().setBaseToolTipGenerator(xYZToolTipGenerator);
|
||||
((XYBlockRenderer)chart.getXYPlot().getRenderer()).setBaseCreateEntities(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear Tooltips
|
||||
*/
|
||||
private void hideTooltip(){
|
||||
//Tooltips are quit expensive
|
||||
((XYBlockRenderer)chart.getXYPlot().getRenderer()).setBaseToolTipGenerator(null);
|
||||
((XYBlockRenderer)chart.getXYPlot().getRenderer()).setBaseCreateEntities(false);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adapt the lower and upper color map scale to the min and max data values of the currently selected region
|
||||
* Need to be called AFTER the chart panel is created
|
||||
*/
|
||||
public void adaptColorMapScale(){
|
||||
double[] v = XYZDatasetUtil.minMaxZValue(data.getData());
|
||||
if(v[0]!=Double.NaN && v[1]!=Double.NaN && v[0]<v[1]){
|
||||
setColorScale(v[0],v[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the min and max of color map scale to scaleMin and scaleMax
|
||||
* @param scaleMin min value of scale
|
||||
* @param scaleMax max value of scale
|
||||
*/
|
||||
public void setColorScale(double scaleMin, double scaleMax){
|
||||
|
||||
// Create scale for legend
|
||||
LookupPaintScale legendScale = new LookupPaintScale(scaleMin, scaleMax, Color.GRAY);
|
||||
setScaleColors(legendScale, scaleMin, scaleMax);
|
||||
|
||||
// Create legend
|
||||
PaintScaleLegend legend = new PaintScaleLegend(legendScale, new NumberAxis());
|
||||
legend.setPadding(new RectangleInsets(5, 5, 5, 5));
|
||||
// Width of the legend (colorbar)
|
||||
legend.setStripWidth(20);
|
||||
// Position of the legend
|
||||
legend.setPosition(RectangleEdge.RIGHT);
|
||||
// Remove background paint/color
|
||||
legend.setBackgroundPaint(null);
|
||||
|
||||
// Add legend to plot panel
|
||||
chart.clearSubtitles();
|
||||
chart.addSubtitle(legend);
|
||||
|
||||
|
||||
//We need a second scale for rendering only, where the 'infinities' are in correct color
|
||||
LookupPaintScale rendererScale = new LookupPaintScale(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Color.GRAY);
|
||||
setScaleColors(rendererScale, scaleMin, scaleMax);
|
||||
// Make the paint scale range from - to + infinity
|
||||
if (grayScale) {
|
||||
rendererScale.add(Double.NEGATIVE_INFINITY, ColorManager.getGrayForValue(scaleMin, scaleMin, scaleMax));
|
||||
rendererScale.add(Double.POSITIVE_INFINITY, ColorManager.getGrayForValue(scaleMax, scaleMin, scaleMax));
|
||||
} else {
|
||||
rendererScale.add(Double.NEGATIVE_INFINITY, ColorManager.getColourForValue(scaleMin, scaleMin, scaleMax));
|
||||
rendererScale.add(Double.POSITIVE_INFINITY, ColorManager.getColourForValue(scaleMax, scaleMin, scaleMax));
|
||||
}
|
||||
((XYBlockRenderer) chart.getXYPlot().getRenderer()).setPaintScale(rendererScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the colors for the colored Paint Scale (either single color or temperature color)
|
||||
* @param paintScale
|
||||
* @param scaleMin
|
||||
* @param scaleMax
|
||||
*/
|
||||
private void setScaleColors(PaintScale paintScale, double scaleMin, double scaleMax){
|
||||
if (grayScale) {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
double value = scaleMin + (i / 255.0) * (scaleMax - scaleMin);
|
||||
((LookupPaintScale) paintScale).add(value, ColorManager.getGrayForValue(value, scaleMin, scaleMax));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
double value = scaleMin + (i / 255.0) * (scaleMax - scaleMin);
|
||||
((LookupPaintScale) paintScale).add(value, ColorManager.getColourForValue(value, scaleMin, scaleMax));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get plot data
|
||||
* @return
|
||||
*/
|
||||
public MatrixPlotData getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the chart panel
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public ChartPanel getChartPanel() {
|
||||
if(chartPanel == null){
|
||||
|
||||
// Create matrix chart
|
||||
// Init size of plot area according to min and max set in the datas metadata
|
||||
// Set axis: (plus half bin size on both sides), since we plot the bins centered.
|
||||
NumberAxis xAxis = new NumberAxis(xAxisLabel);
|
||||
xAxis.setLowerBound(data.getAxisMinX());
|
||||
xAxis.setUpperBound(data.getAxisMaxX());
|
||||
|
||||
NumberAxis yAxis = new NumberAxis(yAxisLabel);
|
||||
yAxis.setLowerBound(data.getAxisMinY());
|
||||
yAxis.setUpperBound(data.getAxisMaxY());
|
||||
|
||||
// Configure block renderer to have the blocks rendered in the correct size
|
||||
XYBlockRenderer renderer = new XYBlockRenderer();
|
||||
renderer.setBlockWidth(data.getBinWidthX()); // If this is not set the default block size is 1
|
||||
renderer.setBlockHeight(data.getBinWidthY()); // If this is not set the default block size is 1
|
||||
renderer.setBlockAnchor(RectangleAnchor.CENTER);
|
||||
|
||||
renderer.setBaseCreateEntities(false);
|
||||
XYPlot plot = new XYPlot(data.getData(), xAxis, yAxis, renderer);
|
||||
|
||||
// Remove background paint/color
|
||||
plot.setBackgroundPaint(null);
|
||||
|
||||
// Set the maximum zoom out to the initial zoom rate This also
|
||||
// provides a workaround for dynamic plots because there zoom out does not work correctly (zoom out to infinity)
|
||||
plot.getRangeAxis().addChangeListener(new AxisChangeListener() {
|
||||
@Override
|
||||
public void axisChanged(AxisChangeEvent event) {
|
||||
ValueAxis axis = ((ValueAxis)event.getAxis());
|
||||
if(axis.getLowerBound() < data.getAxisMinY() || axis.getUpperBound() > data.getAxisMaxY()){
|
||||
Range range = new Range(data.getAxisMinY(), data.getAxisMaxY());
|
||||
axis.setRange(range, true, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
plot.getDomainAxis().addChangeListener(new AxisChangeListener() {
|
||||
@Override
|
||||
public void axisChanged(AxisChangeEvent event) {
|
||||
ValueAxis axis = ((ValueAxis)event.getAxis());
|
||||
if(axis.getLowerBound() < data.getAxisMinX() || axis.getUpperBound() > data.getAxisMaxX()){
|
||||
Range range = new Range(data.getAxisMinX(), data.getAxisMaxX());
|
||||
axis.setRange(range, true, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
chart = new JFreeChart(title, plot);
|
||||
|
||||
//Remove the series label (also called legend)
|
||||
chart.removeLegend();
|
||||
//AntiAliasing is used to speed up rendering
|
||||
// chart.setAntiAlias(false);
|
||||
|
||||
// Init PaintScale
|
||||
setColorScale(0,1);
|
||||
|
||||
|
||||
|
||||
//Create the Chartpanel where the chart will be plotted
|
||||
chartPanel = new ChartPanel(chart);
|
||||
|
||||
chartPanel.setPreferredSize(new java.awt.Dimension(chartPanelWidth, chartPanelHeight));
|
||||
|
||||
//All interactive menu items
|
||||
adaptContextMenu(chartPanel);
|
||||
}
|
||||
|
||||
|
||||
return chartPanel;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.plot.Plot#update()
|
||||
*/
|
||||
@Override
|
||||
public void update() {
|
||||
chart.fireChartChanged();
|
||||
adaptColorMapScale();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.plot.Plot#getChart()
|
||||
*/
|
||||
@Override
|
||||
public JFreeChart getChart() {
|
||||
return chart;
|
||||
}
|
||||
}
|
||||
@@ -1,352 +0,0 @@
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.WindowConstants;
|
||||
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.labels.StandardXYZToolTipGenerator;
|
||||
import org.jfree.chart.labels.XYZToolTipGenerator;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.renderer.LookupPaintScale;
|
||||
import org.jfree.chart.renderer.PaintScale;
|
||||
import org.jfree.chart.renderer.xy.XYBlockRenderer;
|
||||
import org.jfree.chart.title.PaintScaleLegend;
|
||||
import org.jfree.ui.RectangleEdge;
|
||||
import org.jfree.ui.RectangleInsets;
|
||||
|
||||
import ch.psi.plot.Plot;
|
||||
|
||||
|
||||
/**
|
||||
* Returns a matrix plot panel
|
||||
*/
|
||||
public class MatrixPlot2 implements Plot {
|
||||
|
||||
private static final int chartPanelWidth = 500;
|
||||
private static final int chartPanelHeight = 270;
|
||||
|
||||
private String title;
|
||||
|
||||
private boolean grayScale = false;
|
||||
|
||||
private DynamicXYZDatasetList data;
|
||||
private JFreeChart chart;
|
||||
private ChartPanel chartPanel;
|
||||
|
||||
/**
|
||||
* @param title
|
||||
* @param data
|
||||
*/
|
||||
public MatrixPlot2(String title, final DynamicXYZDatasetList data) {
|
||||
this.title = title;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
// Action Classes that implement methods called after keyboard input
|
||||
|
||||
/**
|
||||
* Adapt the context menu of the chart panel
|
||||
*/
|
||||
private void adaptContextMenu(final ChartPanel chartPanel){
|
||||
|
||||
// Show hide tooltips
|
||||
final String tooltipsMenuLabel = "Tooltips";
|
||||
final String hideTooltipsMenuLabel = "Hide Tooltips";
|
||||
JMenuItem contextMenuItemToolTip = new JMenuItem(tooltipsMenuLabel);
|
||||
contextMenuItemToolTip.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuItem source = (JMenuItem)(e.getSource());
|
||||
if (source.getText() == tooltipsMenuLabel){
|
||||
showTooltip();
|
||||
source.setText(hideTooltipsMenuLabel);
|
||||
}
|
||||
|
||||
else if (source.getText() == hideTooltipsMenuLabel){
|
||||
hideTooltip();
|
||||
source.setText(tooltipsMenuLabel);
|
||||
}
|
||||
}
|
||||
});
|
||||
chartPanel.getPopupMenu().add(contextMenuItemToolTip);
|
||||
|
||||
// Update colormap
|
||||
JMenuItem contextMenuItemAdaptScale = new JMenuItem("Update Scale");
|
||||
contextMenuItemAdaptScale.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
adaptColorMapScale();
|
||||
}
|
||||
});
|
||||
|
||||
// Set gray scale colormap
|
||||
JMenuItem contextMenuItemGrayScale = new JMenuItem("Gray Scale");
|
||||
contextMenuItemGrayScale.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
grayScale = true;
|
||||
adaptColorMapScale();
|
||||
}
|
||||
});
|
||||
|
||||
// Set color colormap
|
||||
JMenuItem contextMenuItemTemperatureColor = new JMenuItem("Color Scale");
|
||||
contextMenuItemTemperatureColor.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
grayScale = false;
|
||||
adaptColorMapScale();
|
||||
}
|
||||
});
|
||||
|
||||
// // Set color colormap
|
||||
// JMenuItem menuItemScale = new JMenuItem("Manual Scale");
|
||||
// menuItemScale.addActionListener(new ActionListener() {
|
||||
// @Override
|
||||
// public void actionPerformed(ActionEvent e) {
|
||||
// ManualScaleDialog d = new ManualScaleDialog();
|
||||
// d.setLocationRelativeTo(chartPanel);
|
||||
// d.setLow(((PaintScaleLegend) chart.getSubtitles().get(0)).getScale().getLowerBound());
|
||||
// d.setHigh(((PaintScaleLegend) chart.getSubtitles().get(0)).getScale().getUpperBound());
|
||||
// d.setMatrixPlot(MatrixPlot2.this);
|
||||
//
|
||||
// d.showDialog();
|
||||
// if(d.getSelectedOption()==JOptionPane.OK_OPTION){
|
||||
// setColorScale(d.getLow(), d.getHigh());
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// Group colormap related menu items
|
||||
JMenuItem contextMenuChooseColorMap = new JMenu("ColorMap");
|
||||
contextMenuChooseColorMap.add(contextMenuItemAdaptScale);
|
||||
// contextMenuChooseColorMap.add(menuItemScale);
|
||||
contextMenuChooseColorMap.add(contextMenuItemGrayScale);
|
||||
contextMenuChooseColorMap.add(contextMenuItemTemperatureColor);
|
||||
chartPanel.getPopupMenu().add(contextMenuChooseColorMap);
|
||||
|
||||
// Add separator
|
||||
chartPanel.getPopupMenu().addSeparator();
|
||||
|
||||
// Detach plot into an own frame
|
||||
JMenuItem contextMenuItemDetach = new JMenuItem("Detach Plot");
|
||||
contextMenuItemDetach.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
MatrixPlot2 p = new MatrixPlot2(title, data);
|
||||
|
||||
final JFrame frame = new JFrame(title);
|
||||
frame.getContentPane();
|
||||
frame.setContentPane(p.getChartPanel());
|
||||
frame.pack();
|
||||
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); // Close application if frame is closed
|
||||
|
||||
// Set color scale
|
||||
p.adaptColorMapScale();
|
||||
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
chartPanel.getPopupMenu().add(contextMenuItemDetach);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show Tooltips. This is not done per default since it makes the app slow for datasize >= 1M
|
||||
*/
|
||||
private void showTooltip(){
|
||||
//Tooltips are quit expensive
|
||||
DecimalFormat dm = new DecimalFormat("0.##########");
|
||||
XYZToolTipGenerator xYZToolTipGenerator = new StandardXYZToolTipGenerator("{0}: ({1} / {2} / {3})", dm, dm, dm);
|
||||
|
||||
chart.getXYPlot().getRenderer().setBaseToolTipGenerator(xYZToolTipGenerator);
|
||||
((XYBlockRenderer)chart.getXYPlot().getRenderer()).setBaseCreateEntities(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear Tooltips
|
||||
*/
|
||||
private void hideTooltip(){
|
||||
//Tooltips are quit expensive
|
||||
((XYBlockRenderer)chart.getXYPlot().getRenderer()).setBaseToolTipGenerator(null);
|
||||
((XYBlockRenderer)chart.getXYPlot().getRenderer()).setBaseCreateEntities(false);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adapt the lower and upper color map scale to the min and max data values of the currently selected region
|
||||
* Need to be called AFTER the chart panel is created
|
||||
*/
|
||||
public void adaptColorMapScale(){
|
||||
if(!Double.isNaN(data.getzLowerBound()) && !Double.isNaN(data.getzUpperBound())){
|
||||
setColorScale(data.getzLowerBound(),data.getzUpperBound());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the min and max of color map scale to scaleMin and scaleMax
|
||||
* @param scaleMin min value of scale
|
||||
* @param scaleMax max value of scale
|
||||
*/
|
||||
public void setColorScale(double scaleMin, double scaleMax){
|
||||
|
||||
// Create scale for legend
|
||||
LookupPaintScale legendScale = new LookupPaintScale(scaleMin, scaleMax, Color.GRAY);
|
||||
setScaleColors(legendScale, scaleMin, scaleMax);
|
||||
|
||||
// Create legend
|
||||
PaintScaleLegend legend = new PaintScaleLegend(legendScale, new NumberAxis());
|
||||
legend.setPadding(new RectangleInsets(5, 5, 5, 5));
|
||||
// Width of the legend (colorbar)
|
||||
legend.setStripWidth(20);
|
||||
// Position of the legend
|
||||
legend.setPosition(RectangleEdge.RIGHT);
|
||||
// Remove background paint/color
|
||||
legend.setBackgroundPaint(null);
|
||||
|
||||
// Add legend to plot panel
|
||||
chart.clearSubtitles();
|
||||
chart.addSubtitle(legend);
|
||||
|
||||
|
||||
//We need a second scale for rendering only, where the 'infinities' are in correct color
|
||||
LookupPaintScale rendererScale = new LookupPaintScale(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Color.GRAY);
|
||||
setScaleColors(rendererScale, scaleMin, scaleMax);
|
||||
// Make the paint scale range from - to + infinity
|
||||
if (grayScale) {
|
||||
rendererScale.add(Double.NEGATIVE_INFINITY, ColorManager.getGrayForValue(scaleMin, scaleMin, scaleMax));
|
||||
rendererScale.add(Double.POSITIVE_INFINITY, ColorManager.getGrayForValue(scaleMax, scaleMin, scaleMax));
|
||||
} else {
|
||||
rendererScale.add(Double.NEGATIVE_INFINITY, ColorManager.getColourForValue(scaleMin, scaleMin, scaleMax));
|
||||
rendererScale.add(Double.POSITIVE_INFINITY, ColorManager.getColourForValue(scaleMax, scaleMin, scaleMax));
|
||||
}
|
||||
((XYBlockRenderer) chart.getXYPlot().getRenderer()).setPaintScale(rendererScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the colors for the colored Paint Scale (either single color or temperature color)
|
||||
* @param paintScale
|
||||
* @param scaleMin
|
||||
* @param scaleMax
|
||||
*/
|
||||
private void setScaleColors(PaintScale paintScale, double scaleMin, double scaleMax){
|
||||
if (grayScale) {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
double value = scaleMin + (i / 255.0) * (scaleMax - scaleMin);
|
||||
((LookupPaintScale) paintScale).add(value, ColorManager.getGrayForValue(value, scaleMin, scaleMax));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
double value = scaleMin + (i / 255.0) * (scaleMax - scaleMin);
|
||||
((LookupPaintScale) paintScale).add(value, ColorManager.getColourForValue(value, scaleMin, scaleMax));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get plot data
|
||||
* @return
|
||||
*/
|
||||
public DynamicXYZDatasetList getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the chart panel
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public ChartPanel getChartPanel() {
|
||||
if(chartPanel == null){
|
||||
|
||||
XYPlot plot = new XYPlot(data, data.getxAxis(), data.getyAxis(), data.getRenderer());
|
||||
|
||||
|
||||
// Remove background paint/color
|
||||
plot.setBackgroundPaint(null);
|
||||
|
||||
// Set the maximum zoom out to the initial zoom rate This also
|
||||
// provides a workaround for dynamic plots because there zoom out does not work correctly (zoom out to infinity)
|
||||
// plot.getRangeAxis().addChangeListener(new AxisChangeListener() {
|
||||
// @Override
|
||||
// public void axisChanged(AxisChangeEvent event) {
|
||||
// ValueAxis axis = ((ValueAxis)event.getAxis());
|
||||
// if(axis.getLowerBound() < data.getyLowerBound() || axis.getUpperBound() > data.getyUpperBound()){
|
||||
// Range range = new Range(data.getyLowerBound(), data.getyUpperBound());
|
||||
// axis.setRange(range, true, false);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// plot.getDomainAxis().addChangeListener(new AxisChangeListener() {
|
||||
// @Override
|
||||
// public void axisChanged(AxisChangeEvent event) {
|
||||
// ValueAxis axis = ((ValueAxis)event.getAxis());
|
||||
// if(axis.getLowerBound() < data.getxLowerBound() || axis.getUpperBound() > data.getxUpperBound()){
|
||||
// Range range = new Range(data.getxLowerBound(), data.getxUpperBound());
|
||||
// axis.setRange(range, true, false);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
|
||||
chart = new JFreeChart(title, plot);
|
||||
|
||||
//Remove the series label (also called legend)
|
||||
chart.removeLegend();
|
||||
//AntiAliasing is used to speed up rendering
|
||||
// chart.setAntiAlias(false);
|
||||
|
||||
// Init PaintScale
|
||||
setColorScale(0,1);
|
||||
|
||||
|
||||
|
||||
//Create the Chartpanel where the chart will be plotted
|
||||
chartPanel = new ChartPanel(chart);
|
||||
|
||||
chartPanel.setPreferredSize(new java.awt.Dimension(chartPanelWidth, chartPanelHeight));
|
||||
|
||||
//All interactive menu items
|
||||
adaptContextMenu(chartPanel);
|
||||
}
|
||||
|
||||
|
||||
return chartPanel;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.plot.Plot#update()
|
||||
*/
|
||||
@Override
|
||||
public void update() {
|
||||
chart.fireChartChanged();
|
||||
adaptColorMapScale();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.plot.Plot#getChart()
|
||||
*/
|
||||
@Override
|
||||
public JFreeChart getChart() {
|
||||
return chart;
|
||||
}
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jfree.data.xy.DefaultXYZDataset;
|
||||
import org.jfree.data.xy.XYZDataset;
|
||||
|
||||
/**
|
||||
* PlotData implementation optimized for matrix data.
|
||||
* ...
|
||||
*/
|
||||
public class MatrixPlotData {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MatrixPlotData.class.getName());
|
||||
|
||||
private final double minX;
|
||||
private final double maxX;
|
||||
private final int numberOfBinsX;
|
||||
private final double binWidthX;
|
||||
|
||||
private final double minY;
|
||||
private final double maxY;
|
||||
private final int numberOfBinsY;
|
||||
private final double binWidthY;
|
||||
|
||||
private final double axisMinX;
|
||||
private final double axisMaxX;
|
||||
private final double axisMinY;
|
||||
private final double axisMaxY;
|
||||
|
||||
|
||||
double[] xvalues;
|
||||
double[] yvalues;
|
||||
double[] zvalues;
|
||||
|
||||
private XYZDataset data;
|
||||
|
||||
public MatrixPlotData(double minX, double maxX, int nX, double minY, double maxY, int nY){
|
||||
|
||||
this.minX = minX;
|
||||
this.maxX = maxX;
|
||||
this.numberOfBinsX = nX;
|
||||
|
||||
this.minY = minY;
|
||||
this.maxY = maxY;
|
||||
this.numberOfBinsY = nY;
|
||||
|
||||
this.binWidthX = (maxX - minX)/(double) (numberOfBinsX - 1);
|
||||
this.binWidthY = (maxY - minY)/(double) (numberOfBinsY - 1);
|
||||
|
||||
// The axis min and max values need to be half a bin larger. Otherwise the outer pixels
|
||||
// will not be plotted correctly (half of the pixel is missing)
|
||||
this.axisMinX = minX - 0.5*binWidthX;
|
||||
this.axisMaxX = maxX + 0.5*binWidthX;
|
||||
|
||||
this.axisMinY = minY - 0.5*binWidthY;
|
||||
this.axisMaxY = maxY + 0.5*binWidthY;
|
||||
|
||||
int arraylength = numberOfBinsX*numberOfBinsY;
|
||||
xvalues = new double[arraylength];
|
||||
yvalues = new double[arraylength];
|
||||
zvalues = new double[arraylength];
|
||||
|
||||
Arrays.fill(xvalues, Double.NEGATIVE_INFINITY);
|
||||
Arrays.fill(yvalues, Double.NEGATIVE_INFINITY);
|
||||
Arrays.fill(zvalues, Double.NEGATIVE_INFINITY);
|
||||
|
||||
double[][] dataArray = new double[][] {xvalues, yvalues, zvalues};
|
||||
|
||||
|
||||
//Create the XYDataset (org.jfree), not to be confused with the ch.psi dataSet)
|
||||
data = new DefaultXYZDataset();
|
||||
((DefaultXYZDataset)data).addSeries("Data" , dataArray);
|
||||
}
|
||||
|
||||
public XYZDataset getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void addData(final double x, final double y, final double z) {
|
||||
final int xBin = ((int) ((x - axisMinX)/binWidthX));
|
||||
final int yBin = ((int) ((y - axisMinY)/binWidthY));
|
||||
final int index = yBin * numberOfBinsX + xBin;
|
||||
|
||||
try{
|
||||
//x Value is column, y value is row
|
||||
xvalues[index] = x;
|
||||
yvalues[index] = y;
|
||||
zvalues[index] = z;
|
||||
}
|
||||
catch(ArrayIndexOutOfBoundsException e){
|
||||
logger.log(Level.WARNING, "Unable to add data point at index "+index+" [x: "+x+" y: "+y+"]", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
Arrays.fill(xvalues, Double.NEGATIVE_INFINITY);
|
||||
Arrays.fill(yvalues, Double.NEGATIVE_INFINITY);
|
||||
Arrays.fill(zvalues, Double.NEGATIVE_INFINITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the axisMinX
|
||||
*/
|
||||
public double getAxisMinX() {
|
||||
return axisMinX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the axisMinY
|
||||
*/
|
||||
public double getAxisMinY() {
|
||||
return axisMinY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the binWidthX
|
||||
*/
|
||||
public double getBinWidthX() {
|
||||
return binWidthX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the binWidthY
|
||||
*/
|
||||
public double getBinWidthY() {
|
||||
return binWidthY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the minX
|
||||
*/
|
||||
public double getMinX() {
|
||||
return minX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the maxX
|
||||
*/
|
||||
public double getMaxX() {
|
||||
return maxX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the minY
|
||||
*/
|
||||
public double getMinY() {
|
||||
return minY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the maxY
|
||||
*/
|
||||
public double getMaxY() {
|
||||
return maxY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the axisMaxX
|
||||
*/
|
||||
public double getAxisMaxX() {
|
||||
return axisMaxX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the axisMaxY
|
||||
*/
|
||||
public double getAxisMaxY() {
|
||||
return axisMaxY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the numberOfBinsX
|
||||
*/
|
||||
public int getNumberOfBinsX() {
|
||||
return numberOfBinsX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the numberOfBinsY
|
||||
*/
|
||||
public int getNumberOfBinsY() {
|
||||
return numberOfBinsY;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import org.jfree.data.xy.XYZDataset;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class XYZDatasetUtil {
|
||||
|
||||
/**
|
||||
* Find the minimum and maximum value of the dataset
|
||||
* @param dataset Dataset to find the min and max value
|
||||
* @return Double array with min in element 0 and max in element 1
|
||||
*/
|
||||
public static double[] minMaxZValue(XYZDataset dataset){
|
||||
|
||||
double min = Double.NaN;
|
||||
double max = Double.NaN;
|
||||
|
||||
if(dataset != null){
|
||||
int seriesCount = dataset.getSeriesCount();
|
||||
for(int s=0;s<seriesCount;s++){
|
||||
int itemCount = dataset.getItemCount(s);
|
||||
boolean first = true;
|
||||
for(int i=0;i<itemCount;i++){
|
||||
|
||||
double v = dataset.getZValue(s, i);
|
||||
if(v!=Double.NEGATIVE_INFINITY){
|
||||
if(first){
|
||||
min=v;
|
||||
max=v;
|
||||
first=false;
|
||||
}
|
||||
else{
|
||||
if(v>max){
|
||||
max=v;
|
||||
}
|
||||
if(v<min){
|
||||
min=v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double[] value = new double[2];
|
||||
value[0]=min;
|
||||
value[1]=max;
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
ch.psi.plot.jfree.LinePlot
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
|
||||
import ch.psi.plot.LinePlot;
|
||||
import ch.psi.plot.LinePlotSeries;
|
||||
import ch.psi.plot.Plot;
|
||||
import ch.psi.plot.utils.SwingUtils;
|
||||
import ch.psi.plot.xy.generator.Sinus;
|
||||
import ch.psi.plot.xy.generator.XYGenerator;
|
||||
import javax.swing.JFrame;
|
||||
|
||||
/**
|
||||
* Test for the LinePlot class
|
||||
*/
|
||||
public class LinePlotTest {
|
||||
|
||||
public static void main(final String[] args) throws InterruptedException {
|
||||
//for(int i=0;i<10;i++)
|
||||
{
|
||||
//LinePlot linePlot = ServiceLoader.load(LinePlot.class).iterator().next();
|
||||
//LinePlot linePlot = new ch.psi.plot.jlchart.LinePlot();
|
||||
//LinePlot linePlot = new ch.psi.plot.jfree.LinePlot();
|
||||
LinePlot linePlot = new ch.psi.plot.javafx.LinePlot() ;
|
||||
|
||||
linePlot.setTitle("Title");
|
||||
|
||||
//linePlot.setRangeX(0,10000);
|
||||
//linePlot.setRangeY(0,10);
|
||||
//linePlot.setData(getDataFromGenerator(1));
|
||||
addDataFromGenerator(0, 10, 1000, linePlot);
|
||||
|
||||
JFrame frame = new JFrame();
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setContentPane(linePlot.getChartPanel());
|
||||
frame.pack();
|
||||
SwingUtils.centerOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
frame.requestFocus();
|
||||
|
||||
// Thread.sleep(2000);
|
||||
//addDataFromGenerator(0, 10, 1000, linePlot);
|
||||
//linePlot.getAxis(Plot.AxisId.X).setRange(100,500);
|
||||
//linePlot.getAxis(Plot.AxisId.Y).setRange(0,5);
|
||||
//Thread.sleep(2000);
|
||||
//linePlot.getAxis(Plot.AxisId.X).setAutoRange();
|
||||
//linePlot.getAxis(Plot.AxisId.Y).setAutoRange();
|
||||
}
|
||||
|
||||
Thread.sleep(3600000);
|
||||
}
|
||||
|
||||
private static void addDataFromGenerator(final int sleep, final int series, final int size, final LinePlot plot) {
|
||||
final String seriesBaseName = "Generator Data";
|
||||
final XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, size, false);
|
||||
|
||||
Thread t = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
long start = System.currentTimeMillis();
|
||||
for (int t = 0; t < series; t++) {
|
||||
// Reset generator
|
||||
generator.reset();
|
||||
|
||||
String seriesName = seriesBaseName + " - " + t;
|
||||
LinePlotSeries series = new LinePlotSeries(seriesName);
|
||||
plot.addSeries(series);
|
||||
|
||||
double[] xy;
|
||||
while ((xy = generator.getNewPoint()) != null) {
|
||||
series.appendData(xy[0], xy[1] + t); // Add t to the y value to see the plotted line
|
||||
// data.getSeries(seriesName).add(xy[0], xy[1]+t,false); // No notification send - Update of GUI will be performed periodically
|
||||
|
||||
try {
|
||||
Thread.sleep(sleep);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("DONE: " + (System.currentTimeMillis() - start));
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
import ch.psi.plot.MatrixPlotSeries;
|
||||
import ch.psi.plot.Plot;
|
||||
import ch.psi.plot.xyz.generator.Gauss2D;
|
||||
|
||||
//import ch.psi.sls.xasec.data.DataSet;
|
||||
//import ch.psi.sls.xasec.data.DataSetUtils;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.WindowConstants;
|
||||
|
||||
/**
|
||||
* Test case for MatrixPlot class
|
||||
*
|
||||
*/
|
||||
public class MatrixPlotTest {
|
||||
|
||||
final static int sleepTime = 0;
|
||||
final static double startX = 10;
|
||||
final static double stepSizeX = 1;
|
||||
final static int stepsX = 100;
|
||||
final static double startY = 300;
|
||||
final static double stepSizeY = 2;
|
||||
final static int stepsY = 200;
|
||||
final static MatrixPlotSeries data = new MatrixPlotSeries("", startX, startX + stepsX * stepSizeX, stepsX + 1, startY, startY + stepsY * stepSizeY, stepsY + 1);
|
||||
final static Gauss2D generator = new Gauss2D(50, 500, 40, 800, 2);
|
||||
|
||||
public static void main(final String[] args) throws InterruptedException {
|
||||
final ch.psi.plot.MatrixPlot plot = new ch.psi.plot.jzy3d.MatrixPlot();
|
||||
//final ch.psi.plot.MatrixPlot plot=new ch.psi.plot.jfree.MatrixPlot();
|
||||
|
||||
//plot.getAxis(Plot.AxisId.Z).setRange(0.0, 4.0);
|
||||
//final XYZGenerator generator = new XYZGenerator(new Sinus2D(2, 4), startX, stepSizeX, stepsX, startY, stepSizeY, stepsY, false);
|
||||
//final SphericalWave generator = new SphericalWave(50, 1000, 10, 200, 1);
|
||||
plot.setTitle("Matrix Plot Test");
|
||||
//plot.getAxis(Plot.AxisId.Z).setRange(2.0, 3.0);
|
||||
//plot.addSeries(data);
|
||||
|
||||
final JFrame frame = new JFrame("");
|
||||
frame.setContentPane(plot.getChartPanel());
|
||||
frame.pack();
|
||||
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
|
||||
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
frame.setVisible(true);
|
||||
//runnable.run();
|
||||
}
|
||||
});
|
||||
//plot.getAxis(Plot.AxisId.Z).setRange(2.0, 4.0);
|
||||
//plot.getAxis(Plot.AxisId.X).setRange(40, 60);
|
||||
//plot.getAxis(Plot.AxisId.Y).setRange(400, 600);
|
||||
|
||||
Thread.sleep(1000);
|
||||
plot.addSeries(data);
|
||||
|
||||
Thread t = new Thread(runnable);
|
||||
t.start();
|
||||
|
||||
/*
|
||||
plot.setUpdatesEnabled(false);
|
||||
for (int i=0;i<20;i++){
|
||||
Thread.sleep(1000);
|
||||
plot.requestUpdate();
|
||||
}
|
||||
while(t.isAlive())
|
||||
Thread.sleep(10);
|
||||
plot.requestUpdate();
|
||||
*/
|
||||
/*
|
||||
Thread.sleep(2000);
|
||||
//plot.getAxis(Plot.AxisId.Z).setRange(2.0, 3.0);
|
||||
plot.getAxis(Plot.AxisId.X).setRange(40, 60);
|
||||
plot.getAxis(Plot.AxisId.Y).setRange(400, 600);
|
||||
Thread.sleep(5000);
|
||||
plot.getAxis(Plot.AxisId.X).setAutoRange();
|
||||
plot.getAxis(Plot.AxisId.Y).setAutoRange();
|
||||
//plot.getAxis(Plot.AxisId.Z).setAutoRange();
|
||||
|
||||
Thread.sleep(5000);
|
||||
//plot.removeSeries(data);
|
||||
plot.clear();
|
||||
*/
|
||||
Thread.sleep(360000);
|
||||
|
||||
}
|
||||
|
||||
static Runnable runnable = new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long start = System.currentTimeMillis();
|
||||
double[] xyz;
|
||||
//while ((xyz = generator.getNewPoint()) != null) {
|
||||
// data.appendData(xyz[0], xyz[1], xyz[2]);
|
||||
|
||||
for (double y = startY; y <= startY + stepsY * stepSizeY; y += stepSizeY) {
|
||||
for (double x = startX; x <= startX + stepsX * stepSizeX; x += stepSizeX) {
|
||||
data.appendData(x, y, generator.generate(x, y) + 2);
|
||||
|
||||
try {
|
||||
Thread.sleep(sleepTime);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("------" + (System.currentTimeMillis() - start));
|
||||
// }
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
import org.jzy3d.analysis.AbstractAnalysis;
|
||||
import org.jzy3d.analysis.AnalysisLauncher;
|
||||
import org.jzy3d.chart.factories.AWTChartComponentFactory;
|
||||
import org.jzy3d.chart.Settings;
|
||||
import org.jzy3d.colors.Color;
|
||||
import org.jzy3d.colors.ColorMapper;
|
||||
import org.jzy3d.colors.colormaps.ColorMapRainbow;
|
||||
import org.jzy3d.maths.Range;
|
||||
import org.jzy3d.plot3d.builder.Builder;
|
||||
import org.jzy3d.plot3d.builder.Mapper;
|
||||
import org.jzy3d.plot3d.builder.concrete.OrthonormalGrid;
|
||||
import org.jzy3d.plot3d.primitives.Shape;
|
||||
import org.jzy3d.plot3d.rendering.canvas.Quality;
|
||||
|
||||
public class TestJZY extends AbstractAnalysis {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
AnalysisLauncher.open(new TestJZY());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
// Define a function to plot
|
||||
Mapper mapper = new Mapper() {
|
||||
public double f(double x, double y) {
|
||||
return x * Math.sin(x * y);
|
||||
}
|
||||
};
|
||||
|
||||
// Define range and precision for the function to plot
|
||||
Range range = new Range(-3, 3);
|
||||
int steps = 100;
|
||||
|
||||
// Create the object to represent the function over the given range.
|
||||
final Shape surface = Builder.buildOrthonormal(new OrthonormalGrid(range, steps, range, steps), mapper);
|
||||
surface.setColorMapper(new ColorMapper(new ColorMapRainbow(), surface.getBounds().getZmin(), surface.getBounds().getZmax(), new Color(1, 1, 1, .5f)));
|
||||
surface.setFaceDisplayed(true);
|
||||
surface.setWireframeDisplayed(false);
|
||||
|
||||
// Create a chart
|
||||
chart = AWTChartComponentFactory.chart(Quality.Advanced, getCanvasType());
|
||||
chart.getScene().getGraph().add(surface);
|
||||
}
|
||||
}
|
||||
@@ -1,316 +1,323 @@
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but without any
|
||||
* warranty; without even the implied warranty of merchantability or fitness for
|
||||
* a particular purpose. See the GNU Lesser General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xy;
|
||||
|
||||
import ch.psi.plot.LinePlot;
|
||||
import ch.psi.plot.LinePlotSeries;
|
||||
import ch.psi.plot.utils.SwingUtils;
|
||||
import ch.psi.plot.xy.generator.Sinus;
|
||||
import ch.psi.plot.xy.generator.XYGenerator;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.LineNumberReader;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.JFrame;
|
||||
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.ui.RefineryUtilities;
|
||||
import javax.swing.JPanel;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.psi.plot.xy.LinePlot;
|
||||
import ch.psi.plot.xy.generator.Sinus;
|
||||
import ch.psi.plot.xy.generator.XYGenerator;
|
||||
|
||||
/**
|
||||
* Test for the LinePlot class
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class LinePlotTest {
|
||||
|
||||
private final File file = new File("../ch.psi.sls.xasec/testfiles/text/beamCurrent.txt");
|
||||
private final long timeToClose = 7200000; // 2 hours
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
private final File file = new File("../ch.psi.sls.xasec/testfiles/text/beamCurrent.txt");
|
||||
private final long timeToClose = 7200000; // 2 hours
|
||||
static LinePlot linePlot;
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test LinePlot rendering point by point (getting data from a generator)
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testLinePlotGeneratorPerformance() throws IOException, InterruptedException {
|
||||
|
||||
for(int i=0;i<10;i++){
|
||||
LinePlot linePlot = new LinePlot("Title ", getDataFromGenerator(1)) ;
|
||||
// linePlot.plot();
|
||||
|
||||
JFrame frame = new JFrame();
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setContentPane(linePlot.getChartPanel());
|
||||
frame.pack();
|
||||
RefineryUtilities.centerFrameOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
Thread.sleep(timeToClose);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test LinePlot rendering point by point (getting data from a generator)
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testLinePlotAllDataAvailable() throws IOException, InterruptedException {
|
||||
|
||||
for(int i=0;i<1;i++){
|
||||
XYSeriesCollectionP d = loadDataFromGenerator();
|
||||
LinePlot linePlot = new LinePlot("Title ", d) ;
|
||||
|
||||
ChartPanel chartPanel = linePlot.getChartPanel();
|
||||
JFrame frame = new JFrame();
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setContentPane(chartPanel);
|
||||
frame.pack();
|
||||
RefineryUtilities.centerFrameOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
frame.setContentPane(chartPanel);
|
||||
}
|
||||
|
||||
Thread.sleep(timeToClose);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test LinePlot rendering point by point (getting data from a generator)
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testLinePlotGenerator() throws IOException, InterruptedException {
|
||||
|
||||
for(int i=0;i<1;i++){
|
||||
LinePlot linePlot = new LinePlot("Title ", getDataFromGenerator(1)) ;
|
||||
// linePlot.plot();
|
||||
JFrame frame = new JFrame();
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setContentPane(linePlot.getChartPanel());
|
||||
frame.pack();
|
||||
RefineryUtilities.centerFrameOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
Thread.sleep(timeToClose);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLinePlotGeneratorOne() throws IOException, InterruptedException {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
linePlot = new ch.psi.plot.jfree.LinePlot();
|
||||
//linePlot = new ch.psi.plot.jlchart.LinePlot() ;
|
||||
linePlot.setTitle("Title");
|
||||
}
|
||||
|
||||
XYSeriesCollectionP data = new XYSeriesCollectionP();
|
||||
XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 1000, false);
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
generator.reset();
|
||||
/**
|
||||
* Test LinePlot rendering point by point (getting data from a generator)
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testLinePlotGeneratorPerformance() throws IOException, InterruptedException {
|
||||
linePlot.clear();
|
||||
//for(int i=0;i<10;i++)
|
||||
{
|
||||
LinePlotSeries[] series = getDataFromGenerator(0, linePlot);
|
||||
//linePlot.addSeries(series);
|
||||
|
||||
String seriesName = "test";
|
||||
XYSeriesP serie = new XYSeriesP(seriesName);
|
||||
data.addSeries(serie);
|
||||
//addDataFromGenerator(0, 10, 1000, linePlot);
|
||||
JFrame frame = new JFrame();
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setContentPane(linePlot.getChartPanel());
|
||||
frame.pack();
|
||||
SwingUtils.centerOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
double[] xy;
|
||||
while ((xy = generator.getNewPoint()) != null) {
|
||||
serie.add(xy[0], xy[1]); // Add t to the y value to see the plotted line
|
||||
}
|
||||
Thread.sleep(timeToClose);
|
||||
}
|
||||
|
||||
LinePlot linePlot = new LinePlot("Title ", data);
|
||||
JFrame frame = new JFrame();
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setContentPane(linePlot.getChartPanel());
|
||||
frame.pack();
|
||||
RefineryUtilities.centerFrameOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
/**
|
||||
* Test LinePlot rendering point by point (getting data from a generator)
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testLinePlotAllDataAvailable() throws IOException, InterruptedException {
|
||||
linePlot.clear();
|
||||
for (int i = 0; i < 1; i++) {
|
||||
LinePlotSeries[] d = loadDataFromGenerator(linePlot);
|
||||
//linePlot.addSeries(d);
|
||||
JPanel chartPanel = linePlot.getChartPanel();
|
||||
JFrame frame = new JFrame();
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setContentPane(chartPanel);
|
||||
frame.pack();
|
||||
SwingUtils.centerOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
frame.setContentPane(chartPanel);
|
||||
}
|
||||
|
||||
Thread.sleep(timeToClose);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test LinePlot rendering point by point (getting data from a generator)
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testLinePlotGenerator65536() throws IOException, InterruptedException {
|
||||
|
||||
LinePlot linePlot = new LinePlot("Title ", loadDataFromGenerator65536(0)) ;
|
||||
Thread.sleep(timeToClose);
|
||||
}
|
||||
|
||||
JFrame frame = new JFrame();
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setContentPane(linePlot.getChartPanel());
|
||||
frame.pack();
|
||||
RefineryUtilities.centerFrameOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
|
||||
int cnt = 1;
|
||||
while(true){
|
||||
Thread.sleep(5000);
|
||||
linePlot.getData().removeAllSeries();
|
||||
linePlot.getData().addSeries(loadDataFromGenerator65536(cnt).getSeries(0));
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test LinePlot rendering point by point (getting data from a file)
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testLinePlotFile() throws IOException, InterruptedException {
|
||||
LinePlot linePlot = new LinePlot("Title ", getDataFromFile()) ;
|
||||
// linePlot.plot();
|
||||
JFrame frame = new JFrame();
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setContentPane(linePlot.getChartPanel());
|
||||
frame.pack();
|
||||
RefineryUtilities.centerFrameOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
|
||||
Thread.sleep(timeToClose);
|
||||
}
|
||||
/**
|
||||
* Test LinePlot rendering point by point (getting data from a generator)
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testLinePlotGenerator() throws IOException, InterruptedException {
|
||||
linePlot.clear();
|
||||
for (int i = 0; i < 1; i++) {
|
||||
linePlot.addSeries(getDataFromGenerator(1, linePlot));
|
||||
JFrame frame = new JFrame();
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setContentPane(linePlot.getChartPanel());
|
||||
frame.pack();
|
||||
SwingUtils.centerOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get data from file
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private XYSeriesCollectionP getDataFromFile() throws IOException{
|
||||
String seriesName = "File Data";
|
||||
XYSeriesCollectionP data = new XYSeriesCollectionP();
|
||||
LineNumberReader in = new LineNumberReader(new FileReader(file));
|
||||
|
||||
// Update data
|
||||
data.addSeries(new XYSeriesP(seriesName));
|
||||
|
||||
// Read data
|
||||
String s;
|
||||
while ((s = in.readLine()) != null) {
|
||||
double x = (double) in.getLineNumber();
|
||||
double y = Double.parseDouble(s);
|
||||
|
||||
data.getSeries(seriesName).add(x, y);
|
||||
}
|
||||
in.close();
|
||||
return(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data from a generator
|
||||
* @param sleeptime Time between data points
|
||||
* @return
|
||||
*/
|
||||
private XYSeriesCollectionP getDataFromGenerator(final long sleeptime){
|
||||
final String seriesBaseName = "Generator Data";
|
||||
final XYSeriesCollectionP data = new XYSeriesCollectionP();
|
||||
final XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 1000, false);
|
||||
|
||||
|
||||
|
||||
Thread t = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for(int t=0;t<1000;t++){
|
||||
// Reset generator
|
||||
generator.reset();
|
||||
|
||||
String seriesName = seriesBaseName+" - "+t;
|
||||
XYSeriesP serie = new XYSeriesP(seriesName);
|
||||
data.addSeries(serie);
|
||||
|
||||
double[] xy;
|
||||
while((xy=generator.getNewPoint())!=null){
|
||||
serie.add(xy[0], xy[1]+t); // Add t to the y value to see the plotted line
|
||||
// data.getSeries(seriesName).add(xy[0], xy[1]+t,false); // No notification send - Update of GUI will be performed periodically
|
||||
|
||||
try {
|
||||
Thread.sleep(sleeptime);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("DONE");
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private XYSeriesCollectionP loadDataFromGenerator() {
|
||||
final String seriesBaseName = "Generator Data";
|
||||
final XYSeriesCollectionP data = new XYSeriesCollectionP();
|
||||
final XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 1000, false);
|
||||
Thread.sleep(timeToClose);
|
||||
}
|
||||
|
||||
for (int t = 0; t < 1000; t++) {
|
||||
// Reset generator
|
||||
generator.reset();
|
||||
@Test
|
||||
public void testLinePlotGeneratorOne() throws IOException, InterruptedException {
|
||||
|
||||
String seriesName = seriesBaseName + " - " + t;
|
||||
final XYSeriesP f = new XYSeriesP(seriesName);
|
||||
data.addSeries(f);
|
||||
XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 1000, false);
|
||||
|
||||
double[] xy;
|
||||
while ((xy = generator.getNewPoint()) != null) {
|
||||
// f.add(xy[0], xy[1] + t); // Add t to the y value to see the plotted line
|
||||
f.add(xy[0], xy[1] + t, false); // No notification send - use this if all data is available before plotting
|
||||
}
|
||||
}
|
||||
generator.reset();
|
||||
|
||||
System.out.println("DONE");
|
||||
String seriesName = "test";
|
||||
LinePlotSeries series = new LinePlotSeries(seriesName);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private XYSeriesCollectionP loadDataFromGenerator65536(int count) {
|
||||
final String seriesBaseName = "Generator Data";
|
||||
final XYSeriesCollectionP data = new XYSeriesCollectionP();
|
||||
|
||||
final XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 65536, false);
|
||||
|
||||
String seriesName = seriesBaseName;
|
||||
final XYSeriesP f = new XYSeriesP(seriesName);
|
||||
data.addSeries(f);
|
||||
double[] xy;
|
||||
while ((xy = generator.getNewPoint()) != null) {
|
||||
series.appendData(xy[0], xy[1]); // Add t to the y value to see the plotted line
|
||||
}
|
||||
|
||||
double[] xy;
|
||||
while ((xy = generator.getNewPoint()) != null) {
|
||||
f.add(xy[0], xy[1]+count, false); // No notification send - use this if all data is available before plotting
|
||||
}
|
||||
linePlot.clear();
|
||||
linePlot.addSeries(series);
|
||||
|
||||
System.out.println("DONE");
|
||||
JFrame frame = new JFrame();
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setContentPane(linePlot.getChartPanel());
|
||||
frame.pack();
|
||||
SwingUtils.centerOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
|
||||
Thread.sleep(timeToClose);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test LinePlot rendering point by point (getting data from a generator)
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testLinePlotGenerator65536() throws IOException, InterruptedException {
|
||||
linePlot.clear();
|
||||
linePlot.addSeries(loadDataFromGenerator65536(0, linePlot));
|
||||
|
||||
JFrame frame = new JFrame();
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setContentPane(linePlot.getChartPanel());
|
||||
frame.pack();
|
||||
SwingUtils.centerOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
|
||||
int cnt = 1;
|
||||
while (true) {
|
||||
Thread.sleep(5000);
|
||||
linePlot.clear();
|
||||
linePlot.addSeries(loadDataFromGenerator65536(cnt, linePlot));
|
||||
cnt++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test LinePlot rendering point by point (getting data from a file)
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testLinePlotFile() throws IOException, InterruptedException {
|
||||
linePlot.clear();
|
||||
linePlot.addSeries(getDataFromFile());
|
||||
JFrame frame = new JFrame();
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setContentPane(linePlot.getChartPanel());
|
||||
frame.pack();
|
||||
SwingUtils.centerOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
|
||||
Thread.sleep(timeToClose);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data from file
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private LinePlotSeries getDataFromFile() throws IOException {
|
||||
String seriesName = "File Data";
|
||||
LineNumberReader in = new LineNumberReader(new FileReader(file));
|
||||
|
||||
// Update data
|
||||
LinePlotSeries series = new LinePlotSeries(seriesName);
|
||||
|
||||
// Read data
|
||||
String s;
|
||||
while ((s = in.readLine()) != null) {
|
||||
double x = (double) in.getLineNumber();
|
||||
double y = Double.parseDouble(s);
|
||||
|
||||
series.appendData(x, y);
|
||||
}
|
||||
in.close();
|
||||
return (series);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data from a generator
|
||||
*
|
||||
* @param sleeptime Time between data points
|
||||
* @return
|
||||
*/
|
||||
private LinePlotSeries[] getDataFromGenerator(final long sleeptime, final LinePlot plot) {
|
||||
final String seriesBaseName = "Generator Data";
|
||||
final LinePlotSeries[] series = new LinePlotSeries[100];
|
||||
for (int i = 0; i < series.length; i++) {
|
||||
String seriesName = seriesBaseName + " - " + i;
|
||||
series[i] = new LinePlotSeries(seriesName);
|
||||
}
|
||||
plot.addSeries(series);
|
||||
final XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 1000, false);
|
||||
|
||||
Thread t = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i = 0; i < series.length; i++) {
|
||||
// Reset generator
|
||||
generator.reset();
|
||||
double[] xy;
|
||||
while ((xy = generator.getNewPoint()) != null) {
|
||||
series[i].appendData(xy[0], xy[1] + i); // Add t to the y value to see the plotted line
|
||||
|
||||
try {
|
||||
Thread.sleep(sleeptime);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("DONE: " + (System.currentTimeMillis() - start));
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
private LinePlotSeries[] loadDataFromGenerator(final LinePlot plot) {
|
||||
final String seriesBaseName = "Generator Data";
|
||||
final LinePlotSeries[] series = new LinePlotSeries[10];
|
||||
for (int i = 0; i < series.length; i++) {
|
||||
String seriesName = seriesBaseName + " - " + i;
|
||||
series[i] = new LinePlotSeries(seriesName);
|
||||
}
|
||||
plot.addSeries(series);
|
||||
|
||||
final XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 1000, false);
|
||||
|
||||
plot.setUpdatesEnabled(false);
|
||||
for (int t = 0; t < 1000; t++) {
|
||||
// Reset generator
|
||||
generator.reset();
|
||||
double[] xy;
|
||||
while ((xy = generator.getNewPoint()) != null) {
|
||||
series[t].appendData(xy[0], xy[1] + t); // Add t to the y value to see the plotted line
|
||||
}
|
||||
plot.requestSeriesUpdate(series[t]);
|
||||
}
|
||||
plot.setUpdatesEnabled(true);
|
||||
|
||||
System.out.println("DONE");
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
private LinePlotSeries loadDataFromGenerator65536(int count, final LinePlot plot) {
|
||||
final String seriesBaseName = "Generator Data";
|
||||
LinePlotSeries series = new LinePlotSeries(seriesBaseName);
|
||||
|
||||
final XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 65536, false);
|
||||
|
||||
plot.setUpdatesEnabled(false);
|
||||
double[] xy;
|
||||
plot.setUpdatesEnabled(false);
|
||||
while ((xy = generator.getNewPoint()) != null) {
|
||||
series.appendData(xy[0], xy[1] + count); // No notification send - use this if all data is available before plotting
|
||||
}
|
||||
plot.setUpdatesEnabled(true);
|
||||
plot.update(true);
|
||||
System.out.println("DONE");
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,212 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.WindowConstants;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
//import ch.psi.sls.xasec.data.DataSet;
|
||||
//import ch.psi.sls.xasec.data.DataSetUtils;
|
||||
import ch.psi.plot.xyz.MatrixPlot;
|
||||
import ch.psi.plot.xyz.MatrixPlotData;
|
||||
import ch.psi.plot.xyz.generator.DataGenerator;
|
||||
import ch.psi.plot.xyz.generator.Sinus2D;
|
||||
import ch.psi.plot.xyz.generator.XYZGenerator;
|
||||
|
||||
|
||||
/**
|
||||
* Test case for MatrixPlot class
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class MatrixPlot2Test {
|
||||
|
||||
// Get Logger
|
||||
private static final Logger logger = Logger.getLogger(MatrixPlot2Test.class.getName());
|
||||
|
||||
private final long timeToClose = 7200000; // 2 hours
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test case for MatrixPlot (getting data from a generator)
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testMatrixPlot() throws InterruptedException {
|
||||
double startX = 0;
|
||||
double stepSizeX = 1;
|
||||
int stepsX = 50;
|
||||
double startY = 0;
|
||||
double stepSizeY = 1;
|
||||
int stepsY = 50;
|
||||
|
||||
final DynamicXYZDatasetList data = new DynamicXYZDatasetList();
|
||||
|
||||
final XYZGenerator generator = new XYZGenerator(new Sinus2D(2,4), startX, stepSizeX, stepsX, startY, stepSizeY, stepsY, false);
|
||||
final MatrixPlot2 plot = new MatrixPlot2("Matrix Plot Test", data);
|
||||
|
||||
final JFrame frame = new JFrame("");
|
||||
frame.setContentPane(plot.getChartPanel());
|
||||
frame.pack();
|
||||
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
|
||||
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
Thread t = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// for(int t=0;t<200;t++){
|
||||
// // Reset generator
|
||||
// generator.reset();
|
||||
|
||||
// int count = 0;
|
||||
double[] xyz;
|
||||
while((xyz=generator.getNewPoint())!=null){
|
||||
data.addData(xyz[0], xyz[1], xyz[2]);
|
||||
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
|
||||
// or set matrixChart.setNotify(false); in MatrixPlot Line 431 ...
|
||||
// if(count==10){
|
||||
// plot.update();
|
||||
// count=0;
|
||||
// }
|
||||
// else{
|
||||
// count++;
|
||||
// }
|
||||
}
|
||||
System.out.println("Generator done");
|
||||
|
||||
// }
|
||||
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
|
||||
Thread.sleep(timeToClose);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlotConverterGeneratorMatrixPlot() throws InterruptedException {
|
||||
DataGenerator generator = new DataGenerator(new Sinus2D(2,4));
|
||||
generator.generateData();
|
||||
|
||||
MatrixPlot plot = new MatrixPlot("Matrix Plot Test", generator.getData());
|
||||
|
||||
// converter.generateData();
|
||||
//// Thread t = new Thread(converter);
|
||||
//// t.start();
|
||||
|
||||
final JFrame frame = new JFrame("");
|
||||
frame.setContentPane(plot.getChartPanel());
|
||||
frame.pack();
|
||||
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
|
||||
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Thread.sleep(timeToClose);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlotMatrixPlot() throws InterruptedException {
|
||||
MatrixPlotData data = new MatrixPlotData(-10, -1, 10, -10, -1, 10);
|
||||
|
||||
Random r = new Random();
|
||||
|
||||
for (double i = data.getMinX(); i <= data.getMaxX(); i++) {
|
||||
for (double t = data.getMinY(); t <= data.getMaxY(); t++) {
|
||||
data.addData(i, t, r.nextDouble() * 10);
|
||||
}
|
||||
}
|
||||
|
||||
MatrixPlot plot = new MatrixPlot("Matrix Plot Test", data);
|
||||
final JFrame frame = new JFrame("");
|
||||
frame.setContentPane(plot.getChartPanel());
|
||||
frame.pack();
|
||||
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
|
||||
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
Thread.sleep(timeToClose);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPlotMatrixPlot2() throws InterruptedException {
|
||||
MatrixPlotData data = new MatrixPlotData(-11.5, -11.0, 6, -10.5, -10.0, 6);
|
||||
|
||||
Random r = new Random();
|
||||
|
||||
for (double i = data.getMinX(); i <= data.getMaxX(); i=i+0.1) {
|
||||
for (double t = data.getMinY(); t <= data.getMaxY(); t=t+0.1) {
|
||||
logger.info("Add data: "+i+" "+t);
|
||||
if(t==data.getMinY()){
|
||||
continue;
|
||||
}
|
||||
data.addData(i, t, r.nextDouble() * 10);
|
||||
}
|
||||
}
|
||||
|
||||
MatrixPlot plot = new MatrixPlot("Matrix Plot Test", data);
|
||||
final JFrame frame = new JFrame("");
|
||||
frame.setContentPane(plot.getChartPanel());
|
||||
frame.pack();
|
||||
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
|
||||
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
Thread.sleep(timeToClose);
|
||||
}
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.WindowConstants;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
//import ch.psi.sls.xasec.data.DataSet;
|
||||
//import ch.psi.sls.xasec.data.DataSetUtils;
|
||||
import ch.psi.plot.xyz.MatrixPlot;
|
||||
import ch.psi.plot.xyz.MatrixPlotData;
|
||||
import ch.psi.plot.xyz.generator.DataGenerator;
|
||||
import ch.psi.plot.xyz.generator.Sinus2D;
|
||||
import ch.psi.plot.xyz.generator.XYZGenerator;
|
||||
|
||||
|
||||
/**
|
||||
* Test case for MatrixPlot class
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class MatrixPlotTest {
|
||||
|
||||
// Get Logger
|
||||
private static final Logger logger = Logger.getLogger(MatrixPlotTest.class.getName());
|
||||
|
||||
private final long timeToClose = 7200000; // 2 hours
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test case for MatrixPlot (getting data from a generator)
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
@Test
|
||||
public void testMatrixPlot() throws InterruptedException {
|
||||
double startX = 10;
|
||||
double stepSizeX = 1;
|
||||
int stepsX = 1000;
|
||||
double startY = 10;
|
||||
double stepSizeY = 1;
|
||||
int stepsY = 1000;
|
||||
|
||||
final MatrixPlotData data = new MatrixPlotData(startX, startX+stepsX*stepSizeX, stepsX, startY, startY+stepsY*stepSizeY, stepsY);
|
||||
|
||||
final XYZGenerator generator = new XYZGenerator(new Sinus2D(2,4), startX, stepSizeX, stepsX, startY, stepSizeY, stepsY, false);
|
||||
final MatrixPlot plot = new MatrixPlot("Matrix Plot Test", data);
|
||||
|
||||
final JFrame frame = new JFrame("");
|
||||
frame.setContentPane(plot.getChartPanel());
|
||||
frame.pack();
|
||||
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
|
||||
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
Thread t = new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// for(int t=0;t<200;t++){
|
||||
// // Reset generator
|
||||
// generator.reset();
|
||||
|
||||
// int count = 0;
|
||||
double[] xyz;
|
||||
while((xyz=generator.getNewPoint())!=null){
|
||||
data.addData(xyz[0], xyz[1], xyz[2]);
|
||||
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
|
||||
// or set matrixChart.setNotify(false); in MatrixPlot Line 431 ...
|
||||
// if(count==10){
|
||||
// plot.update();
|
||||
// count=0;
|
||||
// }
|
||||
// else{
|
||||
// count++;
|
||||
// }
|
||||
}
|
||||
|
||||
// }
|
||||
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
|
||||
Thread.sleep(timeToClose);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlotConverterGeneratorMatrixPlot() throws InterruptedException {
|
||||
DataGenerator generator = new DataGenerator(new Sinus2D(2,4));
|
||||
generator.generateData();
|
||||
|
||||
MatrixPlot plot = new MatrixPlot("Matrix Plot Test", generator.getData());
|
||||
|
||||
// converter.generateData();
|
||||
//// Thread t = new Thread(converter);
|
||||
//// t.start();
|
||||
|
||||
final JFrame frame = new JFrame("");
|
||||
frame.setContentPane(plot.getChartPanel());
|
||||
frame.pack();
|
||||
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
|
||||
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Thread.sleep(timeToClose);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlotMatrixPlot() throws InterruptedException {
|
||||
MatrixPlotData data = new MatrixPlotData(-10, -1, 10, -10, -1, 10);
|
||||
|
||||
Random r = new Random();
|
||||
|
||||
for (double i = data.getMinX(); i <= data.getMaxX(); i++) {
|
||||
for (double t = data.getMinY(); t <= data.getMaxY(); t++) {
|
||||
data.addData(i, t, r.nextDouble() * 10);
|
||||
}
|
||||
}
|
||||
|
||||
MatrixPlot plot = new MatrixPlot("Matrix Plot Test", data);
|
||||
final JFrame frame = new JFrame("");
|
||||
frame.setContentPane(plot.getChartPanel());
|
||||
frame.pack();
|
||||
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
|
||||
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
Thread.sleep(timeToClose);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPlotMatrixPlot2() throws InterruptedException {
|
||||
MatrixPlotData data = new MatrixPlotData(-11.5, -11.0, 6, -10.5, -10.0, 6);
|
||||
|
||||
Random r = new Random();
|
||||
|
||||
for (double i = data.getMinX(); i <= data.getMaxX(); i=i+0.1) {
|
||||
for (double t = data.getMinY(); t <= data.getMaxY(); t=t+0.1) {
|
||||
logger.info("Add data: "+i+" "+t);
|
||||
if(t==data.getMinY()){
|
||||
continue;
|
||||
}
|
||||
data.addData(i, t, r.nextDouble() * 10);
|
||||
}
|
||||
}
|
||||
|
||||
MatrixPlot plot = new MatrixPlot("Matrix Plot Test", data);
|
||||
final JFrame frame = new JFrame("");
|
||||
frame.setContentPane(plot.getChartPanel());
|
||||
frame.pack();
|
||||
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
|
||||
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
Thread.sleep(timeToClose);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package ch.psi.plot.xyz.generator;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import ch.psi.plot.xy.generator.Noise;
|
||||
import ch.psi.plot.xyz.MatrixPlotData;
|
||||
import ch.psi.plot.MatrixPlotSeries;
|
||||
|
||||
/**
|
||||
* Converter object converting a file into PixelPlot data
|
||||
@@ -12,7 +12,7 @@ public class DataGenerator implements Runnable {
|
||||
|
||||
private static Logger logger = Logger.getLogger(DataGenerator.class.getName());
|
||||
|
||||
private final MatrixPlotData data;
|
||||
private final MatrixPlotSeries data;
|
||||
private XYZGeneratorFunction function;
|
||||
|
||||
double xMin = 0;
|
||||
@@ -38,7 +38,7 @@ public class DataGenerator implements Runnable {
|
||||
public DataGenerator(XYZGeneratorFunction function, boolean noise, boolean metaDataAvailable){
|
||||
this.function = function;
|
||||
|
||||
data = new MatrixPlotData(xMin,xMax,xNStep,yMin,yMax,yNStep);
|
||||
data = new MatrixPlotSeries(null, xMin,xMax,xNStep,yMin,yMax,yNStep);
|
||||
|
||||
if(noise){
|
||||
noiseFunctionX = new Noise(data.getBinWidthX());
|
||||
@@ -70,7 +70,7 @@ public class DataGenerator implements Runnable {
|
||||
}
|
||||
|
||||
logger.fine("x: "+x+" y: "+y+" z: "+function.generate(x, y));
|
||||
data.addData(x, y, function.generate(x, y));
|
||||
data.appendData(x, y, function.generate(x, y));
|
||||
// try {
|
||||
// Thread.sleep(1);
|
||||
// } catch (InterruptedException e1) {
|
||||
@@ -80,7 +80,7 @@ public class DataGenerator implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
public MatrixPlotData getData() {
|
||||
public MatrixPlotSeries getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,12 +43,12 @@ public class XYZGenerator {
|
||||
this.startX = startX;
|
||||
this.stepSizeX = stepSizeX;
|
||||
this.stepsX = stepsX;
|
||||
this.currentStepX = startX;
|
||||
this.currentStepX = 0;
|
||||
|
||||
this.startY = startY;
|
||||
this.stepSizeY = stepSizeY;
|
||||
this.stepsY = stepsY;
|
||||
this.currentStepY = startY;
|
||||
this.currentStepY = 0;
|
||||
|
||||
if(noise){
|
||||
this.noiseGeneratorX = new Noise(stepSizeX);
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
import java.awt.Color;
|
||||
import org.jfree.chart.plot.Marker;
|
||||
import org.jfree.chart.plot.ValueMarker;
|
||||
import org.jfree.data.xy.XYSeries;
|
||||
import org.jfree.data.xy.XYSeriesCollection;
|
||||
import org.jfree.ui.Layer;
|
||||
import org.jfree.ui.RectangleAnchor;
|
||||
import org.jfree.ui.TextAnchor;
|
||||
|
||||
import ch.psi.plot.util.PluginExecutionException;
|
||||
import ch.psi.plot.xy.LinePlot;
|
||||
import ch.psi.plot.xy.LinePlotData;
|
||||
import ch.psi.plot.xy.plugable.PlugableUtilXY;
|
||||
|
||||
public class Average implements PlugableUtilXY{
|
||||
|
||||
private final static String averageLabel = "average";
|
||||
|
||||
@Override
|
||||
public void execute(LinePlot lineplot) throws PluginExecutionException {
|
||||
double average = calculateAverage(lineplot.getData());
|
||||
// add a labelled marker for the average
|
||||
final Marker start = new ValueMarker(average);
|
||||
start.setPaint(Color.blue);
|
||||
start.setLabel(averageLabel);
|
||||
start.setLabelAnchor(RectangleAnchor.BOTTOM_RIGHT);
|
||||
start.setLabelTextAnchor(TextAnchor.TOP_RIGHT);
|
||||
|
||||
if(lineplot.getChartPanel().getChart().getXYPlot().getRangeMarkers(Layer.FOREGROUND) != null){
|
||||
//remove the previous marker
|
||||
Marker previousAverageMarker = null;
|
||||
for (Object o: lineplot.getChartPanel().getChart().getXYPlot().getRangeMarkers(Layer.FOREGROUND)){
|
||||
if(o instanceof Marker){
|
||||
if( ((Marker) o).getLabel().equals(averageLabel) ){
|
||||
previousAverageMarker = (Marker) o;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lineplot.getChartPanel().getChart().getXYPlot().removeRangeMarker(previousAverageMarker);
|
||||
}
|
||||
|
||||
lineplot.getChartPanel().getChart().getXYPlot().addRangeMarker(start);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate average of all graphs
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
private double calculateAverage(LinePlotData data){
|
||||
XYSeriesCollection inputSeriesCollection = (XYSeriesCollection) data.getData();
|
||||
|
||||
double average = 0.0;
|
||||
int numberOfValues = 0;
|
||||
|
||||
for (Object xySeries : inputSeriesCollection.getSeries()) {
|
||||
for (int i = 1; i < inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getItemCount(); i++) {
|
||||
double yi = inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getDataItem(i).getYValue();
|
||||
average += yi;
|
||||
}
|
||||
numberOfValues += inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getItemCount();
|
||||
}
|
||||
|
||||
return average/numberOfValues;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
import org.jfree.ui.Drawable;
|
||||
|
||||
/**
|
||||
* Class that draws an Red cross as annotation.
|
||||
*
|
||||
* This is an implementation of the {@link Drawable} interface, to illustrate the use of the
|
||||
* {@link org.jfree.chart.annotations.XYDrawableAnnotation} class.
|
||||
*/
|
||||
public class CrossDrawer implements Drawable {
|
||||
|
||||
private Color color; //= Color.orange;
|
||||
private float strokeWidth = 1;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public CrossDrawer(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws cross
|
||||
* @param g2 the graphics device.
|
||||
* @param area the area in which to draw.
|
||||
*/
|
||||
public void draw(Graphics2D g2, Rectangle2D area) {
|
||||
|
||||
// Draw red cross
|
||||
g2.setPaint(color);
|
||||
g2.setStroke(new BasicStroke(strokeWidth));
|
||||
Line2D line1 = new Line2D.Double(area.getCenterX(), area.getMinY(), area.getCenterX(), area.getMaxY());
|
||||
Line2D line2 = new Line2D.Double(area.getMinX(), area.getCenterY(), area.getMaxX(), area.getCenterY());
|
||||
g2.draw(line1);
|
||||
g2.draw(line2);
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
import org.jfree.data.xy.XYSeries;
|
||||
import org.jfree.data.xy.XYSeriesCollection;
|
||||
|
||||
import ch.psi.plot.util.XYPoint;
|
||||
import ch.psi.plot.xy.LinePlot;
|
||||
import ch.psi.plot.xy.LinePlotData;
|
||||
|
||||
|
||||
public class Derivatives implements PlugableUtilXY{
|
||||
|
||||
/**
|
||||
* Calculate derivative (first and/or second order) of a given function.
|
||||
* derivative is based upon 3 points.
|
||||
* @param data
|
||||
* @param inclusiveSecondOrder
|
||||
* @return
|
||||
*/
|
||||
public LinePlotData calculateDerivative(LinePlotData data){
|
||||
XYSeriesCollection inputSeriesCollection = (XYSeriesCollection) data.getData();
|
||||
|
||||
XYSeriesCollection derivativeCollection = new XYSeriesCollection();
|
||||
|
||||
for (Object xySeries : inputSeriesCollection.getSeries()) {
|
||||
XYSeries derivative = new XYSeries(((XYSeries) xySeries).getKey() + "'");
|
||||
XYSeries secondDerivative = new XYSeries(((XYSeries) xySeries).getKey() + "''");
|
||||
|
||||
for (int i = 1; i < inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getItemCount() - 1; i++) {
|
||||
double xi = inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getDataItem(i).getXValue();
|
||||
double xiplus1 = inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getDataItem(i+1).getXValue();
|
||||
double ximinus1 = inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getDataItem(i-1).getXValue();
|
||||
double h1 = xi - ximinus1;
|
||||
double h2 = xiplus1 - xi;
|
||||
//double yiminus2 = inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getDataItem(i-2).getYValue();
|
||||
double yiminus1 = inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getDataItem(i-1).getYValue();
|
||||
double yiplus1 = inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getDataItem(i+1).getYValue();
|
||||
//double yiplus2 = inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getDataItem(i+2).getYValue();
|
||||
//5 point stencil (order h^4)
|
||||
//double di = (-yiplus2 + 8*yiplus1 -8*yiminus1 + yiminus2)/12.0*h;
|
||||
//* Point estimation
|
||||
if(!(h1 + h2 == 0.0)){
|
||||
double di = (yiplus1 - yiminus1)/(h1 + h2);
|
||||
derivative.add(xi, di);
|
||||
}
|
||||
double yi = inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getDataItem(i).getYValue();
|
||||
if (!(h1 == 0.0 || h2 == 0.0)){
|
||||
double d2i = (h1*yiplus1 - (h1+h2)*yi + h2*yiminus1)/(h1*h2*(h1+h2));
|
||||
secondDerivative.add(xi, d2i);
|
||||
}
|
||||
}
|
||||
|
||||
derivativeCollection.addSeries(derivative);
|
||||
derivativeCollection.addSeries(secondDerivative);
|
||||
}
|
||||
LinePlotData d = new LinePlotData();
|
||||
d.setData(derivativeCollection);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
public XYPoint findMaximumDerivative(LinePlotData data){
|
||||
LinePlotData derivative = calculateDerivative(data);
|
||||
XYPoint minimum = Extrema.findExtrema(derivative, true).get(0);
|
||||
return minimum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(LinePlot lineplot) {
|
||||
LinePlotData d = null;
|
||||
d = calculateDerivative(lineplot.getData());
|
||||
LinePlot p = new LinePlot("Derivatives" , d);
|
||||
p.plot(false);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jfree.data.xy.XYSeries;
|
||||
import org.jfree.data.xy.XYSeriesCollection;
|
||||
|
||||
import ch.psi.plot.util.XYPoint;
|
||||
import ch.psi.plot.xy.LinePlotData;
|
||||
|
||||
|
||||
public class Extrema {
|
||||
|
||||
public static List<XYPoint> findExtrema(LinePlotData data, boolean returnMins){
|
||||
|
||||
ArrayList<XYPoint> mins = new ArrayList<XYPoint>();
|
||||
ArrayList<XYPoint> maxs = new ArrayList<XYPoint>();
|
||||
|
||||
XYSeriesCollection inputSeriesCollection = (XYSeriesCollection) data.getData();
|
||||
for (Object xySeries : inputSeriesCollection.getSeries()) {
|
||||
double max = Double.NEGATIVE_INFINITY;
|
||||
double min = Double.POSITIVE_INFINITY;
|
||||
double xmax = 0.0;
|
||||
double xmin = 0.0;
|
||||
for (int i = 0; i < inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getItemCount(); i++) {
|
||||
double xi = inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getDataItem(i).getXValue();
|
||||
double yi = inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getDataItem(i).getYValue();
|
||||
if(yi > max){
|
||||
max = yi;
|
||||
xmax = xi;
|
||||
}
|
||||
if(yi < min){
|
||||
min = yi;
|
||||
xmin = xi;
|
||||
}
|
||||
}
|
||||
XYPoint minPoint = new XYPoint(xmin, min);
|
||||
XYPoint maxPoint = new XYPoint(xmax, max);
|
||||
|
||||
mins.add(minPoint);
|
||||
maxs.add(maxPoint);
|
||||
}
|
||||
if (returnMins){
|
||||
return mins;
|
||||
}
|
||||
else{
|
||||
return maxs;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
|
||||
<Properties>
|
||||
<Property name="defaultCloseOperation" type="int" value="2"/>
|
||||
</Properties>
|
||||
<SyntheticProperties>
|
||||
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
|
||||
</SyntheticProperties>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="39" max="-2" attributes="0"/>
|
||||
<Component id="jPanel1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="47" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="36" max="-2" attributes="0"/>
|
||||
<Component id="graphOptionScrollPane" min="-2" pref="719" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="36" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jPanel1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="249" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="59" max="-2" attributes="0"/>
|
||||
<Component id="graphOptionScrollPane" min="-2" pref="182" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="59" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JScrollPane" name="graphOptionScrollPane">
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="jPanel1">
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="nameLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="123" max="-2" attributes="0"/>
|
||||
<Component id="colorLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="32" max="-2" attributes="0"/>
|
||||
<Component id="plotLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Component id="singleLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Component id="logLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Component id="rangeLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="55" max="-2" attributes="0"/>
|
||||
<Component id="minLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="73" max="-2" attributes="0"/>
|
||||
<Component id="maxLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="119" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="nameLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="logLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="singleLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="plotLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="colorLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="rangeLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="minLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="maxLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="nameLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Name"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="colorLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Color"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="plotLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Plot"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="singleLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Single"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="logLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Log"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="minLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Min"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="maxLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Max"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="rangeLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="range"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
@@ -1,112 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="nameLabel" min="-2" pref="103" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="58" max="-2" attributes="0"/>
|
||||
<Component id="colorLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="50" max="-2" attributes="0"/>
|
||||
<Component id="plotCheckBox" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="30" max="-2" attributes="0"/>
|
||||
<Component id="singleCheckBox" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="30" max="-2" attributes="0"/>
|
||||
<Component id="logCheckBox" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="28" max="-2" attributes="0"/>
|
||||
<Component id="individualRangeScaleCheckBox" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="49" max="-2" attributes="0"/>
|
||||
<Component id="minTextField" min="-2" pref="83" max="-2" attributes="0"/>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Component id="maxTextField" min="-2" pref="86" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="106" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="logCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="singleCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="plotCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="nameLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="103" alignment="0" groupAlignment="3" attributes="0">
|
||||
<Component id="minTextField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="maxTextField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
||||
<Component id="colorLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="individualRangeScaleCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="nameLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="name"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="colorLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value=" "/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="plotCheckBox">
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="plotCheckBoxActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="singleCheckBox">
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="singleCheckBoxActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="logCheckBox">
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="logCheckBoxActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="minTextField">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="min"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="minTextFieldActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="maxTextField">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="max"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="maxTextFieldActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="individualRangeScaleCheckBox">
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="individualRangeScaleCheckBoxActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
@@ -1,29 +0,0 @@
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
class ImagePanel extends JPanel
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private BufferedImage image;
|
||||
|
||||
public ImagePanel( BufferedImage image )
|
||||
{
|
||||
this.image = image;
|
||||
|
||||
setPreferredSize( new Dimension(image.getWidth(), image.getHeight()) );
|
||||
// repaint();
|
||||
// invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g)
|
||||
{
|
||||
if ( image != null )
|
||||
g.drawImage( image, 0, 0, this );
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
import org.jfree.data.xy.XYSeries;
|
||||
import org.jfree.data.xy.XYSeriesCollection;
|
||||
|
||||
import ch.psi.plot.xy.LinePlot;
|
||||
import ch.psi.plot.xy.LinePlotData;
|
||||
|
||||
|
||||
public class Integral implements PlugableUtilXY{
|
||||
|
||||
@Override
|
||||
public void execute(LinePlot lineplot) {
|
||||
LinePlotData d = null;
|
||||
d = calculateIntegral(lineplot.getData());
|
||||
if(d != null){
|
||||
LinePlot p = new LinePlot("Integral" , d);
|
||||
p.plot(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate Integral of function (trapezoidal)
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
private LinePlotData calculateIntegral(LinePlotData data){
|
||||
XYSeriesCollection inputSeriesCollection = (XYSeriesCollection) data.getData();
|
||||
|
||||
XYSeriesCollection integralCollection = new XYSeriesCollection();
|
||||
|
||||
for (Object xySeries : inputSeriesCollection.getSeries()) {
|
||||
XYSeries integral = new XYSeries("int " + ((XYSeries) xySeries).getKey());
|
||||
|
||||
double intXi = 0.0;
|
||||
for (int i = 1; i < inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getItemCount(); i++) {
|
||||
double xi = inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getDataItem(i).getXValue();
|
||||
double ximinus1 = inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getDataItem(i-1).getXValue();
|
||||
double h1 = xi - ximinus1;
|
||||
double yiminus1 = inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getDataItem(i-1).getYValue();
|
||||
double yi = inputSeriesCollection.getSeries(((XYSeries) xySeries).getKey()).getDataItem(i).getYValue();
|
||||
intXi += h1*(yi + yiminus1)/2.0;
|
||||
integral.add(xi, intXi);
|
||||
}
|
||||
|
||||
integralCollection.addSeries(integral);
|
||||
}
|
||||
|
||||
LinePlotData d = new LinePlotData();
|
||||
d.setData(integralCollection);
|
||||
return d;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,985 +0,0 @@
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Paint;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.WindowConstants;
|
||||
|
||||
import org.jfree.chart.ChartFactory;
|
||||
import org.jfree.chart.ChartMouseEvent;
|
||||
import org.jfree.chart.ChartMouseListener;
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.annotations.XYAnnotation;
|
||||
import org.jfree.chart.annotations.XYDrawableAnnotation;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.entity.StandardEntityCollection;
|
||||
import org.jfree.chart.labels.StandardXYToolTipGenerator;
|
||||
import org.jfree.chart.labels.XYToolTipGenerator;
|
||||
import org.jfree.chart.plot.IntervalMarker;
|
||||
import org.jfree.chart.plot.PlotOrientation;
|
||||
import org.jfree.chart.plot.ValueMarker;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
|
||||
import org.jfree.data.Range;
|
||||
import org.jfree.data.xy.XYDataset;
|
||||
import org.jfree.data.xy.XYSeries;
|
||||
import org.jfree.data.xy.XYSeriesCollection;
|
||||
import org.jfree.ui.Layer;
|
||||
import org.jfree.ui.RectangleInsets;
|
||||
import org.jfree.ui.RefineryUtilities;
|
||||
|
||||
import ch.psi.plot.plot.EventActionListener;
|
||||
import ch.psi.plot.plot.Plot;
|
||||
import ch.psi.plot.plot.util.CoordinateTransformer;
|
||||
import ch.psi.plot.plot.xy.GraphChooserFrame;
|
||||
import ch.psi.plot.plot.xy.Interval;
|
||||
import ch.psi.plot.plot.xy.Marker;
|
||||
import ch.psi.plot.plot.xyz.CrossDrawer;
|
||||
|
||||
|
||||
//Removed interfaces: AxisChangeListener
|
||||
public class LinePlot implements Plot, ChartMouseListener, MouseListener, MouseMotionListener, ActionListener {
|
||||
|
||||
private static Logger logger = Logger.getLogger(LinePlot.class.getName());
|
||||
|
||||
private List<EventActionListener> eventActionListener = new ArrayList<EventActionListener>();
|
||||
private List<PlugableUtil> plugableUtils;
|
||||
|
||||
private ChartPanel chartPanel;
|
||||
|
||||
private List<Marker> markers;
|
||||
|
||||
private boolean notification = true;
|
||||
|
||||
private boolean dragging;
|
||||
private boolean rescaleAxis = false;
|
||||
private XYPoint difference = new XYPoint(0.0,0.0);
|
||||
|
||||
//Defining Context Menu Label
|
||||
private static final String pauseMenuLabel = "Pause Conversion";
|
||||
private static final String continueMenuLabel = "Continue Conversion";
|
||||
private static final String clearAnnotationsMenuLabel = "Clear Annotations";
|
||||
private static final String resetPlotMenuLabel = "Reset Plot";
|
||||
private static final String splitPlotMenuLabel = "Split Plot";
|
||||
private static final String detachPlotMenuLabel = "Detach Plot";
|
||||
private static final String showLegendMenuLabel = "Show Legend";
|
||||
private static final String hideLegendMenuLabel = "Hide Legend";
|
||||
private static final String hideGraphPlotMenuLabel = "Hide/Show Graph";
|
||||
private static final String dataPointsMarkersMenuLabel = "Hide/Show datapoint markers";
|
||||
private static final String showTooltipsMenuLabel = "Show Tooltips";
|
||||
private static final String hideTooltipsMenuLabel = "Hide Tooltips";
|
||||
private static final String disableGraphChooserMenuLabel = "Disable GraphChooser";
|
||||
private static final String enableGraphChooserMenuLabel = "Enable GraphChooser";
|
||||
|
||||
|
||||
|
||||
private static final int chartPanelWidth = 500;
|
||||
private static final int chartPanelHeight = 270;
|
||||
|
||||
|
||||
private JMenu hideGraphMenu;
|
||||
private JMenuItem hideLegendMenuItem;
|
||||
|
||||
|
||||
//Action Map keys (Input Map values)
|
||||
|
||||
|
||||
|
||||
private LinePlotData data;
|
||||
private String title;
|
||||
private boolean tooltipVisible = false;
|
||||
private boolean enableGraphChooser = false;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param title Title of plot
|
||||
*/
|
||||
public LinePlot(String title){
|
||||
this(title, new LinePlotData(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param title Title of plot
|
||||
* @param data Data of plot
|
||||
*/
|
||||
public LinePlot(String title, LinePlotData data){
|
||||
this(title, data, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param title Title of plot
|
||||
* @param data Plot data
|
||||
* @param notification Flag whether adding a point will create a notification
|
||||
* @param useFastRenderer Flag to decide whether a fast renderer is used
|
||||
*/
|
||||
public LinePlot(String title, LinePlotData data, boolean notification){
|
||||
this.title = title;
|
||||
this.data = data;
|
||||
this.notification = notification;
|
||||
|
||||
|
||||
this.markers = new ArrayList<Marker>();
|
||||
|
||||
setUpPlotPanel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change visible part of chart
|
||||
* @param translationVector
|
||||
*/
|
||||
private void moverOverPlot(XYPoint translationVector) {
|
||||
double translatedDomainIntervalMin = chartPanel.getChart().getXYPlot().getDomainAxis().getRange().getLowerBound() + translationVector.getX();
|
||||
double translatedDomainIntervalMax = chartPanel.getChart().getXYPlot().getDomainAxis().getRange().getUpperBound() + translationVector.getX();
|
||||
double translatedRangeIntervalMin = chartPanel.getChart().getXYPlot().getRangeAxis().getRange().getLowerBound() + translationVector.getY();
|
||||
double translatedRangeIntervalMax = chartPanel.getChart().getXYPlot().getRangeAxis().getRange().getUpperBound() + translationVector.getY();
|
||||
|
||||
Range domainAxisRange = new Range(translatedDomainIntervalMin, translatedDomainIntervalMax);
|
||||
Range rangeAxisRange = new Range(translatedRangeIntervalMin, translatedRangeIntervalMax);
|
||||
//We set notify to false in the first call..
|
||||
chartPanel.getChart().getXYPlot().getDomainAxis().setRange(domainAxisRange, true, false);
|
||||
//...and true in the last
|
||||
chartPanel.getChart().getXYPlot().getRangeAxis().setRange(rangeAxisRange, true, true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add key bindings to chart panel
|
||||
*/
|
||||
private void addKeyBindings(){
|
||||
final String moveUpKey = "move up";
|
||||
final String moveDownKey = "move down";
|
||||
final String moveRightKey = "move right";
|
||||
final String moveLeftKey = "move left";
|
||||
|
||||
// Up arrow
|
||||
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), moveUpKey);
|
||||
chartPanel.getActionMap().put(moveUpKey, new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
XYPoint translationVector = new XYPoint(0.0, ((NumberAxis)chartPanel.getChart().getXYPlot().getRangeAxis()).getTickUnit().getSize());
|
||||
moverOverPlot(translationVector);
|
||||
}
|
||||
});
|
||||
|
||||
// Down arrow
|
||||
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),moveDownKey);
|
||||
chartPanel.getActionMap().put(moveDownKey, new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
XYPoint translationVector = new XYPoint(0.0, - ((NumberAxis)chartPanel.getChart().getXYPlot().getRangeAxis()).getTickUnit().getSize());
|
||||
moverOverPlot(translationVector);
|
||||
}
|
||||
});
|
||||
|
||||
// Right arrow
|
||||
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),moveRightKey);
|
||||
chartPanel.getActionMap().put(moveRightKey, new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
XYPoint translationVector = new XYPoint(((NumberAxis)chartPanel.getChart().getXYPlot().getDomainAxis()).getTickUnit().getSize(), 0.0);
|
||||
moverOverPlot(translationVector);
|
||||
}
|
||||
});
|
||||
|
||||
// Left arrow
|
||||
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),moveLeftKey);
|
||||
chartPanel.getActionMap().put(moveLeftKey, new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
XYPoint translationVector = new XYPoint(- ((NumberAxis)chartPanel.getChart().getXYPlot().getDomainAxis()).getTickUnit().getSize(), 0.0);
|
||||
moverOverPlot(translationVector);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JPanel getPlotPanel(){
|
||||
chartPanel.setName(title);
|
||||
return this.chartPanel;
|
||||
}
|
||||
|
||||
public BufferedImage getImage(){
|
||||
return(chartPanel.getChart().createBufferedImage(chartPanelWidth, chartPanelHeight, null));
|
||||
}
|
||||
|
||||
|
||||
public void plotByRenderingToScreen(boolean terminateOnExit, Integer x, Integer y, Integer width, Integer height){
|
||||
JFrame frame = new JFrame(title);
|
||||
// Add panel to frame
|
||||
frame.setContentPane(getPlotPanel());
|
||||
|
||||
frame.pack();
|
||||
if(terminateOnExit){
|
||||
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
|
||||
}
|
||||
|
||||
// Set frame size and position
|
||||
if(height != null && width != null){
|
||||
frame.setSize(width, height);
|
||||
}
|
||||
|
||||
if(x != null && y != null){
|
||||
frame.setLocation(x, y);
|
||||
}
|
||||
|
||||
else{
|
||||
// Center the frame
|
||||
RefineryUtilities.centerFrameOnScreen(frame);
|
||||
}
|
||||
frame.setVisible(true);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void plot(){
|
||||
plot(true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void plot(boolean terminateOnExit){
|
||||
plotByRenderingToScreen(terminateOnExit, null, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void plot(boolean terminateOnExit, int x, int y){
|
||||
plotByRenderingToScreen(terminateOnExit, new Integer(x), new Integer(y), null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void plot(boolean terminateOnExit, int x, int y, int width, int height){
|
||||
plotByRenderingToScreen(terminateOnExit, new Integer(x), new Integer(y), new Integer(width), new Integer(height));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEventActionListener(EventActionListener listener){
|
||||
eventActionListener.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEventActionListener(EventActionListener listener){
|
||||
eventActionListener.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup plot
|
||||
*/
|
||||
public void setUpPlotPanel() {
|
||||
// Create chart
|
||||
JFreeChart chart = createChart(data.getData(), data.getMetadata().getxAxisLabel(), data.getMetadata().getyAxisLabel());
|
||||
|
||||
chartPanel = new ChartPanel(chart);
|
||||
|
||||
if(tooltipVisible){
|
||||
showTooltips();
|
||||
}
|
||||
else{
|
||||
hideTooltips();
|
||||
}
|
||||
|
||||
|
||||
// Adapt chart panel
|
||||
chartPanel.addChartMouseListener(this);
|
||||
chartPanel.addMouseListener(this);
|
||||
chartPanel.addMouseMotionListener(this);
|
||||
|
||||
chartPanel.getChart().setBorderVisible(false);
|
||||
chartPanel.getChart().setNotify(notification);
|
||||
|
||||
chartPanel.setPreferredSize(new java.awt.Dimension(chartPanelWidth, chartPanelHeight));
|
||||
|
||||
|
||||
// Add more items to the context menu
|
||||
amendContextMenu();
|
||||
amendPlugableContextMenu();
|
||||
//Activate (arrow) keys
|
||||
addKeyBindings();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show Legend of chart
|
||||
* @param enable
|
||||
*/
|
||||
public void showLegend(boolean enable){
|
||||
chartPanel.getChart().getLegend().setVisible(enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional items to the context menu of the frame
|
||||
*/
|
||||
public void amendContextMenu(){
|
||||
|
||||
JMenuItem pauseMenuItem = new JMenuItem(pauseMenuLabel);
|
||||
pauseMenuItem.addActionListener(this);
|
||||
chartPanel.getPopupMenu().add(pauseMenuItem);
|
||||
|
||||
JMenuItem resetPlotMenuItem = new JMenuItem(resetPlotMenuLabel);
|
||||
resetPlotMenuItem.addActionListener(this);
|
||||
chartPanel.getPopupMenu().add(resetPlotMenuItem);
|
||||
|
||||
|
||||
hideGraphMenu = new JMenu(hideGraphPlotMenuLabel);
|
||||
hideGraphMenu.addActionListener(this);
|
||||
chartPanel.getPopupMenu().add(hideGraphMenu);
|
||||
|
||||
JMenuItem clearAnnotationsMenuItem = new JMenuItem(clearAnnotationsMenuLabel);
|
||||
clearAnnotationsMenuItem.addActionListener(this);
|
||||
chartPanel.getPopupMenu().add(clearAnnotationsMenuItem);
|
||||
|
||||
|
||||
JMenuItem dataPointsMarkersMenuItem = new JMenuItem(dataPointsMarkersMenuLabel);
|
||||
dataPointsMarkersMenuItem.addActionListener(this);
|
||||
chartPanel.getPopupMenu().add(dataPointsMarkersMenuItem);
|
||||
|
||||
JMenuItem splitPlotMenuItem = new JMenuItem(splitPlotMenuLabel);
|
||||
splitPlotMenuItem.addActionListener(this);
|
||||
chartPanel.getPopupMenu().add(splitPlotMenuItem);
|
||||
|
||||
JMenuItem detachPlotMenuItem = new JMenuItem(detachPlotMenuLabel);
|
||||
detachPlotMenuItem.addActionListener(this);
|
||||
chartPanel.getPopupMenu().add(detachPlotMenuItem);
|
||||
|
||||
hideLegendMenuItem = new JMenuItem(hideLegendMenuLabel);
|
||||
hideLegendMenuItem.addActionListener(this);
|
||||
chartPanel.getPopupMenu().add(hideLegendMenuItem);
|
||||
|
||||
JMenuItem hideToolTipsMenuItem = new JMenuItem(hideTooltipsMenuLabel);
|
||||
if(!tooltipVisible){
|
||||
hideToolTipsMenuItem.setText(showTooltipsMenuLabel);
|
||||
}
|
||||
hideToolTipsMenuItem.addActionListener(this);
|
||||
chartPanel.getPopupMenu().add(hideToolTipsMenuItem);
|
||||
|
||||
JMenuItem enableGraphChooserMenuItem = new JMenuItem(disableGraphChooserMenuLabel);
|
||||
if(!enableGraphChooser){
|
||||
enableGraphChooserMenuItem.setText(enableGraphChooserMenuLabel);
|
||||
}
|
||||
enableGraphChooserMenuItem.addActionListener(this);
|
||||
chartPanel.getPopupMenu().add(enableGraphChooserMenuItem);
|
||||
|
||||
|
||||
for (Object xySeries : data.getData().getSeries()) {
|
||||
JMenuItem graphMenuItem = new JMenuItem((String)((XYSeries) xySeries).getKey());
|
||||
graphMenuItem.addActionListener(this);
|
||||
hideGraphMenu.add(graphMenuItem);
|
||||
}
|
||||
|
||||
chartPanel.getPopupMenu().addSeparator();
|
||||
//FFT Menu Items
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* amend additional menu entries to the default context menu
|
||||
*/
|
||||
public void amendPlugableContextMenu(){
|
||||
//Add analysis menu items (created according xml)
|
||||
MenuLoader menuLoader = new MenuLoader(PlotType.oneDim, "menuconfigxy.xml","ch.psi.plot.xy.plugable.", this);
|
||||
menuLoader.initUtils(chartPanel.getPopupMenu());
|
||||
//load the predifined menu entries
|
||||
plugableUtils = menuLoader.getPlugableUtils();
|
||||
//load the user defined plugins
|
||||
loadServices();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* load services if there are and add them to the plugableUtils List
|
||||
*/
|
||||
private void loadServices() {
|
||||
ServiceLoader<PlugableUtilXY> plugableUtilXYServices = ServiceLoader.load(PlugableUtilXY.class);
|
||||
for ( PlugableUtilXY plugableUtilXYService : plugableUtilXYServices){
|
||||
plugableUtils.add(plugableUtilXYService);
|
||||
JMenuItem serviceLoadedMenuItem = new JMenuItem(plugableUtilXYService.getLabel());
|
||||
serviceLoadedMenuItem.addActionListener(this);
|
||||
chartPanel.getPopupMenu().add(serviceLoadedMenuItem);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JFreeChart.
|
||||
* @param dataset the data for the chart.
|
||||
* @return a chart.
|
||||
*/
|
||||
private JFreeChart createChart(XYDataset dataset, String xLabel, String yLabel) {
|
||||
|
||||
// Create chart
|
||||
JFreeChart chart = ChartFactory.createXYLineChart(this.title, xLabel, yLabel, dataset, PlotOrientation.VERTICAL, true, false, false);
|
||||
|
||||
// Customize chart look and feel
|
||||
chart.setBackgroundPaint(new Color(238,238,238));
|
||||
chart.getLegend().setBackgroundPaint(new Color(238,238,238));
|
||||
chart.getLegend().setBorder(0, 0, 0, 0);
|
||||
|
||||
// Customize plot area look and feel
|
||||
XYPlot plot = (XYPlot) chart.getPlot();
|
||||
plot.setBackgroundPaint(Color.white);
|
||||
plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0));
|
||||
plot.setDomainGridlinePaint(Color.gray);
|
||||
plot.setRangeGridlinePaint(Color.gray);
|
||||
|
||||
// Show data point
|
||||
((XYLineAndShapeRenderer)plot.getRenderer()).setBaseShapesVisible(true);
|
||||
|
||||
|
||||
((NumberAxis) plot.getRangeAxis()).setAutoRangeIncludesZero(false);
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show tooltips
|
||||
*/
|
||||
public void showTooltips(){
|
||||
DecimalFormat dm = new DecimalFormat("0.##########");
|
||||
XYToolTipGenerator xYToolTipGenerator = new StandardXYToolTipGenerator( "{1}/{2}", dm, dm);
|
||||
chartPanel.getChart().getXYPlot().getRenderer().setBaseToolTipGenerator(xYToolTipGenerator);
|
||||
chartPanel.setDisplayToolTips(true);
|
||||
chartPanel.getChartRenderingInfo().setEntityCollection(new StandardEntityCollection());
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide tooltips
|
||||
*/
|
||||
public void hideTooltips(){
|
||||
chartPanel.getChartRenderingInfo().setEntityCollection(null); // TODO verify (http://www.jfree.org/phpBB2/viewtopic.php?t=12788&highlight=redraw+speed+performance+problem)
|
||||
chartPanel.getChart().getXYPlot().getRenderer().setBaseToolTipGenerator(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives chart mouse click events.
|
||||
* @param event the event.
|
||||
*/
|
||||
@Override
|
||||
public void chartMouseClicked(ChartMouseEvent event) {
|
||||
|
||||
//calculate x and y value in chart at mouse position
|
||||
XYPoint chartPoint = new XYPoint(0.0,0.0);
|
||||
if (!CoordinateTransformer.chartCoordinates(chartPanel, event.getTrigger().getX(),event.getTrigger().getY(), chartPoint)){;
|
||||
return;
|
||||
}
|
||||
double chartX = chartPoint.getX().doubleValue();
|
||||
|
||||
if ((event.getTrigger().getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK ){
|
||||
//remove marker if exists
|
||||
//Lazy evaluation of the 'and' is needed here
|
||||
if(chartPanel.getChart().getXYPlot().getDomainMarkers(Layer.FOREGROUND) != null && getValueMarker(chartX) != null){
|
||||
chartPanel.getChart().getXYPlot().removeDomainMarker(getValueMarker(chartX));
|
||||
}
|
||||
else{
|
||||
//Now use data to set marker:
|
||||
ValueMarker valuemarker = new ValueMarker(chartX);
|
||||
valuemarker.setPaint(Color.green);
|
||||
//valuemarker.setLabel("Start");
|
||||
//valuemarker.setLabelAnchor(RectangleAnchor.TOP_LEFT);
|
||||
//valuemarker.setLabelTextAnchor(TextAnchor.TOP_RIGHT);
|
||||
chartPanel.getChart().getXYPlot().addDomainMarker(valuemarker);
|
||||
}
|
||||
}
|
||||
else if ((event.getTrigger().getModifiers() & InputEvent.BUTTON2_MASK) == InputEvent.BUTTON2_MASK ){
|
||||
//Lazy evaluation of the 'and' is needed here
|
||||
if(chartPanel.getChart().getXYPlot().getDomainMarkers(Layer.BACKGROUND) != null && isClickInSelectedInterval(chartX) != null){
|
||||
//It could be that valuemarker are allready removed, but there is no danger here
|
||||
chartPanel.getChart().getXYPlot().removeDomainMarker(getValueMarker(isClickInSelectedInterval(chartX).getStartValue()),Layer.FOREGROUND);
|
||||
chartPanel.getChart().getXYPlot().removeDomainMarker(getValueMarker(isClickInSelectedInterval(chartX).getEndValue()),Layer.FOREGROUND);
|
||||
chartPanel.getChart().getXYPlot().removeDomainMarker(isClickInSelectedInterval(chartX),Layer.BACKGROUND);
|
||||
}
|
||||
// else if condition is for security (should not happen that someone clicks to mark interval before interval exists, but can happen.
|
||||
else if(chartPanel.getChart().getXYPlot().getDomainMarkers(Layer.FOREGROUND) != null){
|
||||
Double leftIntervalBorder = calculateInfimum(chartPanel.getChart().getXYPlot().getDomainAxis().getLowerBound(),chartX);
|
||||
Double rightIntervalBorder = calculateSupremum(chartPanel.getChart().getXYPlot().getDomainAxis().getUpperBound(),chartX);
|
||||
IntervalMarker intervalmarker = new IntervalMarker(leftIntervalBorder,rightIntervalBorder);
|
||||
// getBackground(); // TODO commenting out of this need to be verified
|
||||
intervalmarker.setPaint(Color.LIGHT_GRAY);
|
||||
chartPanel.getChart().getXYPlot().addDomainMarker(intervalmarker,Layer.BACKGROUND);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Value marker at the position chartX
|
||||
* @param chartX
|
||||
* @return valueMarker
|
||||
*/
|
||||
public ValueMarker getValueMarker(Double chartX){
|
||||
//Layer.ForeGround returns ValueMarkers make sure that ALL value markers are set foreground
|
||||
for (Object o: chartPanel.getChart().getXYPlot().getDomainMarkers(Layer.FOREGROUND)){
|
||||
ValueMarker valueMarker = (ValueMarker) o;
|
||||
if (valueMarker.getValue() == chartX){
|
||||
return valueMarker;
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the Interval bounded by start/end
|
||||
* @param start
|
||||
* @param end
|
||||
* @return
|
||||
*/
|
||||
public IntervalMarker getIntervalMarker(Double start, Double end){
|
||||
|
||||
//Layer.BACKGROUND returns IntervalMarkers. make sure that ALL interval markers are set background
|
||||
for (Object o: chartPanel.getChart().getXYPlot().getDomainMarkers(Layer.BACKGROUND)){
|
||||
IntervalMarker intervalMarker = (IntervalMarker) o;
|
||||
if (intervalMarker.getStartValue() == start && intervalMarker.getEndValue() == end){
|
||||
return intervalMarker;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get interval markers
|
||||
*/
|
||||
public List<Interval> getIntervalMarkers(){
|
||||
List<Interval> intervals = new ArrayList<Interval>();
|
||||
for (Object o: chartPanel.getChart().getXYPlot().getDomainMarkers(Layer.BACKGROUND)){
|
||||
IntervalMarker intervalMarker = (IntervalMarker) o;
|
||||
intervals.add(new Interval(intervalMarker.getStartValue(), intervalMarker.getEndValue()));
|
||||
}
|
||||
return(intervals);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* calculate the infimum of value chartX that is not smaller than leftBound
|
||||
* @param leftBound
|
||||
* @param chartX
|
||||
* @return
|
||||
*/
|
||||
public Double calculateInfimum(Double leftBound, Double chartX){
|
||||
Set<Double> lower = new HashSet<Double>();
|
||||
lower.add(leftBound);
|
||||
for (Object o: chartPanel.getChart().getXYPlot().getDomainMarkers(Layer.FOREGROUND)){
|
||||
ValueMarker valueMarker = (ValueMarker) o;
|
||||
if (valueMarker.getValue() < chartX){
|
||||
lower.add(valueMarker.getValue());
|
||||
}
|
||||
}
|
||||
return (Double) Collections.max(lower);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate the supremum of value chartX that is not bigger than rightBound
|
||||
* @param leftBound
|
||||
* @param chartX
|
||||
* @return
|
||||
*/
|
||||
public Double calculateSupremum(Double rightBound, Double chartX){
|
||||
Set<Double> upper = new HashSet<Double>();
|
||||
upper.add(rightBound);
|
||||
for (Object o: chartPanel.getChart().getXYPlot().getDomainMarkers(Layer.FOREGROUND)){
|
||||
ValueMarker valueMarker = (ValueMarker) o;
|
||||
if (valueMarker.getValue() > chartX){
|
||||
upper.add(valueMarker.getValue());
|
||||
}
|
||||
}
|
||||
return (Double) Collections.min(upper);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the clicked interval
|
||||
* @param chartX
|
||||
* @return
|
||||
*/
|
||||
public IntervalMarker isClickInSelectedInterval(Double chartX){
|
||||
for (Object o: chartPanel.getChart().getXYPlot().getDomainMarkers(Layer.BACKGROUND)){
|
||||
IntervalMarker intervalMarker = (IntervalMarker) o;
|
||||
if (intervalMarker.getStartValue() <= chartX && chartX <= intervalMarker.getEndValue()){
|
||||
return intervalMarker;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Receives events if mouse moved on the chart
|
||||
* @param event the event.
|
||||
*/
|
||||
@Override
|
||||
public void chartMouseMoved(ChartMouseEvent event) {
|
||||
//TODO To be implemented or removed
|
||||
}
|
||||
|
||||
/**
|
||||
* Event reciever if mouse is clicked
|
||||
*/
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
|
||||
//either: extract tooltip
|
||||
if (e.getSource().equals(chartPanel)){
|
||||
// Parse coordinates out of tooltip
|
||||
double x,y;
|
||||
String label;
|
||||
String ttip = chartPanel.getToolTipText(e);
|
||||
if (ttip != null){
|
||||
String floatingPointRegex = "[-+]?[0-9]*\\.?[0-9]+";
|
||||
String regex = "(\\w*):{1}\\s*\\(" + "(" + floatingPointRegex + ")" + ",{1}\\s*" + "(" + floatingPointRegex + ")";
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher matcher = pattern.matcher(ttip);
|
||||
|
||||
while (matcher.find()) {
|
||||
label = matcher.group(1);
|
||||
x = Double.parseDouble(matcher.group(2).toString());
|
||||
y = Double.parseDouble(matcher.group(3).toString());
|
||||
logger.fine("Label:"+ label +" x=" + x + "y=" + y);
|
||||
markers.add(new Marker(label, x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//or: open graph properties context menu
|
||||
boolean clickInChart = CoordinateTransformer.chartCoordinates(chartPanel, e.getX(), e.getY(), new XYPoint(0.0, 0.0));
|
||||
if((!clickInChart) && enableGraphChooser){
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
new GraphChooserFrame(data, chartPanel.getChart().getXYPlot()).setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Event receiver if mouse entered chart
|
||||
*/
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
//TODO To be implemented or removed
|
||||
}
|
||||
|
||||
/**
|
||||
* Event receiver if mouse exited chart
|
||||
*/
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e) {
|
||||
//TODO To be implemented or removed
|
||||
}
|
||||
|
||||
/**
|
||||
* Event receiver mouse pressed
|
||||
*/
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
dragging = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event receiver mouse released
|
||||
*/
|
||||
@Override
|
||||
//Change scale via drag and drop
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
if(dragging == true && rescaleAxis == true){
|
||||
if(this.difference.getX() > 0.0){
|
||||
chartPanel.getChart().getXYPlot().getDomainAxis().setUpperBound(
|
||||
chartPanel.getChart().getXYPlot().getDomainAxis().getUpperBound() + difference.getX());
|
||||
}
|
||||
else{
|
||||
chartPanel.getChart().getXYPlot().getDomainAxis().setLowerBound(
|
||||
chartPanel.getChart().getXYPlot().getDomainAxis().getLowerBound() - difference.getX());
|
||||
|
||||
}
|
||||
|
||||
if(this.difference.getY() > 0.0){
|
||||
chartPanel.getChart().getXYPlot().getRangeAxis().setUpperBound(
|
||||
chartPanel.getChart().getXYPlot().getRangeAxis().getUpperBound() + difference.getY());
|
||||
}
|
||||
else{
|
||||
chartPanel.getChart().getXYPlot().getRangeAxis().setLowerBound(
|
||||
chartPanel.getChart().getXYPlot().getRangeAxis().getLowerBound() - difference.getY());
|
||||
|
||||
}
|
||||
}
|
||||
dragging = false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Event receiver mouse dragged
|
||||
*/
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
XYPoint startPoint = new XYPoint(0.0,0.0);
|
||||
XYPoint endPoint = new XYPoint(0.0,0.0);
|
||||
|
||||
if (dragging == false){
|
||||
//startPoint of dragging must lie outside plot coordinate system to rescale Axis.
|
||||
rescaleAxis = !CoordinateTransformer.chartCoordinates(chartPanel, e.getX(), e.getY(),startPoint);
|
||||
dragging = true;
|
||||
}
|
||||
CoordinateTransformer.chartCoordinates(chartPanel, e.getX(), e.getY(), endPoint);
|
||||
difference.setX(endPoint.getX() - startPoint.getX());
|
||||
difference.setY(endPoint.getY() - startPoint.getY());
|
||||
|
||||
}
|
||||
|
||||
public void showMins(){
|
||||
for (XYPoint min : Extrema.findExtrema(data, true)){
|
||||
XYAnnotation cross = new XYDrawableAnnotation(min.getX(), min.getY(), 10.0, 10.0, new CrossAnnotation(Color.BLACK));
|
||||
chartPanel.getChart().getXYPlot().addAnnotation(cross);
|
||||
}
|
||||
}
|
||||
public void showMaxs(){
|
||||
for (XYPoint max : Extrema.findExtrema(data, false)){
|
||||
XYAnnotation cross = new XYDrawableAnnotation(max.getX(), max.getY(), 10.0, 10.0, new CrossAnnotation(Color.BLACK));
|
||||
chartPanel.getChart().getXYPlot().addAnnotation(cross);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event receiver mouse moved
|
||||
*/
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
//TODO To be implemented or removed
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Event receiver action performed
|
||||
*/
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuItem source = (JMenuItem)(e.getSource());
|
||||
JMenu parent = null;
|
||||
try {
|
||||
parent = (JMenu)((JPopupMenu) source.getParent()).getInvoker();
|
||||
} catch (ClassCastException c) {
|
||||
}
|
||||
|
||||
|
||||
logger.finest( source.getText());
|
||||
for (PlugableUtil plugableUtil : plugableUtils) {
|
||||
if(source.getText().equals(plugableUtil.getLabel())){
|
||||
try{
|
||||
((PlugableUtilXY)plugableUtil).execute(this);
|
||||
}
|
||||
catch (ClassCastException pe) {
|
||||
logger.log(Level.SEVERE, "Unable to execute plugin " + ((PlugableUtilXY)plugableUtil).getLabel(), pe);
|
||||
} catch (PluginExecutionException pe) {
|
||||
logger.log(Level.SEVERE, "Unable to execute plugin " + ((PlugableUtilXY)plugableUtil).getLabel(), pe);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Need to reimplement this functions
|
||||
// no update() function needed as plot changes automatically if data changes
|
||||
if(source.getText() == pauseMenuLabel){
|
||||
for(EventActionListener listener: eventActionListener){
|
||||
listener.performAction(EventActionListener.Actions.PAUSE);
|
||||
}
|
||||
source.setText(continueMenuLabel);
|
||||
}
|
||||
else if(source.getText() == continueMenuLabel){
|
||||
for(EventActionListener listener: eventActionListener){
|
||||
listener.performAction(EventActionListener.Actions.CONTINUE);
|
||||
}
|
||||
source.setText(pauseMenuLabel);
|
||||
}
|
||||
|
||||
else if(source.getText() == dataPointsMarkersMenuLabel){
|
||||
boolean shapesFilled = ((XYLineAndShapeRenderer)chartPanel.getChart().getXYPlot().getRenderer()).getBaseShapesVisible();
|
||||
((XYLineAndShapeRenderer)chartPanel.getChart().getXYPlot().getRenderer()).setBaseShapesVisible(!shapesFilled);
|
||||
|
||||
}
|
||||
|
||||
else if(source.getText() == clearAnnotationsMenuLabel){
|
||||
chartPanel.getChart().getXYPlot().clearRangeMarkers();
|
||||
chartPanel.getChart().getXYPlot().clearDomainMarkers();
|
||||
chartPanel.getChart().getXYPlot().clearAnnotations();
|
||||
}
|
||||
|
||||
else if(source.getText() == showLegendMenuLabel){
|
||||
showLegend(true);
|
||||
source.setText(hideLegendMenuLabel);
|
||||
}
|
||||
|
||||
else if(source.getText() == hideLegendMenuLabel){
|
||||
showLegend(false);
|
||||
source.setText(showLegendMenuLabel);
|
||||
}
|
||||
|
||||
else if(source.getText() == showTooltipsMenuLabel){
|
||||
showTooltips();
|
||||
source.setText(hideTooltipsMenuLabel);
|
||||
setTooltipVisible(true);
|
||||
}
|
||||
|
||||
else if(source.getText() == hideTooltipsMenuLabel){
|
||||
hideTooltips();
|
||||
source.setText(showTooltipsMenuLabel);
|
||||
setTooltipVisible(false);
|
||||
}
|
||||
|
||||
//
|
||||
else if(source.getText() == enableGraphChooserMenuLabel){
|
||||
enableGraphChooser=true;
|
||||
source.setText(disableGraphChooserMenuLabel);
|
||||
}
|
||||
|
||||
else if(source.getText() == disableGraphChooserMenuLabel){
|
||||
enableGraphChooser=false;
|
||||
source.setText(enableGraphChooserMenuLabel);
|
||||
}
|
||||
//
|
||||
else if(source.getText() == resetPlotMenuLabel){
|
||||
// TODO to be defined
|
||||
// dataListenerAndConverter.resetPlot();
|
||||
}
|
||||
|
||||
else if(source.getText() == splitPlotMenuLabel){
|
||||
for (Object xySeries : ((XYSeriesCollection) data.getData()).getSeries()) {
|
||||
LinePlotData d = new LinePlotData();
|
||||
((XYSeriesCollection) d.getData()).addSeries(((XYSeries) xySeries));
|
||||
int index = data.getData().indexOf((XYSeries) xySeries);
|
||||
//The right colors are not automatically assigned
|
||||
Paint paint = chartPanel.getChart().getXYPlot().getRenderer().getSeriesPaint(index);
|
||||
LinePlot p = new LinePlot((String) ((XYSeries) xySeries).getKey(), d);
|
||||
// there is only one series in this plot, so we choose index 0 to assign paint
|
||||
p.getChartPanel().getChart().getXYPlot().getRenderer().setSeriesPaint(0, paint);
|
||||
p.plot(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else if(source.getText() == detachPlotMenuLabel){
|
||||
LinePlotData d = data;
|
||||
LinePlot p = new LinePlot(this.title, d);
|
||||
p.plot(false);
|
||||
}
|
||||
|
||||
|
||||
//the following cast may throw a ClasscastException
|
||||
else if (parent != null){
|
||||
if(parent.getText().equals(hideGraphPlotMenuLabel ) ){
|
||||
int index = -1;
|
||||
for (Object xySeries : ((XYSeriesCollection) data.getData()).getSeries()) {
|
||||
if( ((XYSeries) xySeries).getKey() == source.getText()){
|
||||
index = data.getData().indexOf((XYSeries) xySeries);
|
||||
}
|
||||
}
|
||||
boolean visible = chartPanel.getChart().getXYPlot().getRenderer().isSeriesVisible(index);
|
||||
chartPanel.getChart().getXYPlot().getRenderer().setSeriesVisible(index, !visible);
|
||||
//logger.fine(chartPanel.getChart().getLegend(index).getFrame().getInsets().getLeft());
|
||||
}
|
||||
}
|
||||
|
||||
else{
|
||||
logger.severe("Unknown source " + source.getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
|
||||
// Update menu structure ...
|
||||
logger.fine("Update triggered in LinePlot ["+title+"]");
|
||||
hideGraphMenu.removeAll();
|
||||
for (Object xySeries : data.getData().getSeries()) {
|
||||
JMenuItem graphMenuItem = new JMenuItem((String)((XYSeries) xySeries).getKey());
|
||||
graphMenuItem.addActionListener(this);
|
||||
hideGraphMenu.add(graphMenuItem);
|
||||
}
|
||||
|
||||
// If there are more than 10 xySeries, hide legend
|
||||
// Only check == 10 because if legend is manually set to true afterwards that this does
|
||||
// not get overwritten each time this function is called
|
||||
if(data.getData().getSeries().size()==10){
|
||||
showLegend(false);
|
||||
hideLegendMenuItem.setText(showLegendMenuLabel);
|
||||
}
|
||||
|
||||
chartPanel.getChart().setNotify(!notification);
|
||||
chartPanel.getChart().setNotify(notification);
|
||||
|
||||
}
|
||||
|
||||
//getter and setter
|
||||
public LinePlotData getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(LinePlotData data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public ChartPanel getChartPanel() {
|
||||
return chartPanel;
|
||||
}
|
||||
|
||||
public void setChartPanel(ChartPanel chartPanel) {
|
||||
this.chartPanel = chartPanel;
|
||||
}
|
||||
|
||||
public List<Marker> getMarkers(){
|
||||
return(markers);
|
||||
}
|
||||
|
||||
public boolean isTooltipVisible() {
|
||||
return tooltipVisible;
|
||||
}
|
||||
|
||||
private void setTooltipVisible(boolean tooltipVisible) {
|
||||
this.tooltipVisible = tooltipVisible;
|
||||
}
|
||||
|
||||
public XYSeries newSeries(String key){
|
||||
XYSeries s = new XYSeries(key);
|
||||
getData().getData().addSeries(s);
|
||||
return(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
import org.jfree.data.xy.XYSeriesCollection;
|
||||
|
||||
import ch.psi.plot.PlotData;
|
||||
|
||||
/**
|
||||
* Bean holding a line plot data/metadata
|
||||
*/
|
||||
public class LinePlotData implements PlotData {
|
||||
|
||||
private XYSeriesCollection data = new XYSeriesCollection();
|
||||
private LinePlotMetadata metadata = new LinePlotMetadata();
|
||||
|
||||
/**
|
||||
* Get plottable XYDataSet
|
||||
* @return Data in an XYDataset object
|
||||
*/
|
||||
public XYSeriesCollection getData(){
|
||||
return(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set line plot data
|
||||
* @param data Data in a XYDataset
|
||||
*/
|
||||
public void setData(XYSeriesCollection data){
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data related metadata
|
||||
* @return
|
||||
*/
|
||||
public LinePlotMetadata getMetadata(){
|
||||
return(metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set line plot metadata
|
||||
* @param metadata
|
||||
*/
|
||||
public void setMetadata(LinePlotMetadata metadata){
|
||||
this.metadata = metadata;
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
/**
|
||||
* Class holding metadata of a line plot
|
||||
*/
|
||||
public class LinePlotMetadata {
|
||||
|
||||
/**
|
||||
* X Axis label
|
||||
*/
|
||||
private String xAxisLabel = "X";
|
||||
|
||||
/**
|
||||
* Y Axis label
|
||||
*/
|
||||
private String yAxisLabel = "Y";
|
||||
|
||||
// Getter and setter functions
|
||||
|
||||
/**
|
||||
* @return the xAxisLabel
|
||||
*/
|
||||
public String getxAxisLabel() {
|
||||
return xAxisLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param xAxisLabel the xAxisLabel to set
|
||||
*/
|
||||
public void setxAxisLabel(String xAxisLabel) {
|
||||
this.xAxisLabel = xAxisLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the yAxisLabel
|
||||
*/
|
||||
public String getyAxisLabel() {
|
||||
return yAxisLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param yAxisLabel the yAxisLabel to set
|
||||
*/
|
||||
public void setyAxisLabel(String yAxisLabel) {
|
||||
this.yAxisLabel = yAxisLabel;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import org.jfree.chart.annotations.XYAnnotation;
|
||||
import org.jfree.chart.annotations.XYDrawableAnnotation;
|
||||
|
||||
import ch.psi.plot.util.XYPoint;
|
||||
import ch.psi.plot.xy.LinePlot;
|
||||
import ch.psi.plot.xyz.CrossDrawer;
|
||||
|
||||
public class Maxs implements PlugableUtilXY{
|
||||
|
||||
@Override
|
||||
public void execute(LinePlot lineplot) {
|
||||
for (XYPoint max : Extrema.findExtrema(lineplot.getData(), false)){
|
||||
CrossDrawer cd = new CrossDrawer(Color.BLACK);
|
||||
XYAnnotation cross = new XYDrawableAnnotation(max.getX(), max.getY(), 10.0, 10.0, cd);
|
||||
lineplot.getChartPanel().getChart().getXYPlot().addAnnotation(cross);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
|
||||
import ch.psi.plot.menuconfig.MenuNodeType;
|
||||
import ch.psi.plot.menuconfig.MenuTreeType;
|
||||
import ch.psi.plot.util.PlugableUtil.PlotType;
|
||||
import ch.psi.plot.xy.plugable.PlugableUtilXY;
|
||||
import ch.psi.plot.xyz.plugable.PlugableUtilXYZ;
|
||||
|
||||
/**
|
||||
* Class which generates a menu according to an xml file
|
||||
*
|
||||
*/
|
||||
public class MenuLoader {
|
||||
|
||||
private static Logger logger = Logger.getLogger(MenuLoader.class.getName());
|
||||
|
||||
private PlotType plotType;
|
||||
private String xmlFileName;
|
||||
private String utilityClassPackageName;
|
||||
private ActionListener listener;
|
||||
private List<PlugableUtil> plugableUtils = new ArrayList<PlugableUtil>();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param plotType
|
||||
* @param xmlFileName
|
||||
* @param utilityClassPackageName
|
||||
* @param listener
|
||||
*/
|
||||
public MenuLoader(PlotType plotType, String xmlFileName,
|
||||
String utilityClassPackageName, ActionListener listener) {
|
||||
this.plotType = plotType;
|
||||
this.xmlFileName = xmlFileName;
|
||||
this.utilityClassPackageName = utilityClassPackageName;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds menu entries and submenus to the basis menu according to the xmlFileName
|
||||
* @param basisMenu
|
||||
*/
|
||||
public void initUtils(JComponent basisMenu){
|
||||
|
||||
JAXBContext jc;
|
||||
Unmarshaller um;
|
||||
JAXBElement<?> rootMenuElement = null;
|
||||
|
||||
try {
|
||||
jc = JAXBContext.newInstance("ch.psi.plot.menuconfig");
|
||||
um = jc.createUnmarshaller();
|
||||
InputStream xmlResource = this.getClass().getResourceAsStream(xmlFileName);
|
||||
if(xmlResource == null){
|
||||
logger.log(Level.WARNING, "Resource '" + xmlFileName + "' is null ");
|
||||
return;
|
||||
}
|
||||
|
||||
rootMenuElement = (JAXBElement<?>) um.unmarshal(xmlResource);
|
||||
|
||||
} catch (JAXBException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
MenuTreeType rootMenu = (MenuTreeType)rootMenuElement.getValue();
|
||||
|
||||
List<MenuNodeType> rootMenuEntries = rootMenu.getMenuNode();
|
||||
//We start with the rootMenu entries for parsing, they are added to the popupmenu
|
||||
addMenuItem(basisMenu, rootMenuEntries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds (recursively) menuEntries to menu. (an element of menuEntries is either a
|
||||
* item (command) or a submenu).
|
||||
* @param menu
|
||||
* @param menuEntries
|
||||
*/
|
||||
private void addMenuItem(JComponent menu, List<MenuNodeType> menuEntries){
|
||||
|
||||
//Check for all menu entries if they are a feature or a submenu
|
||||
for (MenuNodeType menuNodeEntry : menuEntries) {
|
||||
if(menuNodeEntry.getUtilityClass() != null){
|
||||
Class<?> pluginClass = null;
|
||||
try {//Load class according to its name
|
||||
pluginClass = Class.forName( utilityClassPackageName + menuNodeEntry.getUtilityClass().getName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
try {//add loaded class to List of plugable Utils (properly casted)
|
||||
switch (plotType) {
|
||||
case oneDim:
|
||||
plugableUtils.add((PlugableUtilXY) pluginClass.newInstance());
|
||||
break;
|
||||
case twoDim:
|
||||
plugableUtils.add((PlugableUtilXYZ) pluginClass.newInstance());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
continue;
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
|
||||
int indexTop = plugableUtils.size() - 1;
|
||||
JMenuItem menuItem = new JMenuItem(plugableUtils.get(indexTop).getLabel());
|
||||
menuItem.addActionListener(listener);
|
||||
menu.add(menuItem);
|
||||
}
|
||||
else{//If it is not a menu entry, it must be a submenu
|
||||
//so we call the function recursively
|
||||
//First we create the new Menu..
|
||||
JMenu submenu = new JMenu(menuNodeEntry.getName());
|
||||
menu.add(submenu);
|
||||
//..then we call the function again with the newly created menu and the submenulist
|
||||
addMenuItem(submenu, menuNodeEntry.getSubmenu());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//getter and setter
|
||||
public List<PlugableUtil> getPlugableUtils() {
|
||||
return plugableUtils;
|
||||
}
|
||||
|
||||
public void setPlugableUtils(List<PlugableUtil> plugableUtils) {
|
||||
this.plugableUtils = plugableUtils;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
//
|
||||
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6
|
||||
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
|
||||
// Any modifications to this file will be lost upon recompilation of the source schema.
|
||||
// Generated on: 2009.12.07 at 03:37:39 PM CET
|
||||
//
|
||||
|
||||
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Java class for menuNodeType complex type.
|
||||
*
|
||||
* <p>The following schema fragment specifies the expected content contained within this class.
|
||||
*
|
||||
* <pre>
|
||||
* <complexType name="menuNodeType">
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <choice>
|
||||
* <sequence>
|
||||
* <element name="submenu" type="{}menuNodeType" maxOccurs="unbounded" minOccurs="0"/>
|
||||
* </sequence>
|
||||
* <element name="utilityClass" type="{}utilityClassType"/>
|
||||
* </choice>
|
||||
* <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "menuNodeType", propOrder = {
|
||||
"submenu",
|
||||
"utilityClass"
|
||||
})
|
||||
public class MenuNodeType {
|
||||
|
||||
protected List<MenuNodeType> submenu;
|
||||
protected UtilityClassType utilityClass;
|
||||
@XmlAttribute
|
||||
protected String name;
|
||||
|
||||
/**
|
||||
* Gets the value of the submenu property.
|
||||
*
|
||||
* <p>
|
||||
* This accessor method returns a reference to the live list,
|
||||
* not a snapshot. Therefore any modification you make to the
|
||||
* returned list will be present inside the JAXB object.
|
||||
* This is why there is not a <CODE>set</CODE> method for the submenu property.
|
||||
*
|
||||
* <p>
|
||||
* For example, to add a new item, do as follows:
|
||||
* <pre>
|
||||
* getSubmenu().add(newItem);
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Objects of the following type(s) are allowed in the list
|
||||
* {@link MenuNodeType }
|
||||
*
|
||||
*
|
||||
*/
|
||||
public List<MenuNodeType> getSubmenu() {
|
||||
if (submenu == null) {
|
||||
submenu = new ArrayList<MenuNodeType>();
|
||||
}
|
||||
return this.submenu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the utilityClass property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link UtilityClassType }
|
||||
*
|
||||
*/
|
||||
public UtilityClassType getUtilityClass() {
|
||||
return utilityClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the utilityClass property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link UtilityClassType }
|
||||
*
|
||||
*/
|
||||
public void setUtilityClass(UtilityClassType value) {
|
||||
this.utilityClass = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the name property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the name property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public void setName(String value) {
|
||||
this.name = value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
//
|
||||
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6
|
||||
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
|
||||
// Any modifications to this file will be lost upon recompilation of the source schema.
|
||||
// Generated on: 2009.12.07 at 03:37:39 PM CET
|
||||
//
|
||||
|
||||
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Java class for menuTreeType complex type.
|
||||
*
|
||||
* <p>The following schema fragment specifies the expected content contained within this class.
|
||||
*
|
||||
* <pre>
|
||||
* <complexType name="menuTreeType">
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <sequence>
|
||||
* <element name="menuNode" type="{}menuNodeType" maxOccurs="unbounded" minOccurs="0"/>
|
||||
* </sequence>
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "menuTreeType", propOrder = {
|
||||
"menuNode"
|
||||
})
|
||||
public class MenuTreeType {
|
||||
|
||||
protected List<MenuNodeType> menuNode;
|
||||
|
||||
/**
|
||||
* Gets the value of the menuNode property.
|
||||
*
|
||||
* <p>
|
||||
* This accessor method returns a reference to the live list,
|
||||
* not a snapshot. Therefore any modification you make to the
|
||||
* returned list will be present inside the JAXB object.
|
||||
* This is why there is not a <CODE>set</CODE> method for the menuNode property.
|
||||
*
|
||||
* <p>
|
||||
* For example, to add a new item, do as follows:
|
||||
* <pre>
|
||||
* getMenuNode().add(newItem);
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Objects of the following type(s) are allowed in the list
|
||||
* {@link MenuNodeType }
|
||||
*
|
||||
*
|
||||
*/
|
||||
public List<MenuNodeType> getMenuNode() {
|
||||
if (menuNode == null) {
|
||||
menuNode = new ArrayList<MenuNodeType>();
|
||||
}
|
||||
return this.menuNode;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import org.jfree.chart.annotations.XYAnnotation;
|
||||
import org.jfree.chart.annotations.XYDrawableAnnotation;
|
||||
|
||||
import ch.psi.plot.util.XYPoint;
|
||||
import ch.psi.plot.xy.LinePlot;
|
||||
import ch.psi.plot.xyz.CrossDrawer;
|
||||
|
||||
public class Mins implements PlugableUtilXY{
|
||||
|
||||
@Override
|
||||
public void execute(LinePlot lineplot) {
|
||||
for (XYPoint min : Extrema.findExtrema(lineplot.getData(), true)){
|
||||
CrossDrawer cd = new CrossDrawer(Color.BLACK);
|
||||
XYAnnotation cross = new XYDrawableAnnotation(min.getX(), min.getY(), 10.0, 10.0, cd);
|
||||
lineplot.getChartPanel().getChart().getXYPlot().addAnnotation(cross);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
//
|
||||
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6
|
||||
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
|
||||
// Any modifications to this file will be lost upon recompilation of the source schema.
|
||||
// Generated on: 2009.12.07 at 03:37:39 PM CET
|
||||
//
|
||||
|
||||
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import javax.xml.bind.annotation.XmlElementDecl;
|
||||
import javax.xml.bind.annotation.XmlRegistry;
|
||||
import javax.xml.namespace.QName;
|
||||
|
||||
|
||||
/**
|
||||
* This object contains factory methods for each
|
||||
* Java content interface and Java element interface
|
||||
* generated in the ch.psi.sls.xasec.plot.menuconfig package.
|
||||
* <p>An ObjectFactory allows you to programatically
|
||||
* construct new instances of the Java representation
|
||||
* for XML content. The Java representation of XML
|
||||
* content can consist of schema derived interfaces
|
||||
* and classes representing the binding of schema
|
||||
* type definitions, element declarations and model
|
||||
* groups. Factory methods for each of these are
|
||||
* provided in this class.
|
||||
*
|
||||
*/
|
||||
@XmlRegistry
|
||||
public class ObjectFactory {
|
||||
|
||||
private final static QName _MenuNode_QNAME = new QName("", "menuNode");
|
||||
private final static QName _UtilityClass_QNAME = new QName("", "utilityClass");
|
||||
private final static QName _MenuTree_QNAME = new QName("", "menuTree");
|
||||
|
||||
/**
|
||||
* Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: ch.psi.sls.xasec.plot.menuconfig
|
||||
*
|
||||
*/
|
||||
public ObjectFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link MenuNodeType }
|
||||
*
|
||||
*/
|
||||
public MenuNodeType createMenuNodeType() {
|
||||
return new MenuNodeType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link MenuTreeType }
|
||||
*
|
||||
*/
|
||||
public MenuTreeType createMenuTreeType() {
|
||||
return new MenuTreeType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link UtilityClassType }
|
||||
*
|
||||
*/
|
||||
public UtilityClassType createUtilityClassType() {
|
||||
return new UtilityClassType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link JAXBElement }{@code <}{@link MenuNodeType }{@code >}}
|
||||
*
|
||||
*/
|
||||
@XmlElementDecl(namespace = "", name = "menuNode")
|
||||
public JAXBElement<MenuNodeType> createMenuNode(MenuNodeType value) {
|
||||
return new JAXBElement<MenuNodeType>(_MenuNode_QNAME, MenuNodeType.class, null, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link JAXBElement }{@code <}{@link UtilityClassType }{@code >}}
|
||||
*
|
||||
*/
|
||||
@XmlElementDecl(namespace = "", name = "utilityClass")
|
||||
public JAXBElement<UtilityClassType> createUtilityClass(UtilityClassType value) {
|
||||
return new JAXBElement<UtilityClassType>(_UtilityClass_QNAME, UtilityClassType.class, null, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link JAXBElement }{@code <}{@link MenuTreeType }{@code >}}
|
||||
*
|
||||
*/
|
||||
@XmlElementDecl(namespace = "", name = "menuTree")
|
||||
public JAXBElement<MenuTreeType> createMenuTree(MenuTreeType value) {
|
||||
return new JAXBElement<MenuTreeType>(_MenuTree_QNAME, MenuTreeType.class, null, value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
public interface PlugableUtil {
|
||||
public enum PlotType {oneDim, twoDim};
|
||||
public String getLabel();
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package ch.psi.plot.plot.done;
|
||||
import ch.psi.plot.util.PluginExecutionException;
|
||||
import ch.psi.plot.util.PlugableUtil;
|
||||
import ch.psi.plot.xy.LinePlot;
|
||||
|
||||
public interface PlugableUtilXY extends PlugableUtil{
|
||||
public void execute(LinePlot lineplot) throws PluginExecutionException;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
public class PluginExecutionException extends Throwable{
|
||||
|
||||
public PluginExecutionException() {
|
||||
}
|
||||
|
||||
public PluginExecutionException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
//
|
||||
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6
|
||||
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
|
||||
// Any modifications to this file will be lost upon recompilation of the source schema.
|
||||
// Generated on: 2009.12.07 at 03:37:39 PM CET
|
||||
//
|
||||
|
||||
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Java class for utilityClassType complex type.
|
||||
*
|
||||
* <p>The following schema fragment specifies the expected content contained within this class.
|
||||
*
|
||||
* <pre>
|
||||
* <complexType name="utilityClassType">
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "utilityClassType")
|
||||
public class UtilityClassType {
|
||||
|
||||
@XmlAttribute
|
||||
protected String name;
|
||||
|
||||
/**
|
||||
* Gets the value of the name property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the name property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public void setName(String value) {
|
||||
this.name = value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
/**
|
||||
* XY Point
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class XYPoint {
|
||||
|
||||
private Double x;
|
||||
private Double y;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
public XYPoint(double x, double y) {
|
||||
this.x = new Double(x);
|
||||
this.y = new Double(y);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the x
|
||||
*/
|
||||
public Double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param x the x to set
|
||||
*/
|
||||
public void setX(Double x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the y
|
||||
*/
|
||||
public Double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param y the y to set
|
||||
*/
|
||||
public void setY(Double y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
|
||||
jxb:version="2.0">
|
||||
|
||||
<xsd:element name="menuTree" type="menuTreeType"/>
|
||||
<xsd:complexType name="menuTreeType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="menuNode" type="menuNodeType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:element name="menuNode" type="menuNodeType"/>
|
||||
<xsd:complexType name="menuNodeType">
|
||||
<xsd:choice>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="submenu" type="menuNodeType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:element name="utilityClass" type="utilityClassType"/>
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:element name="utilityClass" type="utilityClassType"/>
|
||||
<xsd:complexType name="utilityClassType">
|
||||
<xsd:attribute name="name" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
</xsd:schema>
|
||||
@@ -1,36 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<menuTree>
|
||||
<menuNode name="Extrema">
|
||||
<submenu name="minimum">
|
||||
<utilityClass name="Mins" />
|
||||
</submenu>
|
||||
<submenu name="maximum">
|
||||
<utilityClass name="Maxs" />
|
||||
</submenu>
|
||||
</menuNode>
|
||||
<menuNode name="Integrate">
|
||||
<utilityClass name="Integral" />
|
||||
</menuNode>
|
||||
<menuNode name="Derive">
|
||||
<utilityClass name="Derivatives" />
|
||||
</menuNode>
|
||||
<menuNode name="Interpolate">
|
||||
<utilityClass name="Interpolation" />
|
||||
</menuNode>
|
||||
<menuNode name="FFT">
|
||||
<submenu name="Real">
|
||||
<utilityClass name="FFTReal" />
|
||||
</submenu>
|
||||
<submenu name="Imaginary">
|
||||
<utilityClass name="FFTImaginary" />
|
||||
</submenu>
|
||||
<submenu name="Power Spectrum">
|
||||
<utilityClass name="FFTPowerSpectrum" />
|
||||
</submenu>
|
||||
</menuNode>
|
||||
<menuNode name="XAS">
|
||||
<submenu name="chi">
|
||||
<utilityClass name="Chi" />
|
||||
</submenu>
|
||||
</menuNode>
|
||||
</menuTree>
|
||||
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<menuTree>
|
||||
<menuNode name="BaryCenter">
|
||||
<utilityClass name="BaryCenter"/>
|
||||
</menuNode>
|
||||
<menuNode name="Extrema">
|
||||
<submenu name="minimum">
|
||||
<utilityClass name="Min"/>
|
||||
</submenu>
|
||||
<submenu name="maximum">
|
||||
<utilityClass name="Max"/>
|
||||
</submenu>
|
||||
</menuNode>
|
||||
<menuNode name="Integrate">
|
||||
<submenu name="along X">
|
||||
<utilityClass name="IntegratedXValues"/>
|
||||
</submenu>
|
||||
<submenu name="along Y">
|
||||
<utilityClass name="IntegratedYValues"/>
|
||||
</submenu>
|
||||
</menuNode>
|
||||
|
||||
<menuNode name="Filter">
|
||||
<submenu name="Gauss">
|
||||
<submenu name="wide range">
|
||||
<utilityClass name="GaussFilter"/>
|
||||
</submenu>
|
||||
</submenu>
|
||||
<submenu name="Laplace">
|
||||
<utilityClass name="LaplaceFilter"/>
|
||||
</submenu>
|
||||
</menuNode>
|
||||
</menuTree>
|
||||
@@ -1,56 +0,0 @@
|
||||
package ch.psi.plot.util;
|
||||
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
import org.jfree.chart.ChartRenderingInfo;
|
||||
import org.jfree.chart.axis.ValueAxis;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.ui.RectangleEdge;
|
||||
|
||||
import ch.psi.plot.plot.done.XYPoint;
|
||||
|
||||
|
||||
/**
|
||||
* Helper class transforms window (frame) coordinates to chart coordinates.
|
||||
* @param mouseX, mouseY position of mouse click
|
||||
* @param xyPoint (useless so far)
|
||||
* @return true if mouse click was in Chart, false else (if click was in Legend area, etc.)
|
||||
*/
|
||||
|
||||
|
||||
public class CoordinateTransformer {
|
||||
|
||||
public static boolean chartCoordinates(ChartPanel chartPanel, int mouseX, int mouseY, XYPoint xyPoint) {
|
||||
//calculate x and y value in chart at mouse position
|
||||
Point2D p = chartPanel.translateScreenToJava2D(new Point(mouseX, mouseY));
|
||||
XYPlot plot = (XYPlot) chartPanel.getChart().getPlot();
|
||||
ChartRenderingInfo info = chartPanel.getChartRenderingInfo();
|
||||
Rectangle2D dataArea = info.getPlotInfo().getDataArea();
|
||||
|
||||
ValueAxis domainAxis = plot.getDomainAxis();
|
||||
RectangleEdge domainAxisEdge = plot.getDomainAxisEdge();
|
||||
ValueAxis rangeAxis = plot.getRangeAxis();
|
||||
RectangleEdge rangeAxisEdge = plot.getRangeAxisEdge();
|
||||
double chartX = domainAxis.java2DToValue(p.getX(), dataArea, domainAxisEdge);
|
||||
double chartY = rangeAxis.java2DToValue(p.getY(), dataArea,rangeAxisEdge);
|
||||
|
||||
// TODO need to remove this or make this as an return value
|
||||
xyPoint.setX(chartX);
|
||||
xyPoint.setY(chartY);
|
||||
|
||||
//Check if the click occurred in the plot region
|
||||
if (chartX < domainAxis.getLowerBound() || chartX > domainAxis.getUpperBound() ||
|
||||
chartY < rangeAxis.getLowerBound() || chartY > rangeAxis.getUpperBound()){
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,193 +0,0 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* GraphChoserFrame.java
|
||||
*
|
||||
* Created on Mar 16, 2010, 8:42:58 AM
|
||||
*/
|
||||
|
||||
package ch.psi.plot.plot.xy;
|
||||
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.data.xy.XYSeries;
|
||||
import org.jfree.data.xy.XYSeriesCollection;
|
||||
|
||||
import ch.psi.plot.plot.done.LinePlotData;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author studer_a1
|
||||
*/
|
||||
public class GraphChooserFrame extends javax.swing.JFrame {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
private XYPlot plot;
|
||||
private LinePlotData data;
|
||||
|
||||
|
||||
/** Creates new form GraphChoserFrame */
|
||||
public GraphChooserFrame(LinePlotData data, XYPlot plot) {
|
||||
this.plot = plot;
|
||||
this.data = data;
|
||||
//this.renderer = (XYLineAndShapeRenderer) plot.getRenderer();
|
||||
initComponents();
|
||||
initGraphPanels();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* inits the graph panel. For every series a GraphPropertiesPanel is created and added to the Panel
|
||||
*/
|
||||
public void initGraphPanels(){
|
||||
|
||||
GridBagConstraints gbc = new GridBagConstraints();
|
||||
gbc.weightx = 1.0;
|
||||
gbc.fill = GridBagConstraints.HORIZONTAL;
|
||||
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
||||
|
||||
JPanel graphOptionsContainerPanel = new JPanel(new GridBagLayout());
|
||||
graphOptionScrollPane.setViewportView(graphOptionsContainerPanel);
|
||||
|
||||
int seriesNumber = 0;
|
||||
for (Object xySeriesObject: ((XYSeriesCollection) data.getData()).getSeries()) {
|
||||
XYSeries xySeries = (XYSeries) xySeriesObject;
|
||||
GraphPropertiesPanel gpPanel = new GraphPropertiesPanel(plot, xySeries, seriesNumber);
|
||||
graphOptionsContainerPanel.add(gpPanel, gbc);
|
||||
seriesNumber++;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/** This method is called from within the constructor to
|
||||
* initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is
|
||||
* always regenerated by the Form Editor.
|
||||
*/
|
||||
private void initComponents() {
|
||||
|
||||
graphOptionScrollPane = new javax.swing.JScrollPane();
|
||||
jPanel1 = new javax.swing.JPanel();
|
||||
nameLabel = new javax.swing.JLabel();
|
||||
colorLabel = new javax.swing.JLabel();
|
||||
plotLabel = new javax.swing.JLabel();
|
||||
singleLabel = new javax.swing.JLabel();
|
||||
logLabel = new javax.swing.JLabel();
|
||||
minLabel = new javax.swing.JLabel();
|
||||
maxLabel = new javax.swing.JLabel();
|
||||
rangeLabel = new javax.swing.JLabel();
|
||||
|
||||
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
|
||||
|
||||
nameLabel.setText("Name");
|
||||
|
||||
colorLabel.setText("Color");
|
||||
|
||||
plotLabel.setText("Plot");
|
||||
|
||||
singleLabel.setText("Single");
|
||||
|
||||
logLabel.setText("Log");
|
||||
|
||||
minLabel.setText("Min");
|
||||
|
||||
maxLabel.setText("Max");
|
||||
|
||||
rangeLabel.setText("range");
|
||||
|
||||
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
|
||||
jPanel1.setLayout(jPanel1Layout);
|
||||
jPanel1Layout.setHorizontalGroup(
|
||||
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(nameLabel)
|
||||
.addGap(123, 123, 123)
|
||||
.addComponent(colorLabel)
|
||||
.addGap(32, 32, 32)
|
||||
.addComponent(plotLabel)
|
||||
.addGap(18, 18, 18)
|
||||
.addComponent(singleLabel)
|
||||
.addGap(18, 18, 18)
|
||||
.addComponent(logLabel)
|
||||
.addGap(18, 18, 18)
|
||||
.addComponent(rangeLabel)
|
||||
.addGap(55, 55, 55)
|
||||
.addComponent(minLabel)
|
||||
.addGap(73, 73, 73)
|
||||
.addComponent(maxLabel)
|
||||
.addContainerGap(119, Short.MAX_VALUE))
|
||||
);
|
||||
jPanel1Layout.setVerticalGroup(
|
||||
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(nameLabel)
|
||||
.addComponent(logLabel)
|
||||
.addComponent(singleLabel)
|
||||
.addComponent(plotLabel)
|
||||
.addComponent(colorLabel)
|
||||
.addComponent(rangeLabel)
|
||||
.addComponent(minLabel)
|
||||
.addComponent(maxLabel))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||
getContentPane().setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(39, 39, 39)
|
||||
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(47, Short.MAX_VALUE))
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(36, 36, 36)
|
||||
.addComponent(graphOptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 719, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(36, Short.MAX_VALUE)))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(249, Short.MAX_VALUE))
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(59, 59, 59)
|
||||
.addComponent(graphOptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 182, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(59, Short.MAX_VALUE)))
|
||||
);
|
||||
|
||||
pack();
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JLabel colorLabel;
|
||||
private javax.swing.JScrollPane graphOptionScrollPane;
|
||||
private javax.swing.JPanel jPanel1;
|
||||
private javax.swing.JLabel logLabel;
|
||||
private javax.swing.JLabel maxLabel;
|
||||
private javax.swing.JLabel minLabel;
|
||||
private javax.swing.JLabel nameLabel;
|
||||
private javax.swing.JLabel plotLabel;
|
||||
private javax.swing.JLabel rangeLabel;
|
||||
private javax.swing.JLabel singleLabel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
}
|
||||
@@ -1,358 +0,0 @@
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
/*
|
||||
* GraphPropertiesPanel.java
|
||||
*
|
||||
* Created on Mar 16, 2010, 8:30:56 AM
|
||||
*/
|
||||
|
||||
package ch.psi.plot.plot.xy;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Paint;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jfree.chart.axis.LogarithmicAxis;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
|
||||
import org.jfree.data.xy.XYSeries;
|
||||
import org.jfree.data.xy.XYSeriesCollection;
|
||||
|
||||
import ch.psi.plot.plot.done.LinePlot;
|
||||
import ch.psi.plot.plot.done.LinePlotData;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author studer_a1
|
||||
*/
|
||||
public class GraphPropertiesPanel extends javax.swing.JPanel {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(GraphPropertiesPanel.class.getName());
|
||||
|
||||
private XYSeries xySeries;
|
||||
private XYLineAndShapeRenderer renderer;
|
||||
private XYPlot plot;
|
||||
private int seriesNumber;
|
||||
private int xyDataSetOffset;
|
||||
LinePlot singlePlot = null;
|
||||
|
||||
/** Creates new form GraphPropertiesPanel */
|
||||
public GraphPropertiesPanel(XYPlot plot, XYSeries xySeries, int seriesNumber) {
|
||||
this.plot = plot;
|
||||
this.xySeries = xySeries;
|
||||
this.renderer = (XYLineAndShapeRenderer) plot.getRenderer();
|
||||
this.seriesNumber = seriesNumber;
|
||||
this.xyDataSetOffset = plot.getDatasetCount();
|
||||
|
||||
initComponents();
|
||||
initFields();
|
||||
}
|
||||
|
||||
public void initFields(){
|
||||
nameLabel.setText(xySeries.getKey().toString());
|
||||
colorLabel.setOpaque(true);
|
||||
colorLabel.setBackground((Color) renderer.getSeriesPaint(seriesNumber));
|
||||
plotCheckBox.setSelected(renderer.isSeriesVisible(seriesNumber));
|
||||
singleCheckBox.setSelected(false);
|
||||
logCheckBox.setSelected(false);
|
||||
minTextField.setText(new Double(xySeries.getMinY()).toString());
|
||||
maxTextField.setText(new Double(xySeries.getMaxY()).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a single plot out of an xySeries, destroys the plot if singleCheckBox.isSelected() is false
|
||||
*/
|
||||
public void createSinglePlotUsingSeries(){
|
||||
LinePlotData d = new LinePlotData();
|
||||
((XYSeriesCollection) d.getData()).addSeries(xySeries);
|
||||
//use the same paint as in the original
|
||||
Paint paint = renderer.getSeriesPaint(seriesNumber);
|
||||
singlePlot = new LinePlot(xySeries.getKey().toString(), d);
|
||||
// there is only one series in this plot, so we choose index 0 to assign paint
|
||||
singlePlot.getChartPanel().getChart().getXYPlot().getRenderer().setSeriesPaint(0, paint);
|
||||
singlePlot.plot(false);
|
||||
//check whether we want a log scale
|
||||
if(logCheckBox.isSelected()){
|
||||
final NumberAxis rangeAxis = new LogarithmicAxis("Log");
|
||||
((LogarithmicAxis)rangeAxis).setAllowNegativesFlag(true);
|
||||
singlePlot.getChartPanel().getChart().getXYPlot().setRangeAxis(rangeAxis);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a dataset with a single xySerie
|
||||
* @return
|
||||
*/
|
||||
public XYSeriesCollection wrapSeriesInDataSet(){
|
||||
XYSeriesCollection wrappedSeries = new XYSeriesCollection();
|
||||
wrappedSeries.addSeries(xySeries);
|
||||
return wrappedSeries;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* creates an additional range (y) scale for a series (identified by its name)
|
||||
* lowerbound and upperbound are taken from user input.
|
||||
* @param name
|
||||
* @param lowerBound
|
||||
* @param upperBound
|
||||
* @return
|
||||
*/
|
||||
public NumberAxis createIndivdualRangeScale(String name, double lowerBound, double upperBound){
|
||||
NumberAxis individualRangeScale = new NumberAxis(name);
|
||||
individualRangeScale.setLowerBound(lowerBound);
|
||||
individualRangeScale.setUpperBound(upperBound);
|
||||
return individualRangeScale;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* makes the individual range scale visible
|
||||
*/
|
||||
public void applyIndividualRangeScale(){
|
||||
double lowerBound = 0.0;
|
||||
double upperBound = 0.0;
|
||||
try {
|
||||
lowerBound = Double.parseDouble(minTextField.getText());
|
||||
upperBound = Double.parseDouble(maxTextField.getText());
|
||||
} catch (NumberFormatException e) {
|
||||
logger.warning("invalid bounds");
|
||||
return;
|
||||
}
|
||||
|
||||
//create new dataset and axis
|
||||
NumberAxis individualRangeScale = createIndivdualRangeScale(
|
||||
xySeries.getKey().toString(),lowerBound, upperBound);
|
||||
individualRangeScale.setLabelPaint(renderer.getSeriesPaint(seriesNumber));
|
||||
individualRangeScale.setTickLabelPaint(renderer.getSeriesPaint(seriesNumber));
|
||||
individualRangeScale.setAxisLinePaint(renderer.getSeriesPaint(seriesNumber));
|
||||
plot.setRangeAxis(seriesNumber + xyDataSetOffset, individualRangeScale);
|
||||
plot.setDataset(seriesNumber + xyDataSetOffset, wrapSeriesInDataSet());
|
||||
plot.mapDatasetToRangeAxis(seriesNumber + xyDataSetOffset, seriesNumber + xyDataSetOffset);
|
||||
XYLineAndShapeRenderer individualRenderer = new XYLineAndShapeRenderer();
|
||||
//StandardXYItemRenderer individualRenderer = new StandardXYItemRenderer();
|
||||
individualRenderer.setSeriesPaint(0, renderer.getSeriesPaint(seriesNumber));
|
||||
individualRenderer.setSeriesShape(0, renderer.getSeriesShape(seriesNumber));
|
||||
plot.setRenderer(seriesNumber + xyDataSetOffset, individualRenderer);
|
||||
|
||||
//set original series invisible
|
||||
renderer.setSeriesVisible(seriesNumber, false);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* removes the individual range scale
|
||||
*/
|
||||
public void removeIndividualRangeScale(){
|
||||
//we remove axis and dataset and renderer
|
||||
plot.setRangeAxis(seriesNumber + xyDataSetOffset, null);
|
||||
plot.setDataset(seriesNumber + xyDataSetOffset, null);
|
||||
plot.setRenderer(seriesNumber + xyDataSetOffset, null);
|
||||
if(plotCheckBox.isSelected()){
|
||||
renderer.setSeriesVisible(seriesNumber, true);
|
||||
//renderer.setSer
|
||||
}
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
|
||||
nameLabel = new javax.swing.JLabel();
|
||||
colorLabel = new javax.swing.JLabel();
|
||||
plotCheckBox = new javax.swing.JCheckBox();
|
||||
singleCheckBox = new javax.swing.JButton();
|
||||
logCheckBox = new javax.swing.JCheckBox();
|
||||
minTextField = new javax.swing.JTextField();
|
||||
maxTextField = new javax.swing.JTextField();
|
||||
individualRangeScaleCheckBox = new javax.swing.JCheckBox();
|
||||
|
||||
singleCheckBox.setText("Show");
|
||||
nameLabel.setText("name");
|
||||
|
||||
colorLabel.setText(" ");
|
||||
|
||||
plotCheckBox.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
plotCheckBoxActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
singleCheckBox.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
createSinglePlotUsingSeries();
|
||||
}
|
||||
});
|
||||
|
||||
logCheckBox.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
logCheckBoxActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
minTextField.setText("min");
|
||||
minTextField.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
minTextFieldActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
maxTextField.setText("max");
|
||||
maxTextField.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
maxTextFieldActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
individualRangeScaleCheckBox.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
individualRangeScaleCheckBoxActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(nameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 103, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(58, 58, 58)
|
||||
.addComponent(colorLabel)
|
||||
.addGap(50, 50, 50)
|
||||
.addComponent(plotCheckBox)
|
||||
.addGap(30, 30, 30)
|
||||
.addComponent(singleCheckBox)
|
||||
.addGap(30, 30, 30)
|
||||
.addComponent(logCheckBox)
|
||||
.addGap(28, 28, 28)
|
||||
.addComponent(individualRangeScaleCheckBox)
|
||||
.addGap(49, 49, 49)
|
||||
.addComponent(minTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 83, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(18, 18, 18)
|
||||
.addComponent(maxTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 86, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(106, Short.MAX_VALUE))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(logCheckBox)
|
||||
.addComponent(singleCheckBox)
|
||||
.addComponent(plotCheckBox)
|
||||
.addComponent(nameLabel)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(minTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(maxTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(6, 6, 6)
|
||||
.addComponent(colorLabel))
|
||||
.addComponent(individualRangeScaleCheckBox))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void plotCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_plotCheckBoxActionPerformed
|
||||
if(plotCheckBox.isSelected()){
|
||||
//if an individual scale exists, set this one visible
|
||||
//if(plot.getRenderer(seriesNumber + xyDataSetOffset) != null){
|
||||
if(individualRangeScaleCheckBox.isSelected()){
|
||||
//The following should always be true, if not, there is a (logical) problem
|
||||
if(plot.getRenderer(seriesNumber + xyDataSetOffset) != null){
|
||||
plot.getRenderer(seriesNumber + xyDataSetOffset).setSeriesVisible(0, true);
|
||||
}
|
||||
}
|
||||
else{
|
||||
//set the other one invisible
|
||||
renderer.setSeriesVisible(seriesNumber, true);
|
||||
}
|
||||
}
|
||||
else{
|
||||
//set individual range dataset and series invisible (if exists)
|
||||
renderer.setSeriesVisible(seriesNumber, false);
|
||||
if(plot.getRenderer(seriesNumber + xyDataSetOffset) != null){
|
||||
plot.getRenderer(seriesNumber + xyDataSetOffset).setSeriesVisible(0, false);
|
||||
}
|
||||
|
||||
}
|
||||
}//GEN-LAST:event_plotCheckBoxActionPerformed
|
||||
|
||||
|
||||
private void logCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_logCheckBoxActionPerformed
|
||||
// TODO add your handling code here:
|
||||
}//GEN-LAST:event_logCheckBoxActionPerformed
|
||||
|
||||
private void minTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_minTextFieldActionPerformed
|
||||
double lowerBound = 0.0;
|
||||
|
||||
if(individualRangeScaleCheckBox.isSelected()){
|
||||
if(plot.getRangeAxis(seriesNumber + xyDataSetOffset) != null){
|
||||
try {
|
||||
lowerBound = Double.parseDouble(minTextField.getText());
|
||||
} catch (NumberFormatException e) {
|
||||
logger.warning("invalid lower bound");
|
||||
return;
|
||||
}
|
||||
if(lowerBound >= plot.getRangeAxis(seriesNumber + xyDataSetOffset).getUpperBound()){
|
||||
logger.warning("lower bound >= upper bound");
|
||||
}
|
||||
else{
|
||||
plot.getRangeAxis(seriesNumber + xyDataSetOffset).setLowerBound(lowerBound);
|
||||
}
|
||||
}
|
||||
}
|
||||
}//GEN-LAST:event_minTextFieldActionPerformed
|
||||
|
||||
private void maxTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_maxTextFieldActionPerformed
|
||||
double upperBound = 0.0;
|
||||
|
||||
if(individualRangeScaleCheckBox.isSelected()){
|
||||
if(plot.getRangeAxis(seriesNumber + xyDataSetOffset) != null){
|
||||
try {
|
||||
upperBound = Double.parseDouble(maxTextField.getText());
|
||||
} catch (NumberFormatException e) {
|
||||
logger.warning("invalid upper bound");
|
||||
return;
|
||||
}
|
||||
if(upperBound <= plot.getRangeAxis(seriesNumber + xyDataSetOffset).getLowerBound()){
|
||||
logger.warning("upper bound <= lower bound");
|
||||
}
|
||||
else{
|
||||
plot.getRangeAxis(seriesNumber + xyDataSetOffset).setUpperBound(upperBound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}//GEN-LAST:event_maxTextFieldActionPerformed
|
||||
|
||||
private void individualRangeScaleCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_individualRangeScaleCheckBoxActionPerformed
|
||||
if(individualRangeScaleCheckBox.isSelected()){
|
||||
applyIndividualRangeScale();
|
||||
}
|
||||
else{
|
||||
removeIndividualRangeScale();
|
||||
}
|
||||
}//GEN-LAST:event_individualRangeScaleCheckBoxActionPerformed
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JLabel colorLabel;
|
||||
private javax.swing.JCheckBox individualRangeScaleCheckBox;
|
||||
private javax.swing.JCheckBox logCheckBox;
|
||||
private javax.swing.JTextField maxTextField;
|
||||
private javax.swing.JTextField minTextField;
|
||||
private javax.swing.JLabel nameLabel;
|
||||
private javax.swing.JCheckBox plotCheckBox;
|
||||
private javax.swing.JButton singleCheckBox;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.plot.xy;
|
||||
|
||||
/**
|
||||
* Bean holding information of an LinePlot interval
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class Interval {
|
||||
|
||||
private Double leftBorder;
|
||||
private Double rightBorder;
|
||||
|
||||
/**
|
||||
* Constructor - Default constructor
|
||||
* @param leftBorder
|
||||
* @param rightBorder
|
||||
*/
|
||||
public Interval(Double leftBorder, Double rightBorder) {
|
||||
this.leftBorder = leftBorder;
|
||||
this.rightBorder = rightBorder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the leftBorder
|
||||
*/
|
||||
public Double getLeftBorder() {
|
||||
return leftBorder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param leftBorder the leftBorder to set
|
||||
*/
|
||||
public void setLeftBorder(Double leftBorder) {
|
||||
this.leftBorder = leftBorder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the rightBorder
|
||||
*/
|
||||
public Double getRightBorder() {
|
||||
return rightBorder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rightBorder the rightBorder to set
|
||||
*/
|
||||
public void setRightBorder(Double rightBorder) {
|
||||
this.rightBorder = rightBorder;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.plot.xy;
|
||||
|
||||
/**
|
||||
* Bean for storing a LinePlot marker information
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class Marker {
|
||||
|
||||
/**
|
||||
* Label of the marker
|
||||
*/
|
||||
private String label;
|
||||
/**
|
||||
* X coordinate of the marker
|
||||
*/
|
||||
private Double x;
|
||||
/**
|
||||
* Y coordinate of the marker
|
||||
*/
|
||||
private Double y;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param label
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
public Marker(String label, Double x, Double y) {
|
||||
this.label = label;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the label
|
||||
*/
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param label the label to set
|
||||
*/
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the x
|
||||
*/
|
||||
public Double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param x the x to set
|
||||
*/
|
||||
public void setX(Double x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the y
|
||||
*/
|
||||
public Double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param y the y to set
|
||||
*/
|
||||
public void setY(Double y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import ch.psi.plot.util.XYPoint;
|
||||
|
||||
public class ExtremaFinder {
|
||||
|
||||
private static Logger logger = Logger.getLogger(ExtremaFinder.class.getName());
|
||||
|
||||
private enum Extrema {MIN, MAX, MIN_MAX_VALUE};
|
||||
|
||||
|
||||
/**
|
||||
* Get the point of the minimum value
|
||||
* @param plotData
|
||||
* @param lowerLeft
|
||||
* @param upperRight
|
||||
* @return
|
||||
*/
|
||||
public static XYPoint getMinimum(JFreeMatrixPlotData plotData, XYPoint lowerLeft, XYPoint upperRight){
|
||||
return(findExtrema(plotData, lowerLeft, upperRight, Extrema.MIN, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the point of the maximum value
|
||||
* @param plotData
|
||||
* @param lowerLeft
|
||||
* @param upperRight
|
||||
* @return
|
||||
*/
|
||||
public static XYPoint getMaximum(JFreeMatrixPlotData plotData, XYPoint lowerLeft, XYPoint upperRight){
|
||||
return(findExtrema(plotData, lowerLeft, upperRight, Extrema.MAX, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lowest and highest value of the data in the region
|
||||
*
|
||||
* TODO XYPoint need to be removed !!!!!
|
||||
*
|
||||
* @param plotData
|
||||
* @param lowerLeft
|
||||
* @param upperRight
|
||||
* @return
|
||||
*/
|
||||
public static XYPoint getMinMaxValue(JFreeMatrixPlotData plotData, XYPoint lowerLeft, XYPoint upperRight){
|
||||
return(findExtrema(plotData, lowerLeft, upperRight, Extrema.MIN_MAX_VALUE, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find extremas in the specified region
|
||||
* @param plotData
|
||||
* @param lowerLeft
|
||||
* @param upperRight
|
||||
* @param e
|
||||
* @return
|
||||
*/
|
||||
private static XYPoint findExtrema(JFreeMatrixPlotData plotData, XYPoint lowerLeft, XYPoint upperRight, Extrema e, boolean binned){
|
||||
|
||||
double x; double y; double z;
|
||||
double zmin = Double.POSITIVE_INFINITY;
|
||||
double zmax = Double.NEGATIVE_INFINITY;
|
||||
double minLocationX = 0.0;
|
||||
double minLocationY = 0.0;
|
||||
double maxLocationX = 0.0;
|
||||
double maxLocationY = 0.0;
|
||||
|
||||
|
||||
x = lowerLeft.getX();
|
||||
y = lowerLeft.getY();
|
||||
|
||||
if (binned){
|
||||
try{
|
||||
x = plotData.getXValueBinned(x);
|
||||
y = plotData.getYValueBinned(y);
|
||||
}
|
||||
catch(Exception exc){
|
||||
logger.fine(exc.getMessage() + " Start values couldn't be binned");
|
||||
}
|
||||
}
|
||||
|
||||
while(x < upperRight.getX()){
|
||||
while(y < upperRight.getY()){
|
||||
try{
|
||||
z = plotData.getValue(x, y);
|
||||
//we discard negative infinity, since this is related to init values
|
||||
if (z < zmin && !(z == Double.NEGATIVE_INFINITY)){
|
||||
zmin = z;
|
||||
minLocationX = x;
|
||||
minLocationY = y;
|
||||
}
|
||||
if (z > zmax && !(z == Double.POSITIVE_INFINITY)){
|
||||
zmax = z;
|
||||
maxLocationX = x;
|
||||
maxLocationY = y;
|
||||
}
|
||||
}
|
||||
catch(Exception exception){
|
||||
logger.severe(exception.getMessage());
|
||||
}
|
||||
|
||||
y = y + plotData.getMetadata().getBinWidthY();
|
||||
}
|
||||
y = lowerLeft.getY();
|
||||
x = x + plotData.getMetadata().getBinWidthX();
|
||||
}
|
||||
|
||||
XYPoint extrema = null;
|
||||
|
||||
if(binned){
|
||||
try{
|
||||
minLocationX = plotData.getXValueBinned(minLocationX);
|
||||
minLocationY = plotData.getYValueBinned(minLocationY);
|
||||
|
||||
maxLocationX = plotData.getXValueBinned(maxLocationX);
|
||||
maxLocationY = plotData.getYValueBinned(maxLocationY);
|
||||
}
|
||||
catch(Exception exc){
|
||||
logger.fine(exc.getMessage() + " Extrema couldn't be binned");
|
||||
}
|
||||
}
|
||||
|
||||
if(e.equals(Extrema.MIN)){
|
||||
extrema = new XYPoint(minLocationX, minLocationY);
|
||||
}
|
||||
else if(e.equals(Extrema.MAX)){
|
||||
extrema = new XYPoint(maxLocationX, maxLocationY);
|
||||
}
|
||||
else if(e.equals(Extrema.MIN_MAX_VALUE)){
|
||||
extrema = new XYPoint(zmin, zmax);
|
||||
}
|
||||
|
||||
return(extrema);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
public interface IndexOutOfBoundListener {
|
||||
|
||||
/**
|
||||
* If the initially allocated matrix is too small, we need to reallocate
|
||||
* a new MatrixSeries and then tell matrix plot to replot
|
||||
*/
|
||||
public void redraw();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,130 +0,0 @@
|
||||
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import org.jfree.data.xy.XYZDataset;
|
||||
|
||||
import ch.psi.plot.PlotData;
|
||||
|
||||
public interface JFreeMatrixPlotData extends PlotData{
|
||||
|
||||
public enum DataType {MATRIX, PIXEL};
|
||||
|
||||
/**
|
||||
* Get data object
|
||||
* @return
|
||||
*/
|
||||
public XYZDataset getData();
|
||||
|
||||
/**
|
||||
* Get metadata related to the data
|
||||
* @return
|
||||
*/
|
||||
public JFreeMatrixPlotMetadata getMetadata();
|
||||
|
||||
/**
|
||||
* Set metadata related to the data
|
||||
* @param metadata
|
||||
*/
|
||||
public void setMetadata(JFreeMatrixPlotMetadata metadata);
|
||||
|
||||
/**
|
||||
* Add data to data object
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*/
|
||||
public void addData(Number x, Number y, Number z);
|
||||
|
||||
/**
|
||||
* Add data binned to data object (x and y positions are modified such that
|
||||
* they lie in the middle of their respective bin) |--*--------| -> |-----*-----|
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*/
|
||||
public void addDataBinned(Number x, Number y, Number z);
|
||||
|
||||
/**
|
||||
* Add data to data object, position in array (matrix) is independent of x, y value.
|
||||
* @param i Corresponds to y position
|
||||
* @param j Corresponds to x position
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*/
|
||||
public void addData(int i, int j, Number x, Number y, Number z);
|
||||
|
||||
/**
|
||||
* Get value of coordinates x / y
|
||||
* @param x
|
||||
* @param y
|
||||
* @return
|
||||
*/
|
||||
public double getValue(double x, double y);
|
||||
|
||||
/**
|
||||
* Get value of bin i, j (i row, j column, starting point is lower left
|
||||
* @param i
|
||||
* @param j
|
||||
* @return
|
||||
*/
|
||||
public double getValue(int i, int j);
|
||||
|
||||
/**
|
||||
* Set value at position i/j (i row, j column)
|
||||
* @param x
|
||||
* @param y
|
||||
* @param value
|
||||
*/
|
||||
public void setValue(int i, int j, double value);
|
||||
|
||||
|
||||
/**
|
||||
* Returns value X according to array position (i row, j column)
|
||||
* @param x
|
||||
* @param y
|
||||
* @return
|
||||
*/
|
||||
public double getXValue(int i, int j);
|
||||
|
||||
/**
|
||||
* Returns the Y according to array position (i row, j column)
|
||||
* @param x
|
||||
* @param y
|
||||
* @return
|
||||
*/
|
||||
public double getYValue(int i, int j);
|
||||
|
||||
/**
|
||||
* returns the X value of data
|
||||
* @param x
|
||||
* @return
|
||||
*/
|
||||
public double getXValueBinned(double x);
|
||||
|
||||
/**
|
||||
* returns the Y value of data
|
||||
* @param y
|
||||
* @return
|
||||
*/
|
||||
public double getYValueBinned(double y);
|
||||
|
||||
/**
|
||||
* Returns the bin number in which x lies
|
||||
* @param x
|
||||
* @return
|
||||
*/
|
||||
public int getXBin(double x);
|
||||
|
||||
/**
|
||||
* Returns the bin number in which y lies
|
||||
* @param y
|
||||
* @return
|
||||
*/
|
||||
public int getYBin(double y);
|
||||
|
||||
|
||||
public double[] getDataArray();
|
||||
public int getXSize();
|
||||
public int getYSize();
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
/**
|
||||
* Bean class to holding metadata for matrix plots
|
||||
*/
|
||||
public class JFreeMatrixPlotMetadata {
|
||||
|
||||
private double minX;
|
||||
private double maxX;
|
||||
private int numberOfBinsX;
|
||||
private double minY;
|
||||
private double maxY;
|
||||
private int numberOfBinsY;
|
||||
private double minValue;
|
||||
private double maxValue;
|
||||
private String xAxisLabel = "X";
|
||||
private String yAxisLabel = "Y";
|
||||
|
||||
/**
|
||||
* Get the minimum value of the x-axis
|
||||
* @return
|
||||
*/
|
||||
public double getMinX() {
|
||||
return minX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum value of the x-axis
|
||||
* @param minX
|
||||
*/
|
||||
public void setMinX(double minX) {
|
||||
this.minX = minX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum value of the x-axis
|
||||
* @return
|
||||
*/
|
||||
public double getMaxX() {
|
||||
return maxX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum value of the x-axis
|
||||
* @param maxX
|
||||
*/
|
||||
public void setMaxX(double maxX) {
|
||||
this.maxX = maxX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of bins of the x-axis
|
||||
* @return
|
||||
*/
|
||||
public int getNumberOfBinsX() {
|
||||
return numberOfBinsX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of bins of the x-axis
|
||||
* @param numberOfBinsX
|
||||
*/
|
||||
public void setNumberOfBinsX(int numberOfBinsX) {
|
||||
this.numberOfBinsX = numberOfBinsX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum value of the y-axis
|
||||
* @return
|
||||
*/
|
||||
public double getMinY() {
|
||||
return minY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum value of the y-axis
|
||||
* @param minY
|
||||
*/
|
||||
public void setMinY(double minY) {
|
||||
this.minY = minY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum value of the y-axis
|
||||
* @return
|
||||
*/
|
||||
public double getMaxY() {
|
||||
return maxY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum value of the y-axis
|
||||
* @param maxY
|
||||
*/
|
||||
public void setMaxY(double maxY) {
|
||||
this.maxY = maxY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of bins of the y-axis
|
||||
* @return
|
||||
*/
|
||||
public int getNumberOfBinsY() {
|
||||
return numberOfBinsY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of bins of the y-axis
|
||||
* @param numberOfBinsY
|
||||
*/
|
||||
public void setNumberOfBinsY(int numberOfBinsY) {
|
||||
this.numberOfBinsY = numberOfBinsY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum value of the value
|
||||
* @return
|
||||
*/
|
||||
public double getMinValue() {
|
||||
return minValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum value of the value
|
||||
* @param minValue
|
||||
*/
|
||||
public void setMinValue(double minValue) {
|
||||
this.minValue = minValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum value of the value
|
||||
* @return
|
||||
*/
|
||||
public double getMaxValue() {
|
||||
return maxValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum value of the value
|
||||
* @param maxValue
|
||||
*/
|
||||
public void setMaxValue(double maxValue) {
|
||||
this.maxValue = maxValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bin width of the x-axis
|
||||
* maxX and minX values are the values in the middle of the first and last bin
|
||||
* therefore numberofXBins is reduced by 1.
|
||||
* @return
|
||||
*/
|
||||
public double getBinWidthX(){
|
||||
return (maxX - minX)/(double) (numberOfBinsX - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bin width of the y-axis
|
||||
* maxY and minY values are the values in the middle of the first and last bin
|
||||
* therefore numberofYBins is reduced by 1.
|
||||
* @return
|
||||
*/
|
||||
public double getBinWidthY(){
|
||||
return (maxY - minY)/(double) (numberOfBinsY - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the x-axis label
|
||||
* @return
|
||||
*/
|
||||
public String getxAxisLabel() {
|
||||
return xAxisLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the x-axis label
|
||||
* @param xAxisLabel
|
||||
*/
|
||||
public void setxAxisLabel(String xAxisLabel) {
|
||||
this.xAxisLabel = xAxisLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the y-axis label
|
||||
* @return
|
||||
*/
|
||||
public String getyAxisLabel() {
|
||||
return yAxisLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the y-axis label
|
||||
* @param yAxisLabel
|
||||
*/
|
||||
public void setyAxisLabel(String yAxisLabel) {
|
||||
this.yAxisLabel = yAxisLabel;
|
||||
}
|
||||
}
|
||||
@@ -1,230 +0,0 @@
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jfree.data.xy.DefaultXYZDataset;
|
||||
import org.jfree.data.xy.XYZDataset;
|
||||
|
||||
/**
|
||||
* PlotData implementation optimized for matrix data.
|
||||
* ...
|
||||
*/
|
||||
public class MatrixPlotData implements JFreeMatrixPlotData{
|
||||
|
||||
private static Logger logger = Logger.getLogger(MatrixPlotData.class.getName());
|
||||
|
||||
private int numberOfXBins;
|
||||
private int numberOfYBins;
|
||||
|
||||
private double[][] dataArray;
|
||||
Boolean[] occupiedBin;
|
||||
|
||||
private XYZDataset data;
|
||||
private JFreeMatrixPlotMetadata metadata;
|
||||
|
||||
|
||||
public MatrixPlotData(){
|
||||
this(new JFreeMatrixPlotMetadata());
|
||||
}
|
||||
|
||||
|
||||
public MatrixPlotData(JFreeMatrixPlotMetadata metadata) {
|
||||
|
||||
this.metadata = metadata;
|
||||
|
||||
numberOfXBins = metadata.getNumberOfBinsX();
|
||||
numberOfYBins = metadata.getNumberOfBinsY();
|
||||
|
||||
int arraylength = numberOfXBins*numberOfYBins;
|
||||
double[] xvalues = new double[arraylength];
|
||||
double[] yvalues = new double[arraylength];
|
||||
double[] zvalues = new double[arraylength];
|
||||
|
||||
Arrays.fill(xvalues, Double.NEGATIVE_INFINITY);
|
||||
Arrays.fill(yvalues, Double.NEGATIVE_INFINITY);
|
||||
Arrays.fill(zvalues, Double.NEGATIVE_INFINITY);
|
||||
logger.fine("Number of X values: "+numberOfXBins+" Number of Y values: "+numberOfYBins+" Array size: "+arraylength);
|
||||
|
||||
dataArray = new double[][] {xvalues, yvalues, zvalues};
|
||||
|
||||
occupiedBin = new Boolean[arraylength];
|
||||
Arrays.fill(occupiedBin, false);
|
||||
|
||||
//Create the XYDataset (org.jfree), not to be confused with the ch.psi dataSet)
|
||||
data = new DefaultXYZDataset();
|
||||
((DefaultXYZDataset)data).addSeries("Series Name" , dataArray);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addData(Number x, Number y, Number z) {
|
||||
int xBin = getXBin(x.doubleValue());
|
||||
int yBin = getYBin(y.doubleValue());
|
||||
|
||||
//x Value is column, y value is row
|
||||
dataArray[0][yBin * numberOfXBins + xBin] = x.doubleValue();
|
||||
dataArray[1][yBin * numberOfXBins + xBin] = y.doubleValue();
|
||||
dataArray[2][yBin * numberOfXBins + xBin] = z.doubleValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDataBinned(Number x, Number y, Number z) {
|
||||
int xBin = getXBin(x.doubleValue());
|
||||
int yBin = getYBin(y.doubleValue());
|
||||
|
||||
dataArray[0][yBin * numberOfXBins + xBin] = getXValueBinned(xBin, yBin);
|
||||
dataArray[1][yBin * numberOfXBins + xBin] = getYValueBinned(xBin, yBin);
|
||||
dataArray[2][yBin * numberOfXBins + xBin] = z.doubleValue();
|
||||
|
||||
if (occupiedBin[yBin * numberOfXBins + xBin]){
|
||||
logger.finest("Bin (" + xBin + " " + yBin + ") is allready filled" );
|
||||
}
|
||||
else{
|
||||
occupiedBin[yBin * numberOfXBins + xBin] = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Not part of interface
|
||||
public double getXValueBinned(int i, int j){
|
||||
return metadata.getMinX() + i*metadata.getBinWidthX();
|
||||
}
|
||||
|
||||
//Not part of interface
|
||||
public double getYValueBinned(int i, int j){
|
||||
return metadata.getMinY() + j*metadata.getBinWidthY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addData(int i, int j, Number x, Number y, Number z) {
|
||||
//The array is filled 'horizontally' (row (=yAxis) kept constant, columns++ ,
|
||||
//then row++ etc)
|
||||
|
||||
dataArray[0][i * numberOfXBins + j] = x.doubleValue();
|
||||
dataArray[1][i * numberOfXBins + j] = y.doubleValue();
|
||||
dataArray[2][i * numberOfXBins + j] = z.doubleValue();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public XYZDataset getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JFreeMatrixPlotMetadata getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMetadata(JFreeMatrixPlotMetadata metadata) {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getXValue(int i, int j){
|
||||
return dataArray[0][i * numberOfXBins + j];
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getYValue(int i, int j){
|
||||
return dataArray[1][i * numberOfXBins + j];
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getXValueBinned(double x){
|
||||
return metadata.getMinX() + getXBin(x)*metadata.getBinWidthX();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getYValueBinned(double y){
|
||||
return metadata.getMinY() + getYBin(y)*metadata.getBinWidthY();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public double getValue(double x, double y){
|
||||
int column = getXBin(x);
|
||||
int row = getYBin(y);
|
||||
//int column = (int)x;
|
||||
//int row = (int)y;
|
||||
return dataArray[2][row * numberOfXBins + column];
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValue(int i, int j) {
|
||||
return dataArray[2][i * numberOfXBins + j];
|
||||
}
|
||||
|
||||
/**
|
||||
* The array is filled 'horizontally' (row kept constant, columns++ ,
|
||||
* then row++ etc. where row = i = yAxis and column = j = xAxis)
|
||||
*/
|
||||
@Override
|
||||
public void setValue(int i, int j, double value) {
|
||||
dataArray[2][i * numberOfXBins + j] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the bin in which x lies
|
||||
* maxX and minX values are the values in the middle of the first and last bin
|
||||
* therefore we need to subtract 1/2 of binWidth
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int getXBin(double x) {
|
||||
return ((int) ((x - ( metadata.getMinX() - 0.5*metadata.getBinWidthX()))/metadata.getBinWidthX()));
|
||||
}
|
||||
|
||||
/**
|
||||
* get the bin in which y lies
|
||||
* maxY and minY values are the values in the middle of the first and last bin
|
||||
* therefore we need to subtract 1/2 of binWidth
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public int getYBin(double y) {
|
||||
return ((int) ((y - (metadata.getMinY() - 0.5*metadata.getBinWidthY()))/metadata.getBinWidthY()));
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.plot.xyz.JFreeMatrixPlotData#getDataArray()
|
||||
*/
|
||||
@Override
|
||||
public double[] getDataArray() {
|
||||
return dataArray[2];
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.plot.xyz.JFreeMatrixPlotData#getXSize()
|
||||
*/
|
||||
@Override
|
||||
public int getXSize() {
|
||||
// TODO Auto-generated method stub
|
||||
return numberOfXBins;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.plot.xyz.JFreeMatrixPlotData#getYSize()
|
||||
*/
|
||||
@Override
|
||||
public int getYSize() {
|
||||
// TODO Auto-generated method stub
|
||||
return numberOfYBins;
|
||||
}
|
||||
|
||||
|
||||
public void clear(){
|
||||
Arrays.fill(dataArray[0], Double.NEGATIVE_INFINITY);
|
||||
Arrays.fill(dataArray[1], Double.NEGATIVE_INFINITY);
|
||||
Arrays.fill(dataArray[2], Double.NEGATIVE_INFINITY);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jfree.data.xy.MatrixSeries;
|
||||
import org.jfree.data.xy.MatrixSeriesCollection;
|
||||
import org.jfree.data.xy.XYZDataset;
|
||||
|
||||
public class PixelPlotData implements JFreeMatrixPlotData {
|
||||
|
||||
private static Logger logger = Logger.getLogger(PixelPlotData.class.getName());
|
||||
|
||||
private MatrixSeries matrixData;
|
||||
private JFreeMatrixPlotMetadata metadata = null;
|
||||
|
||||
/**
|
||||
* Constructor using metadata
|
||||
* @param metadata
|
||||
*/
|
||||
public PixelPlotData(JFreeMatrixPlotMetadata metadata){
|
||||
this.metadata = metadata;
|
||||
matrixData = new MatrixSeries("Matrix Series Name", metadata.getNumberOfBinsY(), metadata.getNumberOfBinsX());
|
||||
matrixData.zeroAll();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor without metadata (no metadata available, default values are used)
|
||||
*/
|
||||
public PixelPlotData(){
|
||||
int defaultNumberOfXBins = 5;
|
||||
int defaultNumberOfYBins = 5;
|
||||
|
||||
this.metadata = new JFreeMatrixPlotMetadata();
|
||||
metadata.setMinX(0.0);
|
||||
metadata.setMaxX(defaultNumberOfXBins - 1.0);
|
||||
metadata.setMinY(0.0);
|
||||
metadata.setMaxY(defaultNumberOfYBins - 1.0);
|
||||
metadata.setMinValue(0.0);
|
||||
metadata.setMaxValue(100.0);
|
||||
metadata.setNumberOfBinsX(defaultNumberOfXBins);
|
||||
metadata.setNumberOfBinsY(defaultNumberOfYBins);
|
||||
matrixData = new MatrixSeries("Matrix Series Name", defaultNumberOfYBins, defaultNumberOfXBins);
|
||||
matrixData.zeroAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* If the matrix sized is exceeded, we need a way to enlarge the matrix
|
||||
* @param numberOfXBins
|
||||
* @param numberOfYBins
|
||||
*/
|
||||
public void rescaleMatrix(int rescaledNumberOfXBins, int rescaledNumberOfYBins){
|
||||
MatrixSeries newMatrixData = new MatrixSeries("Matrix Series Name", rescaledNumberOfYBins, rescaledNumberOfXBins);
|
||||
//copy the data first
|
||||
for (int k = 0; k < metadata.getNumberOfBinsY(); k++) {
|
||||
for (int l = 0; l < metadata.getNumberOfBinsX(); l++) {
|
||||
newMatrixData.update(k, l, matrixData.get(k, l));
|
||||
}
|
||||
}
|
||||
|
||||
this.metadata.setNumberOfBinsX(rescaledNumberOfXBins);
|
||||
this.metadata.setNumberOfBinsY(rescaledNumberOfYBins);
|
||||
this.metadata.setMaxX(rescaledNumberOfXBins - 1.0);
|
||||
this.metadata.setMaxY(rescaledNumberOfYBins - 1.0);
|
||||
|
||||
this.matrixData = newMatrixData;
|
||||
}
|
||||
|
||||
//The following convention holds: any function called with int assumes
|
||||
//Matrix like access, i.e (0, 0) is in upper left corner.
|
||||
//functions called with double assume cartesian like access.
|
||||
//i.e (0, 0) is in lower left corner
|
||||
|
||||
@Override
|
||||
public void addData(Number x, Number y, Number z){
|
||||
//Remember that fillBin is called as column, row
|
||||
int j = x.intValue();
|
||||
int i = y.intValue();
|
||||
|
||||
|
||||
try {
|
||||
matrixData.update(i, j, z.doubleValue());
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
logger.log(Level.INFO, "Index out of bound, pixel plot array is resized dynamically" ,e.getMessage());
|
||||
|
||||
int scaleFactor = 2;
|
||||
int rescaledNumberOfXBins = metadata.getNumberOfBinsX();
|
||||
int rescaledNumberOfYBins = metadata.getNumberOfBinsY();
|
||||
|
||||
if(j >= metadata.getNumberOfBinsX()){
|
||||
rescaledNumberOfXBins = scaleFactor*metadata.getNumberOfBinsX();
|
||||
logger.log(Level.INFO, "X Size exceeded");
|
||||
}
|
||||
|
||||
else if(i >= metadata.getNumberOfBinsY()){
|
||||
rescaledNumberOfYBins = scaleFactor*metadata.getNumberOfBinsY();
|
||||
logger.log(Level.INFO, "Y Size exceeded");
|
||||
|
||||
}
|
||||
|
||||
rescaleMatrix(rescaledNumberOfXBins, rescaledNumberOfYBins);
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDataBinned(Number x, Number y, Number z) {
|
||||
addData(x,y,z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addData(int i, int j, Number x, Number y, Number z) {
|
||||
//x, y are discarded
|
||||
//matrixData.update(i, j, z.doubleValue());
|
||||
addData(j, i, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public XYZDataset getData() {
|
||||
return new MatrixSeriesCollection(matrixData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JFreeMatrixPlotMetadata getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getXValue(int i, int j) {
|
||||
//Remember that x is column and y is row
|
||||
return (double) j;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getYValue(int i, int j) {
|
||||
//Remember that x is column and y is row
|
||||
return (double) i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValue(double x, double y) {
|
||||
//Remember that x is column and y is row
|
||||
return matrixData.get((int) y, (int) x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValue(int i, int j) {
|
||||
//called with ints we assume matrix like access
|
||||
return matrixData.get(i, j);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(int i, int j, double value) {
|
||||
matrixData.update(i, j, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getXBin(double x) {
|
||||
return (int) x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getYBin(double y) {
|
||||
return (int) y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMetadata(JFreeMatrixPlotMetadata metadata) {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getXValueBinned(double x) {
|
||||
return (double) ((int)x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getYValueBinned(double y) {
|
||||
return (double) ((int)y);
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.plot.xyz.JFreeMatrixPlotData#getDataArray()
|
||||
*/
|
||||
@Override
|
||||
public double[] getDataArray() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.plot.xyz.JFreeMatrixPlotData#getXSize()
|
||||
*/
|
||||
@Override
|
||||
public int getXSize() {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.plot.xyz.JFreeMatrixPlotData#getYSize()
|
||||
*/
|
||||
@Override
|
||||
public int getYSize() {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ch.psi.plot.util.XYPoint;
|
||||
|
||||
/**
|
||||
* Object describing a region inside a 2D matrix plot
|
||||
*/
|
||||
public class Region{
|
||||
|
||||
private ArrayList<XYPoint> pointList = new ArrayList<XYPoint>(); // List of points
|
||||
|
||||
/**
|
||||
* Check if point is inside the Region/Polygon
|
||||
* Use of a implementation of Point in Polygon algorithm (Ray Casting). This algorithm only works for simple
|
||||
* polygons (no line intersection)
|
||||
* @param xyPoint
|
||||
* @return
|
||||
*/
|
||||
public boolean isInside(XYPoint xyPoint){
|
||||
int numberOfFoundYValues = 0;
|
||||
|
||||
// We init the before Point with the first polygon point, so nothing (wrong) will happen in the first loop
|
||||
XYPoint xyPolygonVertexBefore = new XYPoint(pointList.get(0).getX(), pointList.get(0).getY());
|
||||
XYPoint xyPolygonVertex = new XYPoint(0.0, 0.0);
|
||||
for (int i=1; i< pointList.size(); i++){
|
||||
xyPolygonVertex.setX(pointList.get(i).getX());
|
||||
xyPolygonVertex.setY(pointList.get(i).getY());
|
||||
if (isInInterval(xyPolygonVertex.getX(), xyPolygonVertexBefore.getX(), xyPoint.getX())){
|
||||
//FoundYValues.add(new Double(calculateYValue(xyPolygonVertexBefore, xyPolygonVertex, xyPoint.getX())));
|
||||
if(calculateYValue(xyPolygonVertexBefore, xyPolygonVertex, xyPoint.getX()) < xyPoint.getY()){
|
||||
numberOfFoundYValues++;
|
||||
}
|
||||
}
|
||||
xyPolygonVertexBefore.setX(xyPolygonVertex.getX()); xyPolygonVertexBefore.setY(xyPolygonVertex.getY());
|
||||
}
|
||||
//Don't forget to close the polygon (check the last closing line).
|
||||
xyPolygonVertex.setX(pointList.get(0).getX());
|
||||
xyPolygonVertex.setY(pointList.get(0).getY());
|
||||
//PolygonVertexBefore contains the last element in list.
|
||||
if (isInInterval(xyPolygonVertex.getX(), xyPolygonVertexBefore.getX(), xyPoint.getX())){
|
||||
if(calculateYValue(xyPolygonVertexBefore, xyPolygonVertex, xyPoint.getX()) < xyPoint.getY()){
|
||||
numberOfFoundYValues++;
|
||||
}
|
||||
}
|
||||
|
||||
//Odd number of found yvalues indicates that point lays outside of polygon
|
||||
if(numberOfFoundYValues % 2 == 0){
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the point list of the region/polygon
|
||||
* @return
|
||||
*/
|
||||
public ArrayList<XYPoint> getPointList() {
|
||||
return pointList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the point list of the region/polygon
|
||||
* @param pointList
|
||||
*/
|
||||
public void setPointList(ArrayList<XYPoint> pointList) {
|
||||
this.pointList = pointList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether x is within the interval of x1 and x2
|
||||
* @param x1
|
||||
* @param x2
|
||||
* @param x
|
||||
* @return
|
||||
*/
|
||||
private boolean isInInterval(double x1, double x2, double x){
|
||||
//In case x1 > x2 we interchange them with min, max
|
||||
if (x > Math.min(x1, x2) && x < Math.max(x1,x2)){
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate y value
|
||||
* @param xyStartPoint
|
||||
* @param xyEndPoint
|
||||
* @param x
|
||||
* @return
|
||||
*/
|
||||
private double calculateYValue(XYPoint xyStartPoint, XYPoint xyEndPoint, double x){
|
||||
//This is just for security sake, ask first if x is inInterval before calling
|
||||
if (!isInInterval(xyStartPoint.getX(), xyEndPoint.getX(), x)){
|
||||
return 0.0;
|
||||
}
|
||||
else{
|
||||
//Evaluate y= a*(x - x_start) + y_start at the point x
|
||||
//Note that delta x cannot be zero since in that case x cannot be in interval
|
||||
double a = (xyEndPoint.getY() - xyStartPoint.getY())/(xyEndPoint.getX() - xyStartPoint.getX());
|
||||
return a*(x- xyStartPoint.getX()) + xyStartPoint.getY();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import org.jfree.data.xy.XYSeriesCollection;
|
||||
|
||||
import ch.psi.plot.util.XYPoint;
|
||||
|
||||
public class SectionPlotData {
|
||||
|
||||
/**
|
||||
* Calculates the line section plot data for a xyz plot (the line is typically drawn with mouse)
|
||||
* @param plotData
|
||||
* @param startPoint
|
||||
* @param endPoint
|
||||
* @param lineSectionCollection
|
||||
* @param lineSectionPlotLabel
|
||||
*/
|
||||
public static void calculateSectionPlotData(JFreeMatrixPlotData plotData, XYPoint startPoint, XYPoint endPoint, XYSeriesCollection lineSectionCollection, String lineSectionPlotLabel){
|
||||
|
||||
lineSectionCollection.getSeries(lineSectionPlotLabel).clear();
|
||||
XYPoint difference = new XYPoint(endPoint.getX() - startPoint.getX(), endPoint.getY() - startPoint.getY());
|
||||
|
||||
double angleWithHorizontal;
|
||||
double slope;
|
||||
|
||||
if(difference.getX() == 0.0){
|
||||
slope = Double.MAX_VALUE;
|
||||
angleWithHorizontal = Math.PI/2.0;
|
||||
}
|
||||
else{
|
||||
slope = difference.getY()/difference.getX();
|
||||
angleWithHorizontal = Math.atan(slope);
|
||||
}
|
||||
double x = startPoint.getX();
|
||||
double deltax;
|
||||
double y = startPoint.getY();
|
||||
double deltay;
|
||||
double z;
|
||||
double lineSegmentlength;
|
||||
|
||||
if((angleWithHorizontal >= -Math.PI/4.0 ) && (angleWithHorizontal <= Math.PI/4.0)){
|
||||
//Be aware of signum of delta x (can be negative)
|
||||
deltax = Math.signum(difference.getX())*plotData.getMetadata().getBinWidthX();
|
||||
//Cover both cases (deltax > 0 and deltax < 0)
|
||||
while (Math.signum(difference.getX())*(endPoint.getX() - x) >= 0.0){
|
||||
//z value at the line position
|
||||
z = plotData.getValue(x, y);
|
||||
lineSegmentlength = Math.sqrt(Math.pow(x-startPoint.getX(),2.0) + Math.pow(y-startPoint.getY(),2.0));
|
||||
lineSectionCollection.getSeries(lineSectionPlotLabel).add(lineSegmentlength, z);
|
||||
//y value of the Line
|
||||
y = y + slope*deltax;
|
||||
//update x value
|
||||
x = x + deltax;
|
||||
}
|
||||
}
|
||||
else{
|
||||
//If the slope is steeper than +- 45 degrees, we choose y Axis as independent variable, in order not to miss points
|
||||
if(slope == 0.0){
|
||||
//We should never end here, just for security's sake (if slope = 0 were in x section)
|
||||
}
|
||||
else{
|
||||
slope = 1.0/slope;
|
||||
}
|
||||
//Be aware of signum of delta y (can be negative)
|
||||
deltay = Math.signum(difference.getY())*plotData.getMetadata().getBinWidthY();
|
||||
while (Math.signum(difference.getY())*(endPoint.getY() - y) >= 0.0){
|
||||
z = plotData.getValue(x, y);
|
||||
lineSegmentlength = Math.sqrt(Math.pow(x-startPoint.getX(),2.0) + Math.pow(y-startPoint.getY(),2.0));
|
||||
lineSectionCollection.getSeries(lineSectionPlotLabel).add(lineSegmentlength, z);
|
||||
x = x + slope*deltay;
|
||||
y = y + deltay;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import ch.psi.plot.EventActionListener;
|
||||
import ch.psi.plot.xyz.JFreeMatrixPlot;
|
||||
import ch.psi.plot.xyz.JFreeMatrixPlotMetadata;
|
||||
import ch.psi.plot.xyz.MatrixPlotData;
|
||||
|
||||
public class StaticMatrixPlotter {
|
||||
|
||||
public static void convert(double[][] data, MatrixPlotData matrixPlotData){
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
for (int j = 0; j < data[0].length; j++) {
|
||||
matrixPlotData.addData(matrixPlotData.getXValueBinned(i, j), matrixPlotData.getYValueBinned(i, j), data[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void plot(String name, double minX, double maxX, double minY, double maxY, double minZ, double maxZ, final double[][] data){
|
||||
JFreeMatrixPlotMetadata md = new JFreeMatrixPlotMetadata();
|
||||
md.setNumberOfBinsX(data.length);
|
||||
md.setNumberOfBinsY(data[0].length);
|
||||
md.setMinX(minX);
|
||||
md.setMaxX(maxX);
|
||||
md.setMinY(minY);
|
||||
md.setMaxY(maxY);
|
||||
md.setMinValue(minZ);
|
||||
md.setMaxValue(maxZ);
|
||||
|
||||
final MatrixPlotData matrixPlotData = new MatrixPlotData(md);
|
||||
|
||||
convert(data, matrixPlotData);
|
||||
JFreeMatrixPlot plot = new JFreeMatrixPlot(name, matrixPlotData);
|
||||
plot.plot();
|
||||
plot.adaptColorMapScale();
|
||||
|
||||
class LocalEventActionListener implements EventActionListener{
|
||||
@Override
|
||||
public void performAction(Actions action) {
|
||||
convert(data, matrixPlotData);
|
||||
}
|
||||
}
|
||||
|
||||
plot.addEventActionListener(new LocalEventActionListener());
|
||||
|
||||
}
|
||||
|
||||
public static void plot(String name, double[][] data){
|
||||
plot(name, 0.0, (double)data.length, 0.0, (double)data[0].length, 0.0, 100.0, data );
|
||||
}
|
||||
|
||||
public static void plot(double[][] data){
|
||||
plot("test matrix plot", 0.0, data.length, 0.0, data[0].length, 0.0, 100.0, data );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
|
||||
public class StaticMatrixPlotterTest {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMatrixPlotStatic(){
|
||||
|
||||
int ni = 11;
|
||||
int nj = 19;
|
||||
double[][] data = new double[ni][nj];
|
||||
for (int i = 0; i < ni; i++) {
|
||||
for (int j = 0; j < nj; j++) {
|
||||
data[i][j] = i*j;
|
||||
}
|
||||
}
|
||||
StaticMatrixPlotter.plot("test matrix plot", data);
|
||||
try {
|
||||
Thread.sleep(100000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.WindowConstants;
|
||||
|
||||
import org.jfree.ui.RefineryUtilities;
|
||||
|
||||
import ch.psi.plot.EventActionListener;
|
||||
import ch.psi.plot.Plot;
|
||||
import jhplot.HPlot3D;
|
||||
|
||||
public class SurfacePlot implements Plot {
|
||||
|
||||
private HPlot3D hPlot3D;
|
||||
private final int frameHeight = 500;
|
||||
private final int frameWidth = 1200;
|
||||
|
||||
private List<SurfacePlotData> datalist;
|
||||
private String title;
|
||||
|
||||
public SurfacePlot(String title, List<SurfacePlotData> datalist){
|
||||
this.datalist = datalist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup of the surface plot(s)
|
||||
*/
|
||||
public void setUpFrame(boolean terminateOnExit){
|
||||
|
||||
hPlot3D = new HPlot3D(title, frameWidth, frameHeight, datalist.size(), 1);
|
||||
|
||||
hPlot3D.visible(true);
|
||||
|
||||
hPlot3D.setGTitle("Surface Plot");
|
||||
|
||||
if(terminateOnExit){
|
||||
hPlot3D.getFrame().setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
|
||||
}
|
||||
|
||||
int histogramPosition = 1;
|
||||
// Init the plots histograms and add them to the plot
|
||||
for(SurfacePlotData data: datalist){
|
||||
hPlot3D.cd(histogramPosition, 1);
|
||||
|
||||
hPlot3D.setLabelOffsetZ(5.0);
|
||||
|
||||
hPlot3D.setNameX(data.getMetadata().getxAxisLabel());
|
||||
hPlot3D.setNameY(data.getMetadata().getyAxisLabel());
|
||||
hPlot3D.setNameZ(data.getMetadata().getzAxisLabel());
|
||||
|
||||
hPlot3D.draw(data.getData());
|
||||
hPlot3D.setScaling(data.getMetadata().getScaling());
|
||||
hPlot3D.setRotationAngle(data.getMetadata().getRotationAngle());
|
||||
hPlot3D.setElevationAngle(data.getMetadata().getElevationAngle());
|
||||
histogramPosition++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPanel getPlotPanel(){
|
||||
hPlot3D.getCanvasPanel().setName(title);
|
||||
return hPlot3D.getCanvasPanel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void plot(){
|
||||
plot(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void plot(boolean terminateOnExit) {
|
||||
setUpFrame(terminateOnExit);
|
||||
//We don't explicitly plot here, the plotting is triggered by the converter
|
||||
//via calling update function of all registered classes that implement
|
||||
//DataUpdateListener
|
||||
|
||||
// Center the frame
|
||||
RefineryUtilities.centerFrameOnScreen(hPlot3D.getFrame());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void plot(boolean terminateOnExit, int x, int y){
|
||||
setUpFrame(terminateOnExit);
|
||||
|
||||
// Set frame position
|
||||
hPlot3D.getFrame().setLocation(x, y);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void plot(boolean terminateOnExit, int x, int y, int width, int height){
|
||||
setUpFrame(terminateOnExit);
|
||||
|
||||
// Set frame size and position
|
||||
hPlot3D.getFrame().setSize(width, height);
|
||||
hPlot3D.getFrame().setLocation(x, y);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
// Update panels
|
||||
for (int p = 1; p <= datalist.size(); p++) { // p is plot position
|
||||
hPlot3D.cd(p, 1);
|
||||
hPlot3D.updateData();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEventActionListener(EventActionListener listener) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEventActionListener(EventActionListener listener) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import ch.psi.plot.PlotData;
|
||||
import jhplot.H2D;
|
||||
|
||||
/**
|
||||
* Class to hold Surface Plot specific data and metadata.
|
||||
*/
|
||||
public class SurfacePlotData implements PlotData {
|
||||
|
||||
private H2D data;
|
||||
private SurfacePlotMetadata metadata;
|
||||
|
||||
/**
|
||||
* Instantiate Surface Plot Data. All required parameters are parameters of the constructor.
|
||||
* @param title
|
||||
* @param binsX
|
||||
* @param minX
|
||||
* @param maxX
|
||||
* @param binsY
|
||||
* @param minY
|
||||
* @param maxY
|
||||
*/
|
||||
public SurfacePlotData(String title, int binsX, double minX, double maxX, int binsY, double minY, double maxY){
|
||||
metadata = new SurfacePlotMetadata();
|
||||
data = new H2D(title, binsX, minX, maxX, binsY, minY, maxY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add data to data object
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*/
|
||||
public void addData(Number x, Number y, Number z) {
|
||||
int xBin = data.findBinX(x.doubleValue());
|
||||
int yBin = data.findBinY(y.doubleValue());
|
||||
//Non additive mode
|
||||
if (data.binEntries(xBin, yBin) == 0){
|
||||
data.fill(x.doubleValue(), y.doubleValue(), z.doubleValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add data to data object, bin is not derived from x,y value
|
||||
* @param i
|
||||
* @param j
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*/
|
||||
public void addData(int i, int j, Number x, Number y, Number z) {
|
||||
//Non additive mode, skip x,y
|
||||
double xj = ((double)j/(double)data.getBinsX()) * (data.getMaxX() - data.getMinX());
|
||||
double yi = ((double)i/(double)data.getBinsY()) * (data.getMaxY() - data.getMinY());
|
||||
int xBin = data.findBinX(xj);
|
||||
int yBin = data.findBinY(yi);
|
||||
|
||||
if (data.binEntries(xBin, yBin) == 0){
|
||||
data.fill(xj, yi, z.doubleValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SurfacePlot specific data
|
||||
* @return
|
||||
*/
|
||||
public H2D getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata
|
||||
* @return Metadata object
|
||||
*/
|
||||
public SurfacePlotMetadata getMetadata(){
|
||||
return(metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set metadata
|
||||
* @param metadata
|
||||
*/
|
||||
public void setMetadata(SurfacePlotMetadata metadata){
|
||||
this.metadata = metadata;
|
||||
}
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
/**
|
||||
* Bean to hold surface plot metadata
|
||||
*/
|
||||
public class SurfacePlotMetadata {
|
||||
|
||||
private String xAxisLabel = "";
|
||||
private String yAxisLabel = "";
|
||||
private String zAxisLabel = "";
|
||||
|
||||
private int numberOfBinsX;
|
||||
private double minValueX;
|
||||
private double maxValueX;
|
||||
|
||||
private int numberOfBinsY;
|
||||
private double minValueY;
|
||||
private double maxValueY;
|
||||
|
||||
private double scaling = 15; // Default value
|
||||
private double rotationAngle = 220; // Default value
|
||||
private double elevationAngle = 20; // Default value
|
||||
|
||||
public SurfacePlotMetadata(){
|
||||
}
|
||||
|
||||
public SurfacePlotMetadata(String xAxisLabel, String yAxisLabel, String zAxisLabel){
|
||||
this.xAxisLabel = xAxisLabel;
|
||||
this.yAxisLabel = yAxisLabel;
|
||||
this.zAxisLabel = zAxisLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get x-axis label
|
||||
* @return Label x-axis
|
||||
*/
|
||||
public String getxAxisLabel() {
|
||||
return xAxisLabel;
|
||||
}
|
||||
|
||||
public void setxAxisLabel(String xAxisLabel) {
|
||||
this.xAxisLabel = xAxisLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get y-axis label
|
||||
* @return Label y-axis
|
||||
*/
|
||||
public String getyAxisLabel() {
|
||||
return yAxisLabel;
|
||||
}
|
||||
|
||||
public void setyAxisLabel(String yAxisLabel) {
|
||||
this.yAxisLabel = yAxisLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get z-axis label
|
||||
* @return Label z-axis
|
||||
*/
|
||||
public String getzAxisLabel() {
|
||||
return zAxisLabel;
|
||||
}
|
||||
|
||||
public void setzAxisLabel(String zAxisLabel) {
|
||||
this.zAxisLabel = zAxisLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get scaling
|
||||
* @return Scaling factor
|
||||
*/
|
||||
public double getScaling() {
|
||||
return scaling;
|
||||
}
|
||||
|
||||
public void setScaling(double scaling) {
|
||||
this.scaling = scaling;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rotation angle
|
||||
* @return Rotation angle
|
||||
*/
|
||||
public double getRotationAngle() {
|
||||
return rotationAngle;
|
||||
}
|
||||
|
||||
public void setRotationAngle(double rotationAngle) {
|
||||
this.rotationAngle = rotationAngle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get elevation angle
|
||||
* @return Elevation angle
|
||||
*/
|
||||
public double getElevationAngle() {
|
||||
return elevationAngle;
|
||||
}
|
||||
|
||||
public void setElevationAngle(double elevationAngle) {
|
||||
this.elevationAngle = elevationAngle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of bins of the x-axis
|
||||
* @return Number of bins of the x-axis
|
||||
*/
|
||||
public int getNumberOfBinsX() {
|
||||
return numberOfBinsX;
|
||||
}
|
||||
|
||||
public void setNumberOfBinsX(int numberOfBinsX) {
|
||||
this.numberOfBinsX = numberOfBinsX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lowest x-axis value
|
||||
* @return
|
||||
*/
|
||||
public double getMinValueX() {
|
||||
return minValueX;
|
||||
}
|
||||
|
||||
public void setMinValueX(double minValueX) {
|
||||
this.minValueX = minValueX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get highest x-axis value
|
||||
* @return
|
||||
*/
|
||||
public double getMaxValueX() {
|
||||
return maxValueX;
|
||||
}
|
||||
|
||||
public void setMaxValueX(double maxValueX) {
|
||||
this.maxValueX = maxValueX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of bins of the y-axis
|
||||
* @return
|
||||
*/
|
||||
public int getNumberOfBinsY() {
|
||||
return numberOfBinsY;
|
||||
}
|
||||
|
||||
public void setNumberOfBinsY(int numberOfBinsY) {
|
||||
this.numberOfBinsY = numberOfBinsY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lowest number of the y-axis
|
||||
* @return
|
||||
*/
|
||||
public double getMinValueY() {
|
||||
return minValueY;
|
||||
}
|
||||
|
||||
public void setMinValueY(double minValueY) {
|
||||
this.minValueY = minValueY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get highest y-axis value
|
||||
* @return
|
||||
*/
|
||||
public double getMaxValueY() {
|
||||
return maxValueY;
|
||||
}
|
||||
|
||||
public void setMaxValueY(double maxValueY) {
|
||||
this.maxValueY = maxValueY;
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package ch.psi.plot.xyz.plugable;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import ch.psi.plot.util.XYPoint;
|
||||
import ch.psi.plot.xyz.JFreeMatrixPlot;
|
||||
import ch.psi.plot.xyz.JFreeMatrixPlotData;
|
||||
|
||||
public class BaryCenter implements PlugableUtilXYZ{
|
||||
|
||||
private static Logger logger = Logger.getLogger(BaryCenter.class.getName());
|
||||
|
||||
/**
|
||||
* Find the Barycenter of the passed matrix plot data
|
||||
* @param plotData
|
||||
* @param lowerLeft
|
||||
* @param upperRight
|
||||
* @return
|
||||
*/
|
||||
private XYPoint findBarycenter(JFreeMatrixPlotData plotData, XYPoint lowerLeft, XYPoint upperRight, boolean binned){
|
||||
XYPoint barycenter;
|
||||
|
||||
double x; double y;double z;
|
||||
x = lowerLeft.getX();
|
||||
y = lowerLeft.getY();
|
||||
|
||||
if (binned){
|
||||
try{
|
||||
x = plotData.getXValueBinned(x);
|
||||
y = plotData.getYValueBinned(y);
|
||||
}
|
||||
catch(Exception e){
|
||||
logger.fine(e.getMessage() + " Start values couldn't be binned");
|
||||
}
|
||||
}
|
||||
|
||||
double barycenterX = 0.0; double barycenterY = 0.0;
|
||||
double norm = 0.0;
|
||||
|
||||
while(x < upperRight.getX()){
|
||||
while(y < upperRight.getY()){
|
||||
try{
|
||||
z = plotData.getValue(x, y);
|
||||
barycenterX += z*x;
|
||||
barycenterY += z*y;
|
||||
norm += z;
|
||||
}
|
||||
catch(Exception e){
|
||||
logger.severe(e.getMessage());
|
||||
}
|
||||
|
||||
y = y + plotData.getMetadata().getBinWidthY();
|
||||
}
|
||||
y = lowerLeft.getY();
|
||||
x = x + plotData.getMetadata().getBinWidthX();
|
||||
}
|
||||
|
||||
if(binned){
|
||||
try{
|
||||
barycenter = new XYPoint(plotData.getXValueBinned(barycenterX/norm),
|
||||
plotData.getYValueBinned(barycenterY/norm));
|
||||
}
|
||||
catch(Exception e){
|
||||
logger.log(Level.SEVERE, "Barycenter couldn't be binned", e);
|
||||
//return unbinned version if binned failed
|
||||
barycenter = new XYPoint(barycenterX/norm, barycenterY/norm);
|
||||
}
|
||||
}
|
||||
else{
|
||||
barycenter = new XYPoint(barycenterX/norm, barycenterY/norm);
|
||||
}
|
||||
|
||||
return barycenter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add marker to barycenter value
|
||||
*/
|
||||
@Override
|
||||
public void execute(final JFreeMatrixPlot jFreeMatrixPlot) {
|
||||
|
||||
Thread t = new Thread( new Runnable(){
|
||||
public void run(){
|
||||
|
||||
try {
|
||||
XYPoint bc = findBarycenter(jFreeMatrixPlot.getData(), jFreeMatrixPlot.getLowerLeftChartCorner(), jFreeMatrixPlot.getUpperRightChartCorner(), true);
|
||||
jFreeMatrixPlot.getInterestingSpots().put(getLabel(), bc);
|
||||
jFreeMatrixPlot.redrawSelectedRegions();
|
||||
} catch (Exception e) {
|
||||
logger.warning(e.getMessage());
|
||||
}
|
||||
}});
|
||||
t.start();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package ch.psi.plot.xyz.plugable;
|
||||
|
||||
/**
|
||||
* Abstract filter class
|
||||
*/
|
||||
public abstract class Filter {
|
||||
|
||||
/**
|
||||
* Get the filter data entry of filter row i and column j
|
||||
* @param i Row of the filter
|
||||
* @param j Column of the filter
|
||||
* @return Filter entry
|
||||
*/
|
||||
public abstract double getDataEntry(int i, int j);
|
||||
|
||||
/**
|
||||
* Get the number of rows of the filter
|
||||
* @return Number of rows
|
||||
*/
|
||||
public abstract int getNumberOfRows();
|
||||
|
||||
/**
|
||||
* Get the number of columns of the filter
|
||||
* @return Number of columns
|
||||
*/
|
||||
public abstract int getNumberOfColumns();
|
||||
|
||||
/**
|
||||
* Get whether filter dimensions are odd or even
|
||||
* @return True if either the number of rows or the number of columns is odd, False otherwise
|
||||
*/
|
||||
public boolean isDimensionOdd(){
|
||||
if( (getNumberOfRows() % 2 == 0) || (getNumberOfColumns() % 2 == 0)){
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package ch.psi.plot.xyz.plugable;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import ch.psi.plot.xyz.JFreeMatrixPlotData;
|
||||
|
||||
public class FilterTransformation {
|
||||
|
||||
private static Logger logger = Logger.getLogger(FilterTransformation.class.getName());
|
||||
|
||||
/**
|
||||
* Apply specified filter to the passed data object
|
||||
* @param plotData
|
||||
* @param filter
|
||||
*/
|
||||
public static void applyFilter(JFreeMatrixPlotData plotData, Filter filter){
|
||||
|
||||
int numberOfXBins = plotData.getMetadata().getNumberOfBinsX();
|
||||
int numberOfYBins = plotData.getMetadata().getNumberOfBinsY();
|
||||
|
||||
logger.fine("Number of X bins: "+ numberOfXBins);
|
||||
logger.fine("Number of Y bins: "+ numberOfYBins);
|
||||
|
||||
if(!filter.isDimensionOdd()){
|
||||
logger.severe("Dimension of Filter Matrix must be odd");
|
||||
return;
|
||||
}
|
||||
|
||||
//We need a queue to store the transformed values since we don't want the old values to
|
||||
//be overwritten. (not before their not used anymore for a later row)
|
||||
Queue<double[]> queue = new LinkedList<double[]>();
|
||||
int requiredQueueSize = (filter.getNumberOfRows() - 1)/2;
|
||||
int rowEdges = requiredQueueSize;
|
||||
int columnEdges = (filter.getNumberOfColumns() - 1)/2;
|
||||
|
||||
for (int i = rowEdges; i < numberOfYBins - rowEdges; i++) {
|
||||
double[] filteredPointsQueuing = new double[numberOfXBins - 2*columnEdges];
|
||||
for (int j = columnEdges; j < numberOfXBins - columnEdges; j++) {
|
||||
double filteredPoint = 0.0;
|
||||
for (int f = 0; f < filter.getNumberOfRows(); f++) {
|
||||
for (int g = 0; g < filter.getNumberOfColumns(); g++) {
|
||||
int positionOfFilterPointInMatrixRow = i - rowEdges + f;
|
||||
int positionOfFilterPointInMatrixColumn = j - columnEdges + g;
|
||||
//getValue is called (row, column)
|
||||
filteredPoint += filter.getDataEntry(f, g) * plotData.getValue(positionOfFilterPointInMatrixRow, positionOfFilterPointInMatrixColumn );
|
||||
|
||||
}
|
||||
}//filtered point is calculated
|
||||
filteredPointsQueuing[j - columnEdges] = filteredPoint;
|
||||
}
|
||||
|
||||
queue.add(filteredPointsQueuing);
|
||||
|
||||
if(queue.size() > requiredQueueSize){
|
||||
double[] filteredPointsPolled = new double[numberOfXBins - 2*columnEdges];
|
||||
filteredPointsPolled = queue.poll();
|
||||
//Write the polled data back
|
||||
for (int j = columnEdges; j < numberOfXBins - columnEdges; j++) {
|
||||
plotData.setValue(i - requiredQueueSize, j, filteredPointsPolled[j - columnEdges]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//empty stack if last line is reached
|
||||
while(queue.size() > 0){
|
||||
double[] filteredPointsPolled = new double[numberOfXBins - 2*columnEdges];
|
||||
filteredPointsPolled = queue.poll();
|
||||
//Write the polled data back
|
||||
for (int j = columnEdges; j < numberOfXBins - columnEdges; j++) {
|
||||
//setZValue is called (column, row, value)
|
||||
plotData.setValue(numberOfYBins - 1 - rowEdges - queue.size(), j, filteredPointsPolled[j - columnEdges]);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package ch.psi.plot.xyz.plugable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.commons.math.complex.Complex;
|
||||
import org.apache.commons.math.transform.FastFourierTransformer;
|
||||
|
||||
import ch.psi.plot.xy.plugable.FourierTransformer;
|
||||
import ch.psi.plot.xyz.JFreeMatrixPlot;
|
||||
import ch.psi.plot.xyz.JFreeMatrixPlotData;
|
||||
import ch.psi.plot.xyz.JFreeMatrixPlotMetadata;
|
||||
import ch.psi.plot.xyz.MatrixPlotData;
|
||||
|
||||
public class FourierTransformation implements PlugableUtilXYZ{
|
||||
|
||||
private static Logger logger = Logger.getLogger(FourierTransformation.class.getName());
|
||||
|
||||
|
||||
/**
|
||||
* Apply fourier transformation to the data and return a new data matrix
|
||||
* TODO to be checked
|
||||
* @param plotData
|
||||
* @return
|
||||
*/
|
||||
private JFreeMatrixPlotData calculateFFT(JFreeMatrixPlotData plotData){
|
||||
|
||||
int powerOf2InputDataLengthX = FourierTransformer.getPreviousPowerOf2(plotData.getMetadata().getNumberOfBinsX());
|
||||
int powerOf2InputDataLengthY = FourierTransformer.getPreviousPowerOf2(plotData.getMetadata().getNumberOfBinsY());
|
||||
//Allocate input for FFT
|
||||
Complex[][] inputData = new Complex[powerOf2InputDataLengthY][powerOf2InputDataLengthX];
|
||||
//define Input for FFT
|
||||
for (int i = 0; i < powerOf2InputDataLengthY; i++) {
|
||||
for (int j = 0; j < powerOf2InputDataLengthX; j++) {
|
||||
//Imaginary part of InputData is zero
|
||||
inputData[i][j] = new Complex(plotData.getValue(i, j), 0.0);
|
||||
}
|
||||
}
|
||||
//Do 2D FFT
|
||||
FastFourierTransformer fastFourierTransformer = new FastFourierTransformer();
|
||||
Complex[][] fourierTransformedData = (Complex[][]) fastFourierTransformer.mdfft(inputData,true);
|
||||
|
||||
//calculate interval in fourier space
|
||||
double fourierSpaceScaleFaktorX = (2*Math.PI)/(plotData.getMetadata().getBinWidthX()*powerOf2InputDataLengthX);
|
||||
double fourierSpaceScaleFaktorY = (2*Math.PI)/(plotData.getMetadata().getBinWidthY()*powerOf2InputDataLengthY);
|
||||
|
||||
//Now we know all metadata
|
||||
|
||||
// New FourierPlotDataInstance
|
||||
JFreeMatrixPlotMetadata metadata = new JFreeMatrixPlotMetadata();
|
||||
metadata.setMinX(0.0);
|
||||
metadata.setMaxX(fourierSpaceScaleFaktorX*powerOf2InputDataLengthX);
|
||||
metadata.setNumberOfBinsX(powerOf2InputDataLengthX);
|
||||
metadata.setMinY(0.0);
|
||||
metadata.setMaxY(fourierSpaceScaleFaktorY*powerOf2InputDataLengthY);
|
||||
metadata.setNumberOfBinsY(powerOf2InputDataLengthY);
|
||||
metadata.setMinValue(Double.NEGATIVE_INFINITY);
|
||||
metadata.setMaxValue(Double.POSITIVE_INFINITY);
|
||||
MatrixPlotData fourierPlotData = new MatrixPlotData(metadata);
|
||||
|
||||
//Fill the data of the new instance with the fourier transform
|
||||
ArrayList<Double> powerSpectrumValues = new ArrayList<Double>(powerOf2InputDataLengthX*powerOf2InputDataLengthY);
|
||||
|
||||
for (int i = 0; i < powerOf2InputDataLengthY; i++) {
|
||||
for (int j = 0; j < powerOf2InputDataLengthX; j++) {
|
||||
double kx = fourierSpaceScaleFaktorX*j + fourierSpaceScaleFaktorX/2.0;
|
||||
double ky = fourierSpaceScaleFaktorY*i + fourierSpaceScaleFaktorY/2.0;
|
||||
//Only Power Spectrum
|
||||
double powerSpectrumValue = fourierTransformedData[i][j].abs();
|
||||
//double imagPartValue = fourierTransformedData[i][j].getImaginary();
|
||||
//double realPartValue = fourierTransformedData[i][j].getReal();
|
||||
fourierPlotData.addData(kx,ky,powerSpectrumValue);
|
||||
powerSpectrumValues.add(new Double(powerSpectrumValue));
|
||||
}
|
||||
}
|
||||
return fourierPlotData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show Fourier transformation of the underlying data
|
||||
*/
|
||||
@Override
|
||||
public void execute(final JFreeMatrixPlot jFreeMatrixPlot) {
|
||||
Thread t = new Thread( new Runnable(){
|
||||
public void run(){
|
||||
try {
|
||||
JFreeMatrixPlot plot = new JFreeMatrixPlot("Fourier Transformation", calculateFFT(jFreeMatrixPlot.getData()));
|
||||
plot.adaptColorMapScale();
|
||||
plot.plot(false);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.warning(e.getMessage());
|
||||
}
|
||||
|
||||
}});
|
||||
t.start();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package ch.psi.plot.xyz.plugable;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import ch.psi.plot.xyz.JFreeMatrixPlot;
|
||||
|
||||
public class GaussFilter implements PlugableUtilXYZ{
|
||||
|
||||
private static Logger logger = Logger.getLogger(GaussFilter.class.getName());
|
||||
|
||||
@Override
|
||||
public void execute(final JFreeMatrixPlot jFreeMatrixPlot) {
|
||||
|
||||
|
||||
Thread t = new Thread( new Runnable(){
|
||||
public void run(){
|
||||
|
||||
Class<?> pluginClass = null;
|
||||
|
||||
String classname = "ch.psi.plot.xyz.plugable.IntegratedXValues";
|
||||
try {//Load class according to its name
|
||||
pluginClass = Class.forName(classname);
|
||||
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.warning("Class " + classname + " not found " + e.getMessage());
|
||||
}
|
||||
|
||||
IntegratedXValues integratedXValues = null;
|
||||
|
||||
try {
|
||||
integratedXValues = (IntegratedXValues) pluginClass.newInstance();
|
||||
} catch (InstantiationException e) {
|
||||
logger.warning("Unable to instantiate " + classname + " : " + e.getMessage());
|
||||
} catch (IllegalAccessException e) {
|
||||
logger.warning("Unable to access " + classname + " : " + e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
final int sizeMin = 3;
|
||||
final double filteringRange = 0.02;
|
||||
int n = (int) (filteringRange*jFreeMatrixPlot.getData().getMetadata().getNumberOfBinsY());
|
||||
int m = (int) (filteringRange*jFreeMatrixPlot.getData().getMetadata().getNumberOfBinsX());
|
||||
|
||||
int nOdd = n + (n+1) % 2;
|
||||
int mOdd = m + (m+1) % 2;
|
||||
|
||||
final int nFilter = Math.max(nOdd, sizeMin);
|
||||
final int mFilter = Math.max(mOdd, sizeMin);
|
||||
|
||||
|
||||
logger.info("Total Integral before smoothing: " + integratedXValues.integrate(jFreeMatrixPlot.getData(), jFreeMatrixPlot.getLowerLeftChartCorner(), jFreeMatrixPlot.getUpperRightChartCorner()));
|
||||
FilterTransformation.applyFilter(jFreeMatrixPlot.getData(), new GaussFilterMatrix(nFilter, mFilter));
|
||||
logger.info("Total Integral after smoothing: " + integratedXValues.integrate(jFreeMatrixPlot.getData(), jFreeMatrixPlot.getLowerLeftChartCorner(), jFreeMatrixPlot.getUpperRightChartCorner()));
|
||||
jFreeMatrixPlot.getMatrixPlotPanel().getChart().fireChartChanged();
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.warning(e.getMessage());
|
||||
}
|
||||
|
||||
}});
|
||||
t.start();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package ch.psi.plot.xyz.plugable;
|
||||
|
||||
/**
|
||||
* Gauss filter implementation 5x5
|
||||
*/
|
||||
public class GaussFilterMatrix extends Filter {
|
||||
|
||||
private int numberOfRows;
|
||||
private int numberOfColumns;
|
||||
private double[][] data;
|
||||
private double weight = 0.0;
|
||||
private double sigma = 1.0;
|
||||
|
||||
|
||||
/**
|
||||
* Create Gauss Filter
|
||||
*/
|
||||
public GaussFilterMatrix(int n, int m) {
|
||||
|
||||
this.numberOfRows = n;
|
||||
this.numberOfColumns = m;
|
||||
|
||||
data = new double[numberOfRows][numberOfColumns];
|
||||
|
||||
sigma = (double) 2.0*Math.PI*Math.sqrt(n*n + m*m);
|
||||
//The entry 0,0 is lower left edge! (not upper left edge)
|
||||
//(doesn't matter for symmetric matrices)
|
||||
|
||||
for (int i = 0; i < numberOfRows; i++) {
|
||||
for (int j = 0; j < numberOfColumns; j++) {
|
||||
data[i][j] = Math.exp(-Math.pow(1.0/sigma,2.0)*
|
||||
(Math.pow((i-(numberOfRows-1)/2.0),2.0) +
|
||||
Math.pow((j-(numberOfColumns-1)/2),2.0)));
|
||||
weight += data[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < numberOfRows; i++) {
|
||||
for (int j = 0; j < numberOfColumns; j++) {
|
||||
data[i][j] *= 1.0/weight;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDataEntry(int i, int j) {
|
||||
return data[i][j];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfColumns() {
|
||||
return numberOfColumns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfRows() {
|
||||
return numberOfRows;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
package ch.psi.plot.xyz.plugable;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jfree.data.xy.VectorSeries;
|
||||
import org.jfree.data.xy.VectorSeriesCollection;
|
||||
|
||||
import ch.psi.plot.util.XYPoint;
|
||||
import ch.psi.plot.xyz.JFreeMatrixPlot;
|
||||
import ch.psi.plot.xyz.JFreeMatrixPlotData;
|
||||
|
||||
public class Gradient implements PlugableUtilXYZ{
|
||||
|
||||
private static Logger logger = Logger.getLogger(Gradient.class.getName());
|
||||
|
||||
/**
|
||||
* Calculates the normalized gradient field of the visible part of the scalar field
|
||||
* @param plotData
|
||||
* @param lowerLeftChartCorner
|
||||
* @param upperRightChartCorner
|
||||
* @return
|
||||
*/
|
||||
private VectorSeriesCollection calculateGradientField(JFreeMatrixPlotData plotData, XYPoint lowerLeftChartCorner, XYPoint upperRightChartCorner){
|
||||
double xBinWidth = plotData.getMetadata().getBinWidthX();
|
||||
double yBinWidth = plotData.getMetadata().getBinWidthY();
|
||||
|
||||
logger.fine("x-width: "+xBinWidth+" y-width: "+yBinWidth);
|
||||
|
||||
VectorSeriesCollection gradientField = new VectorSeriesCollection();
|
||||
VectorSeries vectorSeries = new VectorSeries("gradient field of detector");
|
||||
gradientField.addSeries(vectorSeries);
|
||||
//calculate gradient, except at the borders.
|
||||
//the borders are either given by selection, or - if plot is still being updated, by the current XBin value
|
||||
int selectedXminBin = plotData.getXBin(lowerLeftChartCorner.getX());
|
||||
int selectedYminBin = plotData.getYBin(lowerLeftChartCorner.getY());
|
||||
|
||||
int selectedXmaxBin = plotData.getXBin(upperRightChartCorner.getX());
|
||||
int selectedYmaxBin = plotData.getYBin(upperRightChartCorner.getY());
|
||||
|
||||
int numberOfSelectedXBins = selectedXmaxBin - selectedXminBin;
|
||||
int numberOfSelectedYBins = selectedYmaxBin - selectedYminBin;
|
||||
|
||||
logger.fine("no x bins: "+numberOfSelectedXBins+" no y bins: "+numberOfSelectedYBins);
|
||||
|
||||
double[][] gradientXField = new double[numberOfSelectedYBins][numberOfSelectedXBins];
|
||||
double[][] gradientYField = new double[numberOfSelectedYBins][numberOfSelectedXBins];
|
||||
|
||||
double maxGradientNorm = 0.0;
|
||||
|
||||
double binDiagonalLength = Math.sqrt(xBinWidth*xBinWidth + yBinWidth*yBinWidth);
|
||||
//calculate gradient, except at the borders and beyond
|
||||
for (int i = 1; i < numberOfSelectedYBins - 1; i++) {
|
||||
for (int j = 1 ; j < numberOfSelectedXBins - 1; j++) {
|
||||
//Remember that x Axis defines column (y Axis row)
|
||||
//such that gradientX = d/d(column) and gradientY = d/ d(row)
|
||||
gradientXField[i][j] = (plotData.getValue(i + selectedYminBin, j + selectedXminBin + 1) -
|
||||
plotData.getValue(i + selectedYminBin, j + selectedXminBin - 1))/2*xBinWidth;
|
||||
gradientYField[i][j] = (plotData.getValue(i + selectedYminBin + 1, j + selectedXminBin) -
|
||||
plotData.getValue(i + selectedYminBin -1, j + selectedXminBin))/2*yBinWidth;
|
||||
double gradientNorm = Math.sqrt(Math.pow(gradientXField[i][j], 2.0) + Math.pow(gradientYField[i][j], 2.0));
|
||||
maxGradientNorm = Math.max(maxGradientNorm, gradientNorm);
|
||||
}
|
||||
}
|
||||
|
||||
double scaleFactor;
|
||||
if (maxGradientNorm != 0.0){
|
||||
scaleFactor = 1.0/maxGradientNorm;
|
||||
}
|
||||
else{
|
||||
scaleFactor = 0.0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numberOfSelectedYBins - 1; i++) {
|
||||
for (int j = 0; j < numberOfSelectedXBins - 1; j++) {
|
||||
double scaledGradientX = binDiagonalLength * scaleFactor * gradientXField[i][j];
|
||||
double scaledGradientY = binDiagonalLength * scaleFactor * gradientYField[i][j];
|
||||
vectorSeries.add(plotData.getXValue(i + selectedYminBin, j + selectedXminBin), plotData.getYValue(i + selectedYminBin, j + selectedXminBin), scaledGradientX, scaledGradientY);
|
||||
}
|
||||
}
|
||||
return gradientField;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Show gradient field of the underlying data
|
||||
*/
|
||||
@Override
|
||||
public void execute(final JFreeMatrixPlot jFreeMatrixPlot) {
|
||||
Thread t = new Thread( new Runnable(){
|
||||
public void run(){
|
||||
|
||||
try {
|
||||
GradientPlot plot = new GradientPlot("Gradient Field",
|
||||
calculateGradientField(jFreeMatrixPlot.getData(), jFreeMatrixPlot.getLowerLeftChartCorner(), jFreeMatrixPlot.getUpperRightChartCorner()),
|
||||
jFreeMatrixPlot.getLowerLeftChartCorner(), jFreeMatrixPlot.getUpperRightChartCorner());
|
||||
plot.pack();
|
||||
plot.setVisible(true);
|
||||
} catch (Exception e) {
|
||||
logger.warning(e.getMessage());
|
||||
}
|
||||
|
||||
}});
|
||||
t.start();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package ch.psi.plot.xyz.plugable;
|
||||
|
||||
import java.awt.Dimension;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.renderer.xy.VectorRenderer;
|
||||
import org.jfree.data.xy.VectorSeriesCollection;
|
||||
|
||||
import ch.psi.plot.util.XYPoint;
|
||||
|
||||
|
||||
public class GradientPlot extends JFrame{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* Creates a ChartPanel that plots the gradientField
|
||||
* @param title
|
||||
* @param gradientField
|
||||
* @param lowerLeft
|
||||
* @param upperRight
|
||||
*/
|
||||
public GradientPlot(String title, VectorSeriesCollection gradientField, XYPoint lowerLeft, XYPoint upperRight) {
|
||||
super(title);
|
||||
JFreeChart chart = createChart(gradientField, lowerLeft, upperRight);
|
||||
ChartPanel chartPanel = new ChartPanel(chart);
|
||||
chartPanel.setPreferredSize(new Dimension(500, 270));
|
||||
setContentPane(chartPanel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a chart that plots the gradientField in a specified range (lowerleft and upperright rectangle)
|
||||
* @param gradientField
|
||||
* @param lowerLeft
|
||||
* @param upperRight
|
||||
* @return
|
||||
*/
|
||||
private JFreeChart createChart(VectorSeriesCollection gradientField, XYPoint lowerLeft, XYPoint upperRight) {
|
||||
// create the chart...
|
||||
|
||||
NumberAxis xAxis = new NumberAxis("X");
|
||||
xAxis.setLowerBound(lowerLeft.getX());
|
||||
xAxis.setUpperBound(upperRight.getX());
|
||||
|
||||
NumberAxis yAxis = new NumberAxis("Y");
|
||||
yAxis.setLowerBound(lowerLeft.getY());
|
||||
yAxis.setUpperBound(upperRight.getY());
|
||||
|
||||
VectorRenderer renderer = new VectorRenderer();
|
||||
XYPlot vectorPlot = new XYPlot(gradientField, xAxis, yAxis, renderer);
|
||||
JFreeChart chart = new JFreeChart("Gradient Field", vectorPlot);
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user