Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 914c7a583e | |||
| 04b55fce00 | |||
| ac7ef97ca3 | |||
| 9ec66825e2 | |||
| 0029eba2d9 | |||
| 4a5df6042e | |||
| 4c86952b79 | |||
| f6539cc630 | |||
| 73cdc280c0 | |||
| ab1f81b942 | |||
| 8b38fe3354 | |||
| 58cf30d915 | |||
| 7ccce9976b | |||
| b7aaaf160d | |||
| 9906e7c240 | |||
| d7136e60d5 | |||
| 328f448b3c | |||
| a6fd949f3c | |||
| d7f7c776e6 | |||
| 4be942e0fc |
+32
-6
@@ -1,10 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding//src/main/java=UTF-8
|
||||
encoding//src/test/java=UTF-8
|
||||
@@ -1,3 +1,5 @@
|
||||
#Tue Oct 18 15:36:07 CEST 2011
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
|
||||
org.eclipse.jdt.core.compiler.compliance=1.7
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.7
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# Overview
|
||||
|
||||
# Notes
|
||||
JFree is not thread safe!
|
||||
|
||||
While data is modified while JFree is rendering the plot there will be an runtime exception.
|
||||
|
||||
E.g. if you define an array of hundred points to be plotted by JFree and for some reason
|
||||
you decide to remove (or alter) these points, then the rendering thread tries to finish rendering the 100
|
||||
points it started with but allows the concurrent modification of the data. This causes a runtime
|
||||
ArrayIndexOutOfBounds or similar Runtime Exception in the worst case or at least give a 'noisy' impression of the plotting.
|
||||
However, the problem occurs only for large datasets and/or high update frequencies.
|
||||
@@ -1 +0,0 @@
|
||||
JFree is not thread safe. If a manipulate the plotting data used by JFree, the rendering process is not synchronized in the sense that it does not lock the data and hence does not finish plotting the data it started with. If you e.g. define a array of hundred points to be plotted by JFree and for some reason you decide to remove (or alter) these points, then the rendering thread tries to finish rendering the 100 points it started with but allows the concurrent modification of the data. This can cause a runtime Array Index Out of Bounds Exception in the worst case or at least give a 'noisy' impression of the plotting. However, the problem occurs only for large datasets and/or high update frequencies.
|
||||
+44
-10
@@ -2,13 +2,19 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>ch.psi</groupId>
|
||||
<artifactId>plot</artifactId>
|
||||
<version>1.1.30</version>
|
||||
|
||||
<version>2.1-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>
|
||||
<artifactId>chart</artifactId>
|
||||
<version>1.0.13</version>
|
||||
<artifactId>jfreechart</artifactId>
|
||||
<version>1.0.15</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
@@ -16,12 +22,31 @@
|
||||
<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>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<encoding>UTF-8</encoding>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- Generate Javadoc Jar -->
|
||||
<plugin>
|
||||
<!-- <plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.8</version>
|
||||
@@ -31,9 +56,12 @@
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<additionalparam>-Xdoclint:none</additionalparam>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugin> -->
|
||||
<!-- Generate Source Jar -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
@@ -47,7 +75,7 @@
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
@@ -55,12 +83,18 @@
|
||||
<snapshotRepository>
|
||||
<id>i.snapshots</id>
|
||||
<name>Artifactory Snapshots</name>
|
||||
<url>http://yoke/artifactory/libs-snapshots-local</url>
|
||||
<url>http://artifacts.psi.ch/artifactory/libs-snapshots-local</url>
|
||||
</snapshotRepository>
|
||||
<repository>
|
||||
<id>i.releases</id>
|
||||
<name>Atrifactory Releases</name>
|
||||
<url>http://yoke/artifactory/libs-releases-local</url>
|
||||
<url>http://artifacts.psi.ch/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,166 @@
|
||||
/*
|
||||
* 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;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void createChart() {
|
||||
super.createChart();
|
||||
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 createPopupMenu() {
|
||||
super.createPopupMenu();
|
||||
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());
|
||||
if (getTitleFont()!=null)
|
||||
p.setTitleFont(getTitleFont());
|
||||
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((JPanel)p);
|
||||
frame.pack();
|
||||
SwingUtils.centerOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
frame.requestFocus();
|
||||
} catch (Exception ex) {
|
||||
SwingUtils.showException(LinePlotBase.this, 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,188 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* Data representation for LinePlot.
|
||||
*/
|
||||
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()*/ null);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private int maxItemCount=-1;
|
||||
public int getMaxItemCount() {
|
||||
return maxItemCount;
|
||||
}
|
||||
public void setMaxItemCount(int value) {
|
||||
maxItemCount=value;
|
||||
}
|
||||
|
||||
|
||||
//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,167 @@
|
||||
/*
|
||||
* 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 javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
abstract public class MatrixPlotBase extends PlotBase<MatrixPlotSeries> implements MatrixPlot {
|
||||
|
||||
protected MatrixPlotBase() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
protected MatrixPlotBase(String title) {
|
||||
super(MatrixPlotSeries.class, title);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createChart() {
|
||||
super.createChart();
|
||||
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)Math.round((x - series.getMinX()) / series.getBinWidthX());
|
||||
final int indexY = (int)Math.round((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 createPopupMenu() {
|
||||
super.createPopupMenu();
|
||||
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((JPanel)p);
|
||||
frame.pack();
|
||||
SwingUtils.centerOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
} catch (Exception ex) {
|
||||
SwingUtils.showException(MatrixPlotBase.this, 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,161 @@
|
||||
package ch.psi.plot;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Data representation for MatrixPlot.
|
||||
*/
|
||||
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++) {
|
||||
double val=data[i][j];
|
||||
if ((!Double.isNaN(val)) && (!Double.isInfinite(val))) {
|
||||
if (Double.isNaN(min) || (val < min)) {
|
||||
min = val;
|
||||
}
|
||||
if (Double.isNaN(max) || (val > max)) {
|
||||
max = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new double[]{min, max};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,46 +1,67 @@
|
||||
/**
|
||||
*
|
||||
* 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.Font;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
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>{
|
||||
|
||||
//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();
|
||||
public void setTitleFont(Font font);
|
||||
public Font getTitleFont();
|
||||
|
||||
//Generic operations
|
||||
public void saveData(String filename) throws IOException;
|
||||
|
||||
public BufferedImage getSnapshot();
|
||||
|
||||
public void saveSnapshot(String filename, String format) throws IOException;
|
||||
|
||||
public void copy();
|
||||
|
||||
//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,501 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot;
|
||||
|
||||
import ch.psi.plot.utils.IO;
|
||||
import ch.psi.plot.utils.MonitoredPanel;
|
||||
import ch.psi.plot.utils.SwingUtils;
|
||||
import ch.psi.plot.utils.SwingUtils.ExtensionFileFilter;
|
||||
import ch.psi.plot.utils.SwingUtils.ImageTransferHandler;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.datatransfer.Clipboard;
|
||||
import java.awt.datatransfer.ClipboardOwner;
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.print.PageFormat;
|
||||
import java.awt.print.Printable;
|
||||
import java.awt.print.PrinterException;
|
||||
import java.awt.print.PrinterJob;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
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> extends MonitoredPanel implements Plot<T>, Printable {
|
||||
|
||||
final String LINE_SEPARATOR = System.lineSeparator();
|
||||
final String FIELD_SEPARATOR = "\t";
|
||||
|
||||
protected static final int PREFERRED_WIDTH = 500;
|
||||
protected static final int PREFERRED_HEIGHT = 270;
|
||||
|
||||
final Class seriesType;
|
||||
|
||||
protected PlotBase(Class<T> seriesType) {
|
||||
this(seriesType, null);
|
||||
}
|
||||
|
||||
volatile boolean instantiated;
|
||||
|
||||
protected PlotBase(Class<T> seriesType, String title) {
|
||||
super();
|
||||
if (title == null) {
|
||||
title = "Plot";
|
||||
}
|
||||
setTitle(title);
|
||||
this.seriesType = seriesType;
|
||||
// SwingUtilities.invokeLater(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
try {
|
||||
createChart();
|
||||
createPopupMenu();
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(PlotBase.class.getName()).log(Level.INFO, null, ex);
|
||||
}
|
||||
// }
|
||||
// });
|
||||
instantiated=true;
|
||||
}
|
||||
String title;
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
if (instantiated)
|
||||
onTitleChanged();
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
|
||||
Font titleFont;
|
||||
|
||||
public void setTitleFont(Font font) {
|
||||
this.titleFont = font;
|
||||
if (instantiated)
|
||||
onTitleChanged();
|
||||
}
|
||||
|
||||
public Font getTitleFont() {
|
||||
return titleFont;
|
||||
}
|
||||
|
||||
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;
|
||||
*/
|
||||
@Override
|
||||
public BufferedImage getSnapshot() {
|
||||
return SwingUtils.createImage(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveSnapshot(String filename, String format) throws IOException {
|
||||
IO.writeImageToFile(getSnapshot(), filename, format);
|
||||
}
|
||||
|
||||
public void copy() {
|
||||
BufferedImage img = getSnapshot();
|
||||
if (img != null) {
|
||||
ImageTransferHandler imageSelection = new ImageTransferHandler(img);
|
||||
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
|
||||
clipboard.setContents(imageSelection, new ClipboardOwner() {
|
||||
@Override
|
||||
public void lostOwnership(Clipboard clipboard, Transferable contents) {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//Printable interface
|
||||
public int print(Graphics g, PageFormat pf, int page) throws PrinterException {
|
||||
|
||||
if (page > 0) {
|
||||
return NO_SUCH_PAGE;
|
||||
}
|
||||
|
||||
BufferedImage img = getSnapshot();
|
||||
|
||||
//Schrinks the image if too big but does not expand it
|
||||
double scaleX = img.getWidth()>pf.getImageableWidth() ? ((double) pf.getImageableWidth()) / img.getWidth() : 1.0;
|
||||
double scaleY = img.getHeight() > pf.getImageableHeight() ? ((double) pf.getImageableHeight()) / img.getHeight() : 1.0;
|
||||
double scale = Math.min(scaleX, scaleY); //Keep aspect ratio
|
||||
AffineTransform transf = new AffineTransform();
|
||||
transf.scale(scale, scale);
|
||||
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
g2d.translate(pf.getImageableX(), pf.getImageableY());
|
||||
g2d.drawImage(img, transf, null);
|
||||
//g2d.drawImage(img,0,0,null);
|
||||
return PAGE_EXISTS;
|
||||
}
|
||||
|
||||
protected void createChart() {
|
||||
|
||||
}
|
||||
|
||||
protected void createPopupMenu() {
|
||||
addPopupMenuItem(null);//Separator
|
||||
|
||||
JMenuItem saveSnapshot = new JMenuItem("Save Image As...");
|
||||
saveSnapshot.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
|
||||
JFileChooser chooser = new JFileChooser(".");
|
||||
chooser.addChoosableFileFilter(new ExtensionFileFilter("PNG files (*.png)", new String[]{"png"}));
|
||||
chooser.addChoosableFileFilter(new ExtensionFileFilter("Bitmap files (*.bmp)", new String[]{"bmp"}));
|
||||
chooser.addChoosableFileFilter(new ExtensionFileFilter("JPEG files (*.jpg)", new String[]{"jpg", "jpeg"}));
|
||||
chooser.setAcceptAllFileFilterUsed(false);
|
||||
if (chooser.showSaveDialog(PlotBase.this) == JFileChooser.APPROVE_OPTION) {
|
||||
|
||||
String filename = chooser.getSelectedFile().getAbsolutePath();
|
||||
String type = "png";
|
||||
String ext = IO.getExtension(chooser.getSelectedFile());
|
||||
for (String fe : new String[]{"bmp", "jpg"}) {
|
||||
if ((chooser.getFileFilter().getDescription().contains(fe))
|
||||
|| (fe.equals(ext))) {
|
||||
type = fe;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ext == null) {
|
||||
filename += "." + type;
|
||||
}
|
||||
if (new File(filename).exists()) {
|
||||
if (SwingUtils.showOption(PlotBase.this, "Overwrite", "File " + filename + " already exists.\nDo you want to overwrite it?", javax.swing.JOptionPane.YES_NO_OPTION) == javax.swing.JOptionPane.NO_OPTION) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
saveSnapshot(filename, type);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
SwingUtils.showException(PlotBase.this, ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
addPopupMenuItem(saveSnapshot);
|
||||
|
||||
JMenuItem saveData = new JMenuItem("Save Data As...");
|
||||
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(PlotBase.this);
|
||||
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(PlotBase.this, ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
addPopupMenuItem(saveData);
|
||||
|
||||
JMenuItem print = new JMenuItem("Print...");
|
||||
print.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
PrinterJob job = PrinterJob.getPrinterJob();
|
||||
job.setPrintable(PlotBase.this);
|
||||
|
||||
PrinterJob pj = PrinterJob.getPrinterJob();
|
||||
//PageFormat pdef=pj.defaultPage();
|
||||
//PageFormat pf = pj.pageDialog(pdef);
|
||||
//if (pf!=pdef){
|
||||
if (job.printDialog()) {
|
||||
job.print();
|
||||
}
|
||||
//}
|
||||
} catch (Exception ex) {
|
||||
SwingUtils.showException(PlotBase.this, ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
addPopupMenuItem(print);
|
||||
|
||||
JMenuItem copy = new JMenuItem("Copy");
|
||||
copy.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
copy();
|
||||
} catch (Exception ex) {
|
||||
SwingUtils.showException(PlotBase.this, ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
addPopupMenuItem(copy);
|
||||
}
|
||||
|
||||
/**
|
||||
* null for separator
|
||||
*/
|
||||
abstract protected void addPopupMenuItem(JMenuItem item);
|
||||
|
||||
//Series list support
|
||||
final HashMap<String, T> seriesList = new HashMap<>();
|
||||
volatile int seriesID = 1;
|
||||
|
||||
@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.id = seriesID++;
|
||||
series.setToken(onAddedSeries(series));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSeries(T[] series) {
|
||||
for (T s : series) {
|
||||
addSeries(s);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSeries(T series) {
|
||||
if (series != null) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getSeries(int index) {
|
||||
synchronized (seriesList) {
|
||||
if ((index < 0) || (index >= seriesList.size())) {
|
||||
return null;
|
||||
}
|
||||
return getAllSeries()[index];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfSeries() {
|
||||
return seriesList.size();
|
||||
}
|
||||
|
||||
public class SeriesComparator implements Comparator<T> {
|
||||
|
||||
@Override
|
||||
public int compare(T o1, T o2) {
|
||||
return Integer.valueOf(o1.id).compareTo(Integer.valueOf(o2.id));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T[] getAllSeries() {
|
||||
synchronized (seriesList) {
|
||||
ArrayList<T> list = new ArrayList();
|
||||
for (T series : seriesList.values()) {
|
||||
list.add(series);
|
||||
}
|
||||
Collections.sort(list, new SeriesComparator());
|
||||
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 onTitleChanged() {
|
||||
if (isUpdatesEnabled()) {
|
||||
doUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
protected void onAxisLabelChanged(AxisId axis) {
|
||||
if (isUpdatesEnabled()) {
|
||||
doUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
protected void onAxisRangeChanged(AxisId axis) {
|
||||
if (isUpdatesEnabled()) {
|
||||
doUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
//Static Configuration
|
||||
//Hardware Acceleration
|
||||
static boolean hardwareAccelerated = true;
|
||||
|
||||
public static void setHardwareAccelerated(boolean value) {
|
||||
hardwareAccelerated = value;
|
||||
}
|
||||
|
||||
public static boolean getHardwareAccelerated() {
|
||||
return hardwareAccelerated;
|
||||
}
|
||||
|
||||
static boolean lighweightPopups = true;
|
||||
|
||||
public static void setLighweightPopups(boolean value) {
|
||||
lighweightPopups = value;
|
||||
if (javax.swing.JPopupMenu.getDefaultLightWeightPopupEnabled() != value) {
|
||||
javax.swing.JPopupMenu.setDefaultLightWeightPopupEnabled(lighweightPopups);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean getLighweightPopups() {
|
||||
return lighweightPopups;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public abstract class PlotSeries<T extends Plot> {
|
||||
|
||||
volatile boolean updating = false;
|
||||
volatile int id;
|
||||
|
||||
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,668 @@
|
||||
/*
|
||||
* 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.ArrayList;
|
||||
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.JPopupMenu;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class LinePlot extends ch.psi.plot.LinePlotBase {
|
||||
|
||||
final boolean HOVERING_SYMBOLS = true;
|
||||
|
||||
public LinePlot() {
|
||||
super();
|
||||
setRequireUpdateOnAppend(false);
|
||||
}
|
||||
|
||||
protected void onTitleChanged() {
|
||||
Platform.runLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
chart.setId(getTitle());
|
||||
chart.setTitle(getTitle());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void onAxisLabelChanged(final AxisId axis) {
|
||||
//TODO
|
||||
/*
|
||||
Platform.runLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
switch (axis){
|
||||
case X:
|
||||
break;
|
||||
case Y:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@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());
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
LinePlotSeries getLinePlotSeries(XYChart.Series s) {
|
||||
for (LinePlotSeries series:this.getAllSeries())
|
||||
if (series.getToken()==s)
|
||||
return series;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doUpdate() {
|
||||
if (mTimerFX != null) {
|
||||
Platform.runLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateFX();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private JFXPanel fxContainer;
|
||||
|
||||
@Override
|
||||
protected void createChart() {
|
||||
super.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 = new MyLineChart<>(xAxis, yAxis);
|
||||
chart.setAnimated(false);
|
||||
chart.setCreateSymbols(false);
|
||||
chart.setCursor(Cursor.CROSSHAIR);
|
||||
|
||||
|
||||
|
||||
fxContainer.setPreferredSize(new Dimension(PREFERRED_WIDTH, PREFERRED_HEIGHT));
|
||||
setLayout(new BorderLayout());
|
||||
add(fxContainer);
|
||||
// create JavaFX scene
|
||||
Platform.runLater(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
createScene();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
//if (!isUpdatesEnabled())
|
||||
// return;
|
||||
synchronized (seriesList) {
|
||||
for (Iterator<Series> it = seriesList.keySet().iterator(); it.hasNext();) {
|
||||
XYChart.Series series = it.next();
|
||||
LinePlotSeries lps = getLinePlotSeries(series);
|
||||
int maxItemCount = (lps==null) ? -1 : lps.getMaxItemCount();
|
||||
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);
|
||||
if ((maxItemCount>0)&&(series.getData().size()>maxItemCount)){
|
||||
series.getData().remove(0, series.getData().size()-maxItemCount);
|
||||
}
|
||||
|
||||
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() {
|
||||
ArrayList<XYChart.Series> list=new ArrayList<>();
|
||||
for (Iterator<Series<Number, Number>> it = chart.getData().iterator(); it.hasNext();) {
|
||||
XYChart.Series series = it.next();
|
||||
if (!seriesList.keySet().contains(series)) {
|
||||
list.add(series);
|
||||
}
|
||||
}
|
||||
for (XYChart.Series series:list)
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
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 menuFx = new Menu(item.getText());
|
||||
for (Component menuItem : ((JMenu) item).getMenuComponents()) {
|
||||
if (menuItem instanceof JMenu) {
|
||||
addSwingMenuItem(menuFx.getItems(), ((JMenu) menuItem));
|
||||
} else if (menuItem instanceof JPopupMenu.Separator) {
|
||||
menuFx.getItems().add(new SeparatorMenuItem());
|
||||
} else if (menuItem instanceof JMenuItem) {
|
||||
addSwingMenuItem(menuFx.getItems(), ((JMenuItem) menuItem));
|
||||
}
|
||||
}
|
||||
menu.add(menuFx);
|
||||
} 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,588 @@
|
||||
package ch.psi.plot.jfree;
|
||||
|
||||
import ch.psi.plot.LinePlotBase;
|
||||
import ch.psi.plot.LinePlotSeries;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.print.PageFormat;
|
||||
import java.awt.print.PrinterException;
|
||||
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.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;
|
||||
|
||||
//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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackground(Color c){
|
||||
super.setBackground(c);
|
||||
if (chartPanel!=null){
|
||||
chartPanel.setBackground(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@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());
|
||||
if (series.getMaxItemCount()>0){
|
||||
s.setMaximumItemCount(series.getMaxItemCount());
|
||||
}
|
||||
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 void createChart() {
|
||||
super.createChart();
|
||||
|
||||
data = new XYSeriesCollection();
|
||||
// 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);
|
||||
|
||||
// Remove border
|
||||
chartPanel.getChart().setBorderVisible(false);
|
||||
|
||||
// Set size of chart
|
||||
chartPanel.setPreferredSize(new java.awt.Dimension(PREFERRED_WIDTH, PREFERRED_HEIGHT));
|
||||
|
||||
chartPanel.setBackground(getBackground());
|
||||
|
||||
//Activate (arrow) keys
|
||||
addKeyBindings();
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
add(chartPanel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTitleChanged() {
|
||||
chartPanel.setName(getTitle());
|
||||
chart.setTitle(getTitle());
|
||||
if(getTitleFont()!=null)
|
||||
chart.getTitle().setFont(getTitleFont());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAxisLabelChanged(AxisId axis) {
|
||||
switch (axis){
|
||||
case X:
|
||||
chart.getXYPlot().getDomainAxis().setLabel(getAxis(AxisId.X).getLabel());
|
||||
break;
|
||||
case Y:
|
||||
chart.getXYPlot().getRangeAxis().setLabel(getAxis(AxisId.Y).getLabel());
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAxisRangeChanged(AxisId axisId) {
|
||||
ValueAxis axis = null;
|
||||
|
||||
switch (axisId) {
|
||||
case X:
|
||||
axis = chart.getXYPlot().getDomainAxis();
|
||||
break;
|
||||
case Y:
|
||||
axis = chart.getXYPlot().getRangeAxis();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if (getAxis(axisId).isAutoRange()) {
|
||||
axis.setAutoRange(true);
|
||||
} else {
|
||||
axis.setRange(new Range(getAxis(axisId).getMin(), getAxis(axisId).getMax()), true, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@Override
|
||||
protected void createPopupMenu() {
|
||||
//Remove copy/save as/print menus: copy is buggy, save is limited
|
||||
for (int index=6;index>=2;index--)
|
||||
chartPanel.getPopupMenu().remove(index);
|
||||
|
||||
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
super.createPopupMenu();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
*/
|
||||
|
||||
@Override
|
||||
public int print(Graphics g, PageFormat pf, int page) throws PrinterException {
|
||||
return chartPanel.print(g, pf, page);
|
||||
}
|
||||
}
|
||||
@@ -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,521 @@
|
||||
package ch.psi.plot.jfree;
|
||||
|
||||
import ch.psi.plot.MatrixPlotBase;
|
||||
import ch.psi.plot.MatrixPlotSeries;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.print.PageFormat;
|
||||
import java.awt.print.PrinterException;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Arrays;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
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 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;
|
||||
NumberAxis xAxis, yAxis;
|
||||
XYBlockRenderer renderer;
|
||||
|
||||
public MatrixPlot() {
|
||||
super();
|
||||
}
|
||||
|
||||
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.NaN);
|
||||
Arrays.fill(yvalues, Double.NaN);
|
||||
Arrays.fill(zvalues, Double.NaN);
|
||||
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);
|
||||
|
||||
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 onTitleChanged() {
|
||||
chartPanel.setName(getTitle());
|
||||
chart.setTitle(getTitle());
|
||||
if(getTitleFont()!=null)
|
||||
chart.getTitle().setFont(getTitleFont());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAxisLabelChanged(AxisId axis) {
|
||||
switch (axis) {
|
||||
case X:
|
||||
xAxis.setLabel(getAxis(AxisId.X).getLabel());
|
||||
break;
|
||||
case Y:
|
||||
yAxis.setLabel(getAxis(AxisId.Y).getLabel());
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onAxisRangeChanged(AxisId axisId) {
|
||||
// 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 (axisId == 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 (axisId == 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createPopupMenu() {
|
||||
//Remove copy/save as/print menus: copy is buggy, save is limited
|
||||
for (int index=6;index>=2;index--)
|
||||
chartPanel.getPopupMenu().remove(index);
|
||||
|
||||
// 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);
|
||||
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);
|
||||
*/
|
||||
super.createPopupMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (series!=null){
|
||||
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 void createChart() {
|
||||
super.createChart();
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
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(PREFERRED_WIDTH, PREFERRED_HEIGHT));
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
add(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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int print(Graphics g, PageFormat pf, int page) throws PrinterException {
|
||||
return chartPanel.print(g, pf, page);
|
||||
}
|
||||
|
||||
|
||||
//public JFreeChart getChart() {
|
||||
// return chart;
|
||||
//}
|
||||
//@Override
|
||||
//public void setData(Object data){
|
||||
// super.setData(data);
|
||||
// this.data=(MatrixPlotSeries) data;
|
||||
//}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
|
||||
*/
|
||||
package ch.psi.plot.utils;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class IO {
|
||||
|
||||
public static void writeArrayToFile(String filename, byte[] arr) throws IOException {
|
||||
Files.write(Paths.get(filename),arr);
|
||||
}
|
||||
|
||||
public static void writeStringToFile(String filename, String str) throws IOException {
|
||||
writeArrayToFile(filename, str.getBytes(StandardCharsets.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,45 @@
|
||||
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 java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
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) {
|
||||
Logger.getLogger(MonitoredPanel.class.getName()).log(Level.FINE, null, ex);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
onHidden();
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(MonitoredPanel.class.getName()).log(Level.FINE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void onShown() {
|
||||
}
|
||||
|
||||
protected void onHidden() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* 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.Image;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.util.Random;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.TransferHandler;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
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(long seed) {
|
||||
Random random = new Random(seed);
|
||||
return generateRandomColor(random);
|
||||
}
|
||||
|
||||
public static Color generateRandomColor() {
|
||||
Random random = new Random();
|
||||
return generateRandomColor(random);
|
||||
}
|
||||
|
||||
public static Color generateRandomColor(Random 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 int showOption(Component parent, String title, String msg, int optionType)
|
||||
{
|
||||
return JOptionPane.showOptionDialog(parent,msg,title,optionType,JOptionPane.QUESTION_MESSAGE,null,null,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;
|
||||
}
|
||||
|
||||
public static class ImageTransferHandler extends TransferHandler implements Transferable {
|
||||
|
||||
private static final DataFlavor[] dataFlavors = {DataFlavor.imageFlavor};
|
||||
private Image image;
|
||||
|
||||
public ImageTransferHandler(Image data) {
|
||||
this.image = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTransferData(DataFlavor flavor) {
|
||||
if (isDataFlavorSupported(flavor)) {
|
||||
return image;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataFlavor[] getTransferDataFlavors() {
|
||||
return dataFlavors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSourceActions(JComponent c) {
|
||||
return TransferHandler.COPY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canImport(JComponent comp, DataFlavor flavor[]) {
|
||||
if (!(comp instanceof JLabel)) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0, n = flavor.length; i < n; i++) {
|
||||
for (int j = 0, m = dataFlavors.length; j < m; j++) {
|
||||
if (flavor[i].equals(dataFlavors[j])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDataFlavorSupported(DataFlavor flavor) {
|
||||
return flavor.equals(DataFlavor.imageFlavor);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ExtensionFileFilter extends FileFilter {
|
||||
|
||||
String description;
|
||||
|
||||
String extensions[];
|
||||
|
||||
public ExtensionFileFilter(String description, String extension) {
|
||||
this(description, new String[]{extension});
|
||||
}
|
||||
|
||||
public ExtensionFileFilter(String description, String extensions[]) {
|
||||
if (description == null) {
|
||||
this.description = extensions[0];
|
||||
} else {
|
||||
this.description = description;
|
||||
}
|
||||
this.extensions = (String[]) extensions.clone();
|
||||
for (int i = 0, n = extensions.length; i < n; i++) {
|
||||
extensions[i] = extensions[i].toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public boolean accept(File file) {
|
||||
if (file.isDirectory()) {
|
||||
return true;
|
||||
} else {
|
||||
String path = file.getAbsolutePath().toLowerCase();
|
||||
for (int i = 0, n = extensions.length; i < n; i++) {
|
||||
String extension = extensions[i];
|
||||
if ((path.endsWith(extension) && (path.charAt(path.length() - extension.length() - 1)) == '.')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,549 +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 {
|
||||
|
||||
|
||||
// Get Logger
|
||||
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;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param title Title of plot
|
||||
*/
|
||||
public LinePlot(String title){
|
||||
this(title, new XYSeriesCollectionP());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @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 frame
|
||||
*/
|
||||
public void amendContextMenu(){
|
||||
|
||||
chartPanel.getPopupMenu().addSeparator();
|
||||
|
||||
JMenu toolsMenu = new JMenu("Tools");
|
||||
chartPanel.getPopupMenu().add(toolsMenu);
|
||||
|
||||
// Manipulation function
|
||||
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);
|
||||
// System.out.println("Average: "+a);
|
||||
|
||||
// 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
// chartPanel.getPopupMenu().add(averageMenuItem);
|
||||
toolsMenu.add(averageMenuItem);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
// chartPanel.getPopupMenu().add(minimumMenuItem);
|
||||
toolsMenu.add(minimumMenuItem);
|
||||
|
||||
|
||||
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);
|
||||
// System.out.println("Maximum: "+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("Maximum: "+m.getXValue() +" / "+ m.getYValue());
|
||||
chartPanel.getChart().getXYPlot().addAnnotation(cross);
|
||||
}
|
||||
}
|
||||
});
|
||||
// chartPanel.getPopupMenu().add(maximumMenuItem);
|
||||
toolsMenu.add(maximumMenuItem);
|
||||
|
||||
JMenuItem derivativeMenuItem = new JMenuItem("Derivative");
|
||||
derivativeMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Derivative derivative = new Derivative();
|
||||
// for (XYSeriesP series : data.getSeries()) {
|
||||
// // Show derivative in same plot
|
||||
// final XYSeriesP s = derivative.derivative(series);
|
||||
// SwingUtilities.invokeLater(new Runnable() { // Avoid concurrent modification exception
|
||||
// @Override
|
||||
// public void run() {
|
||||
// data.addSeries(s); // Add Derivative
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// Show new frame
|
||||
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);
|
||||
}
|
||||
});
|
||||
// chartPanel.getPopupMenu().add(derivativeMenuItem);
|
||||
toolsMenu.add(derivativeMenuItem);
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
// chartPanel.getPopupMenu().add(integralMenuItem);
|
||||
toolsMenu.add(integralMenuItem);
|
||||
|
||||
chartPanel.getPopupMenu().addSeparator();
|
||||
|
||||
// // Plot all series of the plot in a own plot
|
||||
// JMenuItem splitPlotMenuItem = new JMenuItem("Split");
|
||||
// splitPlotMenuItem.addActionListener(new ActionListener() {
|
||||
// @Override
|
||||
// public void actionPerformed(ActionEvent e) {
|
||||
// for (XYSeriesP serie : data.getSeries()) {
|
||||
// XYSeriesCollectionP collection = new XYSeriesCollectionP();
|
||||
// collection.addSeries(serie);
|
||||
//
|
||||
// int index = data.indexOf(serie);
|
||||
// //The right colors are not automatically assigned
|
||||
// Paint paint = chart.getXYPlot().getRenderer().getSeriesPaint(index);
|
||||
// LinePlot p = new LinePlot((String) serie.getKey(), collection);
|
||||
// // there is only one series in this plot, so we choose index 0 to assign paint
|
||||
// p.getChartPanel().getChart().getXYPlot().getRenderer().setSeriesPaint(0, paint);
|
||||
//
|
||||
// JFrame frame = new JFrame();
|
||||
// frame.setContentPane(p.getChartPanel());
|
||||
// frame.pack();
|
||||
// RefineryUtilities.centerFrameOnScreen(frame);
|
||||
// frame.setVisible(true);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// chartPanel.getPopupMenu().add(splitPlotMenuItem);
|
||||
|
||||
// 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);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Show tooltips
|
||||
*/
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide tooltips
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.plot.Plot#update()
|
||||
*/
|
||||
@Override
|
||||
public void update() {
|
||||
// Fire chart change event
|
||||
// chart.fireChartChanged();
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.plot.Plot#getChart()
|
||||
*/
|
||||
@Override
|
||||
public JFreeChart getChart() {
|
||||
return chart;
|
||||
}
|
||||
|
||||
//getter and setter
|
||||
public XYSeriesCollectionP getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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,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,62 +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;
|
||||
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
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,81 +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;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
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,66 +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;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
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,52 +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;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
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,52 +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;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
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,87 +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;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
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,409 +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.DatasetChangeEvent;
|
||||
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 DynamicXYZDataset 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<DynamicXYZDataset.Vector> items = new ArrayList<DynamicXYZDataset.Vector>();
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public DynamicXYZDataset(){
|
||||
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(double x, double y, double z){
|
||||
items.add(new DynamicXYZDataset.Vector(x,y,z));
|
||||
|
||||
// Update axis
|
||||
|
||||
|
||||
// if(Double.isNaN(xLowerBound) && Double.isNaN(xUpperBound)){
|
||||
// xLowerBound = x-incX;
|
||||
// xUpperBound = x+incX;
|
||||
// xAxis.setRange(xLowerBound, xUpperBound);
|
||||
// }
|
||||
// else{
|
||||
// if(x>(xUpperBound+incX)){
|
||||
// xUpperBound = x+incX;
|
||||
// xAxis.setUpperBound(xUpperBound);
|
||||
// }
|
||||
// else if(x<xLowerBound-incX){
|
||||
// xLowerBound = x-incX;
|
||||
// xAxis.setLowerBound(xLowerBound);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if(Double.isNaN(yLowerBound) && Double.isNaN(yUpperBound)){
|
||||
// yLowerBound = y-incY;
|
||||
// yUpperBound = y+incY;
|
||||
// yAxis.setRange(yLowerBound, yUpperBound);
|
||||
// }
|
||||
// else{
|
||||
// if(y>(yUpperBound+incY)){
|
||||
// yUpperBound = y+incY;
|
||||
// yAxis.setUpperBound(yUpperBound);
|
||||
// }
|
||||
// else if(y<yLowerBound-incY){
|
||||
// yLowerBound = y-incY;
|
||||
// yAxis.setLowerBound(yLowerBound);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if(Double.isNaN(zLowerBound) && Double.isNaN(zUpperBound)){
|
||||
// zLowerBound = z;
|
||||
// zUpperBound = z;
|
||||
// }
|
||||
// else{
|
||||
// if(z>zUpperBound){
|
||||
// zUpperBound = z;
|
||||
// }
|
||||
// else if(z<zLowerBound){
|
||||
// zLowerBound = z;
|
||||
// }
|
||||
// }
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
/* (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();
|
||||
}
|
||||
|
||||
/* (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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* (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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return the xLowerBound
|
||||
*/
|
||||
public double getxLowerBound() {
|
||||
return xLowerBound;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the xUpperBound
|
||||
*/
|
||||
public double getxUpperBound() {
|
||||
return xUpperBound;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the yLowerBound
|
||||
*/
|
||||
public double getyLowerBound() {
|
||||
return yLowerBound;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the yUpperBound
|
||||
*/
|
||||
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,388 +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.DatasetChangeEvent;
|
||||
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 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<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;
|
||||
incX = xResolution/2;
|
||||
incY = yResolution/2;
|
||||
|
||||
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);
|
||||
// renderer.setBaseCreateEntities(true, false);
|
||||
// renderer.setBaseCreateEntities(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,381 +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.DatasetChangeEvent;
|
||||
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 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,361 +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 MatrixPlot2 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 DynamicXYZDatasetList data;
|
||||
private JFreeChart chart;
|
||||
private ChartPanel chartPanel;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @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,194 +0,0 @@
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
//import java.util.Arrays;
|
||||
|
||||
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 {
|
||||
|
||||
// Get Logger
|
||||
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,73 +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;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
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,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
|
||||
<Properties>
|
||||
<Property name="defaultCloseOperation" type="int" value="3"/>
|
||||
</Properties>
|
||||
<SyntheticProperties>
|
||||
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
|
||||
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
|
||||
</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">
|
||||
<Component id="plot" alignment="0" pref="520" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="plot" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="ch.psi.plot.jlchart.LinePlot" name="plot">
|
||||
<Properties>
|
||||
<Property name="title" type="java.lang.String" value="Frame Test"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
/**
|
||||
* 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.getAxis(Plot.AxisId.X).setLabel("aaa");
|
||||
//linePlot.getAxis(Plot.AxisId.Y).setLabel("bbb");
|
||||
|
||||
//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.setContentPane((JPanel)linePlot);
|
||||
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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// plot.removeSeries(plot.getSeries(0));
|
||||
// plot.removeSeries(plot.getSeries(1));
|
||||
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.PlotBase;
|
||||
import ch.psi.plot.xyz.generator.Gauss2D;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.WindowConstants;
|
||||
|
||||
/**
|
||||
* Test case for MatrixPlot class
|
||||
*
|
||||
*/
|
||||
public class MatrixPlotTest {
|
||||
final static int sleepTime = 1;
|
||||
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 {
|
||||
PlotBase.setLighweightPopups(false);
|
||||
//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);
|
||||
// plot.getAxis(Plot.AxisId.X).setLabel("aaa");
|
||||
// plot.getAxis(Plot.AxisId.Y).setLabel("bbb");
|
||||
// plot.getAxis(Plot.AxisId.Z).setLabel("ccc");
|
||||
|
||||
final JFrame frame = new JFrame("");
|
||||
frame.setContentPane((JPanel)plot);
|
||||
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,61 @@
|
||||
/*
|
||||
* 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 java.lang.reflect.InvocationTargetException;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.WindowConstants;
|
||||
|
||||
/**
|
||||
* Test case for MatrixPlot class
|
||||
*
|
||||
*/
|
||||
public class MatrixPlotTest2 {
|
||||
|
||||
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, InvocationTargetException {
|
||||
final ch.psi.plot.MatrixPlot plot = new ch.psi.plot.jzy3d.MatrixPlot();
|
||||
plot.setTitle("Matrix Plot Test");
|
||||
|
||||
|
||||
double[][] d= new double[201][101];
|
||||
int indexX=0,indexY=0;
|
||||
for (double y = startY; y <= startY + stepsY * stepSizeY; y += stepSizeY, indexY++) {
|
||||
indexX=0;
|
||||
for (double x = startX; x <= startX + stepsX * stepSizeX; x += stepSizeX, indexX++) {
|
||||
d[indexY][indexX]= generator.generate(x, y) + 5.0;
|
||||
}
|
||||
}
|
||||
|
||||
plot.addSeries(data);
|
||||
data.setData(d);
|
||||
|
||||
|
||||
|
||||
|
||||
final JFrame frame = new JFrame("");
|
||||
frame.setContentPane((JPanel)plot);
|
||||
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();
|
||||
}
|
||||
});
|
||||
//Thread.sleep(360000);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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((JPanel)linePlot);
|
||||
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 = (JPanel) linePlot;
|
||||
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((JPanel)linePlot);
|
||||
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((JPanel)linePlot);
|
||||
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((JPanel)linePlot);
|
||||
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((JPanel)linePlot);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user