Version 2: Abstraction of graphs & new implementations: JZY3D, JavaFX, JFreeChart

This commit is contained in:
2014-08-12 16:40:57 +02:00
parent 4be942e0fc
commit d7f7c776e6
107 changed files with 4946 additions and 12214 deletions
+33 -7
View File
@@ -2,8 +2,14 @@
<modelVersion>4.0.0</modelVersion>
<groupId>ch.psi</groupId>
<artifactId>plot</artifactId>
<version>1.1.31</version>
<version>2.0-SNAPSHOT</version>
<repositories>
<repository>
<id>jzy3d-releases</id>
<name>Jzy3d Snapshots</name>
<url>http://www.jzy3d.org/maven/releases</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.jfree</groupId>
@@ -16,18 +22,29 @@
<version>4.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependency>
<groupId>fr.esrf.tangoatk.widget.util.chart</groupId>
<artifactId>JLChart</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.jzy3d</groupId>
<artifactId>jzy3d-api</artifactId>
<version>0.9.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<encoding>UTF-8</encoding>
<source>1.7</source>
<target>1.7</target>
<target>1.7</target>
</configuration>
</plugin>
</plugin>
<!-- Generate Javadoc Jar -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -39,6 +56,9 @@
<goals>
<goal>jar</goal>
</goals>
<configuration>
<additionalparam>-Xdoclint:none</additionalparam>
</configuration>
</execution>
</executions>
</plugin>
@@ -55,7 +75,7 @@
</goals>
</execution>
</executions>
</plugin>
</plugin>
</plugins>
</build>
@@ -71,4 +91,10 @@
<url>http://yoke/artifactory/libs-releases-local</url>
</repository>
</distributionManagement>
<!-- G
<properties>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
-->
</project>
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
package ch.psi.plot;
import ch.psi.plot.Plot.AxisId;
/**
*
*/
public class Axis {
PlotBase plot;
AxisId id;
Axis(String label, PlotBase plot, AxisId id) {
this.plot = plot;
this.id = id;
if (label == null) {
label = "";
}
this.label = label;
}
String label = "";
public String getLabel() {
return label;
}
public void setLabel(String value) {
label = value;
plot.onAxisLabelChanged(id);
}
double min;
public double getMin() {
return min;
}
public void setMin(double value) {
min = value;
plot.onAxisRangeChanged(id);
}
double max;
public double getMax() {
return max;
}
public void setMax(double value) {
max = value;
plot.onAxisRangeChanged(id);
}
public void setRange(double min, double max) {
this.min = min;
this.max = max;
plot.onAxisRangeChanged(id);
}
public boolean isAutoRange() {
return (max <= min);
}
public void setAutoRange() {
setRange(0, 0);
}
}
@@ -0,0 +1,10 @@
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
package ch.psi.plot;
/**
*
*/
public interface LinePlot extends Plot<LinePlotSeries> {
}
@@ -0,0 +1,155 @@
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
package ch.psi.plot;
import ch.psi.plot.LinePlotSeries.LinePlotSeriesListener;
import ch.psi.plot.utils.IO;
import ch.psi.plot.utils.SwingUtils;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
/**
* TODO: FDA calls to .update -> requestUpdate()
*/
abstract public class LinePlotBase extends PlotBase<LinePlotSeries> implements LinePlot {
private String xAxisLabel = "X";
private String yAxisLabel = "Y";
protected LinePlotBase() {
this(null);
}
protected LinePlotBase(String title) {
super(LinePlotSeries.class, title);
createAxis(AxisId.X, "X");
createAxis(AxisId.Y, "Y");
}
//TODO: Improve it to share the same X rows
@Override
public void saveData(String filename) throws IOException {
StringBuilder str = new StringBuilder(1024);
int numberSeries = getAllSeries().length;
str.append(getAxis(AxisId.X).getLabel().isEmpty() ? "X" : getAxis(AxisId.X).getLabel()).append(FIELD_SEPARATOR);
for (LinePlotSeries series : getAllSeries()) {
str.append(series.getName()).append(FIELD_SEPARATOR);
}
str.append(LINE_SEPARATOR);
int seriesIndex = 0;
for (LinePlotSeries series : getAllSeries()) {
double[][] data = getSeriesData(series);
for (int i = 0; i < data[0].length; i++) {
double x = data[0][i];
double y = data[1][i];
str.append(String.format("%1.6f", x)).append(FIELD_SEPARATOR);
for (int j = 0; j < seriesIndex; j++) {
str.append(String.format("NaN", x)).append(FIELD_SEPARATOR);
}
str.append(String.format("%1.6f", y)).append(FIELD_SEPARATOR);
for (int j = seriesIndex + 1; j < numberSeries; j++) {
str.append(String.format("NaN", x)).append(FIELD_SEPARATOR);
}
str.append(LINE_SEPARATOR);
}
seriesIndex++;
}
IO.writeStringToFile(filename, str.toString());
}
final LinePlotSeriesListener seriesListener = new LinePlotSeriesListener() {
@Override
public void onSeriesAppendData(LinePlotSeries series, double x, double y) {
onAppendData(series, x, y);
if (getRequireUpdateOnAppend() && isUpdatesEnabled()) {
requestSeriesUpdate(series);
}
}
@Override
public void onSeriesSetData(LinePlotSeries series, double[] x, double[] y) {
if (y == null) {
y = new double[0];
}
if ((x == null) || (y.length != x.length)) {
x = new double[y.length];
for (int i = 0; i < x.length; i++) {
x[i] = i;
}
}
onSetData(series, x, y);
if (isUpdatesEnabled()) {
requestSeriesUpdate(series);
}
}
};
/**
* Returns a token to reference underlying data from LinePlotSeries
*/
abstract protected void onAppendData(LinePlotSeries series, double x, double y);
abstract protected void onSetData(LinePlotSeries series, double[] x, double[] y);
//Injecting specific entries in popup menu
@Override
protected void onCreatedPanel() {
addPopupMenuItem(null);//Separator
// Detach plot into a separate frame
JMenu detachPlotMenu = new JMenu("Detach");
String[] implementations = getImplementations();
JMenuItem[] detachPlotMenuItems = new JMenuItem[implementations.length];
ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
LinePlot p = newPlot(e.getActionCommand());
p.setTitle(getTitle());
p.getAxis(AxisId.X).setLabel(getAxis(AxisId.X).getLabel());
p.getAxis(AxisId.Y).setLabel(getAxis(AxisId.Y).getLabel());
for (LinePlotSeries series : getAllSeries()) {
LinePlotSeries detachedSeries = new LinePlotSeries(series.getName(), series.getColor());
p.addSeries(detachedSeries);
detachedSeries.setData(series.getX(), series.getY());
}
JFrame frame = new JFrame(getTitle());
frame.setContentPane(p.getChartPanel());
frame.pack();
SwingUtils.centerOnScreen(frame);
frame.setVisible(true);
} catch (Exception ex) {
SwingUtils.showException(getChartPanel(), ex);
}
}
};
for (int i=0;i<implementations.length;i++){
detachPlotMenuItems[i] = new JMenuItem(implementations[i]);
detachPlotMenuItems[i].addActionListener(listener);
detachPlotMenu.add(detachPlotMenuItems[i]);
}
addPopupMenuItem(detachPlotMenu);
}
// Known Implemenmtations
//TODO: Should add reflection & dynamic including classes?
public static LinePlot newPlot(String impl) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
return (LinePlot) (Class.forName( "ch.psi.plot." + impl + ".LinePlot")).newInstance();
}
public static String[] getImplementations(){
return new String[]{"jfree", "jlchart", "javafx"};
}
}
@@ -0,0 +1,180 @@
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
package ch.psi.plot;
import ch.psi.plot.utils.SwingUtils;
import java.awt.Color;
/**
*
*/
public class LinePlotSeries extends PlotSeries<LinePlot> {
public interface LinePlotSeriesListener {
void onSeriesSetData(LinePlotSeries series, double[] x, double[] y);
void onSeriesAppendData(LinePlotSeries series, double x, double y);
}
public LinePlotSeries(String name) {
this(name, SwingUtils.generateRandomColor());
}
public LinePlotSeries(String name, Color color) {
super(name);
setColor(color);
}
private Color color;
void setColor(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
private int axisY = 1;
void setAxisY(int axis) {
this.axisY = axisY;
}
public int getAxisY() {
return axisY;
}
public void setData(double[] x, double[] y) {
if (getPlot() != null) {
((LinePlotBase) getPlot()).seriesListener.onSeriesSetData(this, x, y);
}
}
public void appendData(double x, double y) {
if (getPlot() != null) {
((LinePlotBase) getPlot()).seriesListener.onSeriesAppendData(this, x, y);
}
}
@Override
public void clear() {
setData(new double[0], new double[0]);
}
public double[] getX() {
if (getPlot() == null) {
return new double[0];
}
return getPlot().getSeriesData(this)[0];
}
public double[] getY() {
if (getPlot() == null) {
return new double[0];
}
return getPlot().getSeriesData(this)[1];
}
public int getCount() {
if (getPlot() == null) {
return 0;
}
return getPlot().getSeriesData(this)[0].length;
}
//Tools
public double getAverage() {
double average = 0.0;
for (double y : getY()) {
average = average + y;
}
return average / getCount();
}
public double[] getMinimum() {
double min = Double.NaN;
double xmin = Double.NaN;
double[][] data = getPlot().getSeriesData(this);
double[] x = data[0];
double[] y = data[1];
for (int i = 0; i < x.length; i++) {
if (Double.isNaN(min) || (y[i] < min)) {
min = y[i];
xmin = x[i];
}
}
return new double[]{xmin, min};
}
public double[] getMaximum() {
double max = Double.NaN;
double xmax = Double.NaN;
double[][] data = getPlot().getSeriesData(this);
double[] x = data[0];
double[] y = data[1];
for (int i = 0; i < x.length; i++) {
if (Double.isNaN(max) || (y[i] > max)) {
max = y[i];
xmax = x[i];
}
}
return new double[]{xmax, max};
}
public double[][] getDerivative() {
if (getCount() <= 2) {
return new double[][]{new double[0], new double[0]};
}
double[][] data = getPlot().getSeriesData(this);
double[] x = data[0];
double[] y = data[1];
double[] dx = new double[getCount() - 2];
double[] dy = new double[getCount() - 2];
for (int i = 1; i < getCount() - 1; i++) { // do not start at 0 but 1 - stop 1 before end
double xi = x[i];
double ximinus1 = x[i - 1];
double xiplus1 = x[i + 1];
double yiminus1 = y[i - 1];
double yiplus1 = y[i + 1];
if (xiplus1 - ximinus1 != 0.0) {
double di = (yiplus1 - yiminus1) / (xiplus1 - ximinus1);
dx[i - 1] = xi;
dy[i - 1] = di;
} else {
dx[i - 1] = xi;
dy[i - 1] = Double.NaN;
}
}
return new double[][]{dx, dy};
}
public double[][] getIntegral() {
if (getCount() <= 1) {
return new double[][]{new double[0], new double[0]};
}
double[][] data = getPlot().getSeriesData(this);
double[] x = data[0];
double[] y = data[1];
double[] ix = new double[getCount() - 1];
double[] iy = new double[getCount() - 1];
double value = 0.0;
for (int i = 1; i < getCount(); i++) { // Leave out 1. point
value += (x[i] - x[i - 1]) * (y[i] + y[i - 1]) / 2.0;
ix[i - 1] = x[i];
iy[i - 1] = value;
}
return new double[][]{ix, iy};
}
}
@@ -0,0 +1,10 @@
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
package ch.psi.plot;
/**
*
*/
public interface MatrixPlot extends Plot<MatrixPlotSeries> {
}
@@ -0,0 +1,160 @@
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
package ch.psi.plot;
import ch.psi.plot.MatrixPlotSeries.MatrixPlotSeriesListener;
import ch.psi.plot.utils.IO;
import ch.psi.plot.utils.SwingUtils;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.HashMap;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
/**
*
*/
abstract public class MatrixPlotBase extends PlotBase<MatrixPlotSeries> implements MatrixPlot {
protected MatrixPlotBase() {
this(null);
}
protected MatrixPlotBase(String title) {
super(MatrixPlotSeries.class, title);
createAxis(AxisId.X, "X");
createAxis(AxisId.Y, "Y");
createAxis(AxisId.Z);
}
//Only supporting one series for now so let's gain some speed
@Override
public void addSeries(MatrixPlotSeries series) {
if (getAllSeries().length > 0) {
removeSeries(getAllSeries()[0]);
}
super.addSeries(series);
}
final MatrixPlotSeriesListener seriesListener = new MatrixPlotSeriesListener() {
@Override
public void onSeriesAppendData(MatrixPlotSeries series, double x, double y, double z) {
if ((series == null) || (getNumberOfSeries() == 0)) {
return;
}
final int indexX = ((int) ((x - series.getMinX()) / series.getBinWidthX()));
final int indexY = ((int) ((y - series.getMinY()) / series.getBinWidthY()));
if (!series.contains(indexX, indexY)) {
return;
}
onAppendData(series, indexX, indexY, x, y, z);
if (getRequireUpdateOnAppend() && isUpdatesEnabled()) {
requestSeriesUpdate(series);
}
}
@Override
public void onSeriesSetData(MatrixPlotSeries series, double[][] data) {
if ((series == null) || (getNumberOfSeries() == 0)) {
return;
}
//TODO: Check consistency of z
onSetData(series, data);
if (isUpdatesEnabled()) {
requestSeriesUpdate(series);
}
}
};
public void saveData(String filename) throws IOException {
if (getAllSeries().length == 0) {
return;
}
MatrixPlotSeries series = getAllSeries()[0];
StringBuilder str = new StringBuilder(1024);
str.append(getAxis(AxisId.X).getLabel().isEmpty() ? "X" : getAxis(AxisId.X).getLabel()).append(FIELD_SEPARATOR);
str.append(getAxis(AxisId.Y).getLabel().isEmpty() ? "Y" : getAxis(AxisId.Y).getLabel()).append(FIELD_SEPARATOR);
str.append(getAxis(AxisId.Z).getLabel().isEmpty() ? "Z" : getAxis(AxisId.Z).getLabel()).append(LINE_SEPARATOR);
double[][] data = getSeriesData(getAllSeries()[0]);
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[0].length; j++) {
double y = series.getMinY() + i * series.getBinWidthY();
double x = series.getMinX() + j * series.getBinWidthX();
double z = data[i][j];
str.append(String.format("%1.6f", x)).append(FIELD_SEPARATOR);
str.append(String.format("%1.6f", y)).append(FIELD_SEPARATOR);
str.append(String.format("%1.6f", z)).append(LINE_SEPARATOR);
}
}
IO.writeStringToFile(filename, str.toString());
}
//Injecting specific entries in popup menu
@Override
protected void onCreatedPanel() {
addPopupMenuItem(null);//Separator
// Detach plot into a separate frame
JMenu detachPlotMenu = new JMenu("Detach");
String[] implementations = getImplementations();
JMenuItem[] detachPlotMenuItems = new JMenuItem[implementations.length];
ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
if (getAllSeries().length == 0) {
return;
}
MatrixPlotSeries s = getAllSeries()[0];
MatrixPlot p = newPlot(e.getActionCommand());
p.setTitle(getTitle());
p.getAxis(AxisId.X).setLabel(getAxis(AxisId.X).getLabel());
p.getAxis(AxisId.Y).setLabel(getAxis(AxisId.Y).getLabel());
p.getAxis(AxisId.Z).setLabel(getAxis(AxisId.Z).getLabel());
MatrixPlotSeries detachedSeries = new MatrixPlotSeries(null, s.getMinX(), s.getMaxX(), s.getNumberOfBinsX(), s.getMinY(), s.getMaxY(), s.getNumberOfBinsY());
p.addSeries(detachedSeries);
detachedSeries.setData(s.getData());
JFrame frame = new JFrame(getTitle());
frame.setContentPane(p.getChartPanel());
frame.pack();
SwingUtils.centerOnScreen(frame);
frame.setVisible(true);
} catch (Exception ex) {
SwingUtils.showException(getChartPanel(), ex);
}
}
};
for (int i=0;i<implementations.length;i++){
detachPlotMenuItems[i] = new JMenuItem(implementations[i]);
detachPlotMenuItems[i].addActionListener(listener);
detachPlotMenu.add(detachPlotMenuItems[i]);
}
addPopupMenuItem(detachPlotMenu);
}
//abstract protected Object onSetSeries(MatrixPlotSeries series);
abstract protected void onAppendData(MatrixPlotSeries series, int indexX, int indexY, double x, double y, double z);
abstract protected void onSetData(MatrixPlotSeries series, double[][] data);
// Known Implemenmtations
//TODO: Should add reflection & dynamic including classes? Should factorize in PlotBase?
public static MatrixPlot newPlot(String impl) throws ClassNotFoundException, InstantiationException, IllegalAccessException{
return (MatrixPlot) (Class.forName( "ch.psi.plot." + impl + ".MatrixPlot")).newInstance();
}
public static String[] getImplementations(){
return new String[]{"jfree", "jzy3d"};
}
}
@@ -0,0 +1,160 @@
package ch.psi.plot;
import java.util.Arrays;
import java.util.logging.Logger;
/**
* PlotData implementation optimized for matrix data.
*/
public class MatrixPlotSeries extends PlotSeries<MatrixPlot> {
public interface MatrixPlotSeriesListener {
void onSeriesSetData(MatrixPlotSeries series, double[][] data);
void onSeriesAppendData(MatrixPlotSeries series, double x, double y, double z);
}
private static final Logger logger = Logger.getLogger(MatrixPlotSeries.class.getName());
private final double minX;
private final double maxX;
private final int numberOfBinsX;
private final double binWidthX;
private final double minY;
private final double maxY;
private final int numberOfBinsY;
private final double binWidthY;
public MatrixPlotSeries(String name, double minX, double maxX, int nX, double minY, double maxY, int nY) {
super(name);
this.minX = minX;
this.maxX = maxX;
this.numberOfBinsX = nX;
this.minY = minY;
this.maxY = maxY;
this.numberOfBinsY = nY;
this.binWidthX = (maxX - minX) / (double) (numberOfBinsX - 1);
this.binWidthY = (maxY - minY) / (double) (numberOfBinsY - 1);
}
public void setData(double[][] data) {
if ((data == null) || (data.length != numberOfBinsY) || (data[0].length != numberOfBinsX)) {
data = new double[numberOfBinsY][numberOfBinsX];
for (int i = 0; i < numberOfBinsY; i++) {
Arrays.fill(data[i], Double.NaN);
}
}
if (getPlot() != null) {
((MatrixPlotBase) getPlot()).seriesListener.onSeriesSetData(this, data);
}
}
public void appendData(double x, double y, double z) {
if (getPlot() != null) {
((MatrixPlotBase) getPlot()).seriesListener.onSeriesAppendData(this, x, y, z);
}
}
public double[][] getData() {
if (getPlot() == null) {
return new double[0][0];
}
return getPlot().getSeriesData(this);
}
@Override
public void clear() {
setData(null);
}
/**
* @return the binWidthX
*/
public double getBinWidthX() {
return binWidthX;
}
/**
* @return the binWidthY
*/
public double getBinWidthY() {
return binWidthY;
}
/**
* @return the minX
*/
public double getMinX() {
return minX;
}
/**
* @return the maxX
*/
public double getMaxX() {
return maxX;
}
/**
* @return the minY
*/
public double getMinY() {
return minY;
}
/**
* @return the maxY
*/
public double getMaxY() {
return maxY;
}
/**
* @return the numberOfBinsX
*/
public int getNumberOfBinsX() {
return numberOfBinsX;
}
/**
* @return the numberOfBinsY
*/
public int getNumberOfBinsY() {
return numberOfBinsY;
}
//Utilities
public boolean contains(int indexX, int indexY) {
return ((indexX <= numberOfBinsX) && (indexX >= 0) && (indexY <= numberOfBinsY) && (indexY >= 0));
}
public double[] minMaxZValue() {
double min = Double.NaN;
double max = Double.NaN;
double[][] data = getData();
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[0].length; j++) {
if (data[i][j] != Double.NEGATIVE_INFINITY) {
if (Double.isNaN(min) || (data[i][j] < min)) {
min = data[i][j];
}
if (Double.isNaN(max) || (data[i][j] > max)) {
max = data[i][j];
}
}
}
}
return new double[]{min, max};
}
}
+60 -37
View File
@@ -1,42 +1,65 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
package ch.psi.plot;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.swing.JPanel;
public interface Plot {
/**
* Get the chart panel
* @return
*/
public ChartPanel getChartPanel();
/**
* Get chart of the plot (e.g. to be able to export the chart as an image)
* @return
*/
public JFreeChart getChart();
/**
* Update plot (notify all components of the plot)
*/
public void update();
/**
*
*/
public interface Plot<T extends PlotSeries> {
public JPanel getChartPanel();
//Request update on event loop
public void update(boolean deferred);
public void setUpdatesEnabled(boolean value);
public boolean isUpdatesEnabled();
//Generic properties
public void setTitle(String title);
public String getTitle();
//Generic operations
public void saveData(String filename) throws IOException;
public BufferedImage getSnapshot();
public void saveSnapshot(String filename, String format) throws IOException;
//Series list management
public void addSeries(T series);
public void addSeries(T[] series);
public void removeSeries(T series);
public T getSeries(String name);
public T getSeries(int index);
public int getNumberOfSeries();
public void updateSeries(T series);
public void requestSeriesUpdate(final T series);
public double[][] getSeriesData(final T series);
public T[] getAllSeries();
public void clear(); //remove all series
//Axis
public enum AxisId {
X, Y, Z;
};
public Axis getAxis(AxisId id);
}
@@ -0,0 +1,333 @@
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
package ch.psi.plot;
import ch.psi.plot.utils.IO;
import ch.psi.plot.utils.SwingUtils;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileNameExtensionFilter;
/**
*
*/
abstract public class PlotBase<T extends PlotSeries> implements Plot<T> {
static{
javax.swing.JPopupMenu.setDefaultLightWeightPopupEnabled(false);
}
final String LINE_SEPARATOR = System.lineSeparator();
final String FIELD_SEPARATOR = "\t";
final Class seriesType;
protected PlotBase(Class<T> seriesType) {
this(seriesType, null);
}
protected PlotBase(Class<T> seriesType, String title) {
if (title == null) {
title = "Plot";
}
setTitle(title);
this.seriesType = seriesType;
}
String title;
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
volatile boolean bUpdating;
public final void update(boolean deferred) {
if ((!deferred) && SwingUtilities.isEventDispatchThread()) {
bUpdating = false;
doUpdate();
} else {
if (!bUpdating) {
bUpdating = true;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (bUpdating) {
bUpdating = false;
try {
doUpdate();
} catch (Exception ex) {
Logger.getLogger(PlotBase.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
});
}
}
}
boolean requireUpdateOnAppend = true;
protected void setRequireUpdateOnAppend(boolean value) {
requireUpdateOnAppend = value;
}
protected boolean getRequireUpdateOnAppend() {
return requireUpdateOnAppend;
}
boolean updatesEnabled = true;
public void setUpdatesEnabled(boolean value) {
updatesEnabled = value;
}
public boolean isUpdatesEnabled() {
return updatesEnabled;
}
/**
* Should be improved in implementations to make it independent of the
* window state;
*/
public BufferedImage getSnapshot() {
return SwingUtils.createImage(getChartPanel());
}
public void saveSnapshot(String filename, String format) throws IOException {
IO.writeImageToFile(getSnapshot(), filename, format);
}
JPanel panel;
public JPanel getChartPanel() {
if (panel == null) {
panel = createChartPanel();
addPopupMenuItem(null);//Separator
JMenuItem saveData = new JMenuItem("Save Data");
saveData.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
JFileChooser chooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter("Text data files", "txt", "dat");
chooser.setFileFilter(filter);
int returnVal = chooser.showSaveDialog(panel);
if (returnVal == JFileChooser.APPROVE_OPTION) {
String filename = chooser.getSelectedFile().getAbsolutePath();
String type = IO.getExtension(chooser.getSelectedFile());
if (type == null) {
type = "txt";
filename += "." + type;
}
saveData(filename);
}
} catch (Exception ex) {
SwingUtils.showException(panel, ex);
}
}
});
addPopupMenuItem(saveData);
JMenuItem saveSnapshot = new JMenuItem("Save Snapshot");
saveSnapshot.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
JFileChooser chooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter("Image File", "png", "jpg", "bmp");
chooser.setFileFilter(filter);
int returnVal = chooser.showSaveDialog(panel);
if (returnVal == JFileChooser.APPROVE_OPTION) {
String filename = chooser.getSelectedFile().getAbsolutePath();
String type = IO.getExtension(chooser.getSelectedFile());
if (type == null) {
type = "png";
filename += "." + type;
}
saveSnapshot(filename, type);
}
} catch (Exception ex) {
SwingUtils.showException(panel, ex);
}
}
});
addPopupMenuItem(saveSnapshot);
onCreatedPanel();
}
return panel;
}
//Overidables
protected void onCreatedPanel() {
}
abstract protected JPanel createChartPanel();
/**
* null for separator
*/
abstract protected void addPopupMenuItem(JMenuItem item);
//Series list support
final HashMap<String, T> seriesList = new HashMap<>();
@Override
public void addSeries(T series) {
if (series.name == null) {
return;
}
T existingSeries = getSeries(series.name);
if (existingSeries == series) {
return;
}
if (existingSeries != null) {
removeSeries(existingSeries);
}
synchronized (seriesList) {
seriesList.put(series.name, series);
}
series.setPlot(this);
series.setToken(onAddedSeries(series));
}
@Override
public void addSeries(T[] series) {
for (T s : series) {
addSeries(s);
}
}
@Override
public void removeSeries(T series) {
if (series.getPlot() == this) {
series.setPlot(null);
}
onRemovedSeries(series);
synchronized (seriesList) {
seriesList.remove(series.name);
}
}
@Override
public T getSeries(String name) {
synchronized (seriesList) {
return seriesList.get(name);
}
}
//TODO: Not respecting order
@Override
public T getSeries(int index) {
synchronized (seriesList) {
if ((index < 0) || (index >= seriesList.size())) {
return null;
}
return seriesList.get(getAllSeries()[index]);
}
}
@Override
public int getNumberOfSeries() {
return seriesList.size();
}
@Override
public T[] getAllSeries() {
synchronized (seriesList) {
ArrayList<T> list = new ArrayList();
for (T series : seriesList.values()) {
list.add(series);
}
return list.toArray((T[]) Array.newInstance(seriesType, 0));
}
}
@Override
public void requestSeriesUpdate(final T series) {
if (!series.updating) {
series.updating = true;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
series.updating = false;
try {
updateSeries(series);
} catch (Exception ex) {
Logger.getLogger(LinePlotBase.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
}
abstract protected Object onAddedSeries(T series);
abstract protected void onRemovedSeries(T series);
/**
* These overridables can be optimised in implementations
*/
protected void onRemovedAllSeries() {
for (T s : getAllSeries()) {
removeSeries(s);
}
}
protected void doUpdate() {
for (T s : getAllSeries()) {
updateSeries(s);
}
}
@Override
public void clear() {
onRemovedAllSeries();
synchronized (seriesList) {
seriesList.clear();
}
update(true);
}
//Axis
final HashMap<AxisId, Axis> axisList = new HashMap<>();
protected void createAxis(AxisId axis) {
createAxis(axis, null);
}
protected void createAxis(AxisId axis, String label) {
axisList.put(axis, new Axis(label, this, axis));
}
public Axis getAxis(AxisId id) {
return axisList.get(id);
}
//Axis Callbacks
protected void onAxisLabelChanged(AxisId axis) {
if (isUpdatesEnabled()) {
doUpdate();
}
}
protected void onAxisRangeChanged(AxisId axis) {
if (isUpdatesEnabled()) {
doUpdate();
}
}
}
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
package ch.psi.plot;
/**
*
*/
public abstract class PlotSeries<T extends Plot> {
volatile boolean updating = false;
protected PlotSeries() {
this("");
}
protected PlotSeries(String name) {
setName((name == null) ? "" : name);
}
Object token;
void setToken(Object token) {
this.token = token;
}
public Object getToken() {
return token;
}
private T plot;
void setPlot(T plot) {
this.plot = plot;
}
public T getPlot() {
return plot;
}
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void clear(){
}
}
@@ -0,0 +1,625 @@
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
package ch.psi.plot.javafx;
import ch.psi.plot.LinePlotSeries;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.text.DecimalFormat;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import javafx.animation.AnimationTimer;
import javafx.application.Platform;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.ObservableList;
import javafx.embed.swing.JFXPanel;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Point2D;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.Axis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
/**
*
*/
public class LinePlot extends ch.psi.plot.LinePlotBase {
final boolean HOVERING_SYMBOLS = true;
public LinePlot() {
super();
createChart();
setRequireUpdateOnAppend(false);
}
final LinkedHashMap<XYChart.Series, ConcurrentLinkedQueue<Data<Number, Number>>> seriesList = new LinkedHashMap<>();
@Override
protected Object onAddedSeries(final LinePlotSeries series) {
XYChart.Series chartSeries = new XYChart.Series<Number, Number>();
ConcurrentLinkedQueue<Data<Number, Number>> queue = new ConcurrentLinkedQueue<>();
chartSeries.setName(series.getName());
synchronized (seriesList) {
seriesList.put(chartSeries, queue);
}
update(true);
return chartSeries;
}
@Override
protected void onRemovedSeries(LinePlotSeries series) {
XYChart.Series chartSeries = getChartSeries(series);
if (chartSeries != null) {
synchronized (seriesList) {
seriesList.remove(chartSeries);
}
update(true);
}
}
@Override
protected void onAppendData(final LinePlotSeries series, final double x, final double y) {
XYChart.Series chartSeries = getChartSeries(series);
if (chartSeries != null) {
synchronized (seriesList) {
ConcurrentLinkedQueue<Data<Number, Number>> queue = seriesList.get(chartSeries);
Data<Number, Number> dataPoint = new Data<Number, Number>(x, y);
queue.add(dataPoint);
}
}
}
@Override
protected void onSetData(LinePlotSeries series, double[] x, double[] y) {
XYChart.Series chartSeries = getChartSeries(series);
synchronized (seriesList) {
ConcurrentLinkedQueue<Data<Number, Number>> queue = seriesList.get(chartSeries);
for (int i = 0; i < x.length; i++) {
Data<Number, Number> dataPoint = new Data<Number, Number>(x[i], y[i]);
queue.add(dataPoint);
}
}
}
@Override
public void updateSeries(LinePlotSeries series) {
}
@Override
public double[][] getSeriesData(LinePlotSeries series) {
XYChart.Series s = getChartSeries(series);
ObservableList<Data<Number, Number>> list = s.getData();
double[] x = new double[list.size()];
double[] y = new double[list.size()];
int index = 0;
for (Data<Number, Number> item : list) {
x[index] = item.getXValue().doubleValue();
y[index++] = item.getYValue().doubleValue();
}
return new double[][]{x, y};
}
XYChart.Series getChartSeries(LinePlotSeries series) {
return (XYChart.Series) (series.getToken());
}
@Override
public void doUpdate() {
if (mTimerFX != null) {
Platform.runLater(new Runnable() {
@Override
public void run() {
updateFX();
}
});
}
}
private static JFXPanel fxContainer;
@Override
protected JPanel createChartPanel() {
fxContainer.setPreferredSize(new Dimension(480, 240));
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(fxContainer);
// create JavaFX scene
Platform.runLater(new Runnable() {
@Override
public void run() {
createScene();
}
});
return panel;
}
class MyLineChart<X extends Object, Y extends Object> extends LineChart<X, Y> {
public MyLineChart(Axis<X> axis, Axis<Y> axis1) {
super(axis, axis1);
}
public void addNode(Node node) {
if (node != null) {
getPlotChildren().add(node);
}
}
public void removeNode(Node node) {
if (node != null) {
getPlotChildren().remove(node);
}
}
@Override
protected void requestChartLayout() {
super.requestChartLayout();
}
}
private MyLineChart<Number, Number> chart;
boolean drawSymbols = false;
public void setDrawSymbols(boolean value) {
if (value != drawSymbols) {
drawSymbols = value;
if (chart != null) {
if (HOVERING_SYMBOLS) {
for (Iterator<Series<Number, Number>> it = chart.getData().iterator(); it.hasNext();) {
XYChart.Series series = it.next();
ObservableList<Data<Number, Number>> list = series.getData();
for (Data<Number, Number> item : list) {
Node symbol = item.getNode();
if (symbol != null) {
item.setNode(null);
chart.removeNode(symbol);
}
if (drawSymbols) {
symbol = new HoveredThresholdNode(series, item.getXValue(), item.getYValue());
//symbol = chart.createSymbol(series,chart.getData().indexOf(series), item, itemIndex);
item.setNode(symbol);
chart.addNode(symbol);
}
}
}
} else {
chart.setCreateSymbols(getDrawSymbols());
}
chart.requestChartLayout();
}
}
}
public boolean getDrawSymbols() {
return drawSymbols;
}
private void createChart() {
fxContainer = new JFXPanel(); //Must do bedore any JavaFX call
//xAxis = new NumberAxis(lower,upper,tick);
NumberAxis xAxis = new NumberAxis();
xAxis.setForceZeroInRange(false);
xAxis.setAutoRanging(true);
xAxis.setTickLabelsVisible(true);
xAxis.setTickMarkVisible(true);
xAxis.setMinorTickVisible(true);
NumberAxis yAxis = new NumberAxis();
yAxis.setForceZeroInRange(false);
yAxis.setAutoRanging(true);
//-- Chart
chart = new MyLineChart<>(xAxis, yAxis);
chart.setAnimated(false);
chart.setCreateSymbols(false);
chart.setCursor(Cursor.CROSSHAIR);
}
Rectangle zoomRect;
private void createScene() {
/*Platform.runLater(new Runnable() {
@Override
public void run() {*/
chart.setId(getTitle());
chart.setTitle(getTitle());
final StackPane chartContainer = new StackPane();
chartContainer.getChildren().add(chart);
zoomRect = new Rectangle();
zoomRect.setManaged(false);
zoomRect.setFill(Color.LIGHTSEAGREEN.deriveColor(0, 1, 1, 0.5));
chartContainer.getChildren().add(zoomRect);
setUpZooming(zoomRect, chart);
setUpContextMenu();
fxContainer.setScene(new Scene(chartContainer));
synchronized (seriesList) {
addSeriesToChart();
}
// Every frame to take any data from queue and add to chart
mTimerFX = new AnimationTimer() {
@Override
public void handle(long now) {
onTimerFX(now);
}
};
mTimerFX.start();
/*
mTimerFX = new Timeline(new KeyFrame(Duration.millis(200), new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
onTimerFX(System.nanoTime());
}
}));
mTimerFX.setCycleCount(Timeline.INDEFINITE);
mTimerFX.play();
*/
/*
}
});*/
}
//Timeline mTimerFX;
AnimationTimer mTimerFX;
void onTimerFX(long start) {
synchronized (seriesList) {
for (Iterator<Series> it = seriesList.keySet().iterator(); it.hasNext();) {
XYChart.Series series = it.next();
if (isPlottingSeries(series)) {
ConcurrentLinkedQueue<Data<Number, Number>> queue = seriesList.get(series);
//int count=0;
//while (!queue.isEmpty() && (count++<1000)) {
// series.getData().add(queue.remove());
//}
if (!queue.isEmpty()) {
if (getDrawSymbols()) {
for (Data<Number, Number> d : queue) {
d.setNode(new HoveredThresholdNode(series, d.getXValue(), d.getYValue()));
}
}
series.getData().addAll(queue);
queue.clear();
}
}
if (getElapsedMillis(start) > 200) {
return;
}
//xAxis.setLowerBound(xSeriesData-MAX_DATA_POINTS);
//xAxis.setUpperBound(xSeriesData-1);
}
}
}
long getElapsedMillis(long start) {
return (System.nanoTime() - start) / 1000000;
}
void updateFX() {
synchronized (seriesList) {
addSeriesToChart();
removeSeriesFromChart();
}
}
void addSeriesToChart() {
for (Iterator<Series> it = seriesList.keySet().iterator(); it.hasNext();) {
XYChart.Series series = it.next();
if (!isPlottingSeries(series)) {
chart.getData().add(series);
//Attempt to have a floating label that could speed up rendering of symbol coordinates
//Didn't manage to display the label.
/*
final Label label = new Label("");
label.setLabelFor(series.getNode());
label.getStyleClass().addAll("chart-line-symbol");
label.getStyleClass().addAll(series.getNode().getStyleClass());
label.setStyle("-fx-font-size: 13; -fx-font-weight: normal;"); ;
label.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
chart.addNode(label);
series.getNode().setOnMouseEntered(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
final NumberAxis yAxis = (NumberAxis) chart.getYAxis();
final NumberAxis xAxis = (NumberAxis) chart.getXAxis();
Point2D xAxisInScene = xAxis.localToScene(0, 0);
double xOffset = mouseEvent.getSceneX() - xAxisInScene.getX();
double yOffset = mouseEvent.getSceneY() - xAxisInScene.getY();
double xAxisScale = xAxis.getScale();
double yAxisScale = yAxis.getScale();
double x = xAxis.getLowerBound() + xOffset / xAxisScale;
double y = yAxis.getLowerBound() + yOffset / yAxisScale;
String str="(" + format.format(x) + ", " + format.format(y) +")";
//System.out.println(str);
label.setText(str);
label.setVisible(true);
label.toFront();
}
});
series.getNode().setOnMouseExited(new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent mouseEvent) {
label.setVisible(false);
}
});
*/
}
}
}
void removeSeriesFromChart() {
for (Iterator<Series<Number, Number>> it = chart.getData().iterator(); it.hasNext();) {
XYChart.Series series = it.next();
if (!seriesList.keySet().contains(series)) {
chart.getData().remove(series);
}
}
}
boolean isPlottingSeries(Series series) {
return chart.getData().contains(series);
}
boolean zooming;
private void setUpZooming(final Rectangle rect, final Node zoomingNode) {
final ObjectProperty<Point2D> mouseAnchor = new SimpleObjectProperty<>();
zoomingNode.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
if (event.isControlDown() && (event.getButton() == MouseButton.PRIMARY)) {
mouseAnchor.set(new Point2D(event.getX(), event.getY()));
zooming = true;
rect.setWidth(0);
rect.setHeight(0);
} else if (event.getButton() == MouseButton.SECONDARY) {
contextMenu.show(zoomingNode, event.getScreenX(), event.getScreenY());
}
}
});
zoomingNode.setOnMouseDragged(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
if (event.isControlDown() && zooming) {
double x = event.getX();
double y = event.getY();
rect.setX(Math.min(x, mouseAnchor.get().getX()));
rect.setY(Math.min(y, mouseAnchor.get().getY()));
rect.setWidth(Math.abs(x - mouseAnchor.get().getX()));
rect.setHeight(Math.abs(y - mouseAnchor.get().getY()));
}
}
});
zoomingNode.setOnMouseReleased(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
if (event.isControlDown() && zooming) {
doZoom(zoomRect, chart);
}
rect.setWidth(0);
rect.setHeight(0);
zooming = false;
}
});
}
private void doZoom(Rectangle zoomRect, LineChart<Number, Number> chart) {
Point2D zoomTopLeft = new Point2D(zoomRect.getX(), zoomRect.getY());
Point2D zoomBottomRight = new Point2D(zoomRect.getX() + zoomRect.getWidth(), zoomRect.getY() + zoomRect.getHeight());
final NumberAxis yAxis = (NumberAxis) chart.getYAxis();
Point2D yAxisInScene = yAxis.localToScene(0, 0);
final NumberAxis xAxis = (NumberAxis) chart.getXAxis();
if (zoomTopLeft.getX() < yAxisInScene.getX() && zoomTopLeft.getY() < yAxisInScene.getY()) {
resetZoom();
} else {
xAxis.setAutoRanging(false);
yAxis.setAutoRanging(false);
Point2D xAxisInScene = xAxis.localToScene(0, 0);
double xOffset = zoomTopLeft.getX() - yAxisInScene.getX();
double yOffset = zoomBottomRight.getY() - xAxisInScene.getY();
double xAxisScale = xAxis.getScale();
double yAxisScale = yAxis.getScale();
xAxis.setLowerBound(xAxis.getLowerBound() + xOffset / xAxisScale);
xAxis.setUpperBound(xAxis.getLowerBound() + zoomRect.getWidth() / xAxisScale);
yAxis.setLowerBound(yAxis.getLowerBound() + yOffset / yAxisScale);
yAxis.setUpperBound(yAxis.getLowerBound() - zoomRect.getHeight() / yAxisScale);
// System.out.println(xAxis.getLowerBound() + " " + xAxis.getUpperBound() + " " + yAxis.getLowerBound() + " " + yAxis.getUpperBound());
}
zoomRect.setWidth(0);
zoomRect.setHeight(0);
}
private void resetZoom() {
final NumberAxis yAxis = (NumberAxis) chart.getYAxis();
final NumberAxis xAxis = (NumberAxis) chart.getXAxis();
if (getAxis(AxisId.Y).isAutoRange()) {
yAxis.setLowerBound(getAxis(AxisId.Y).getMin());
yAxis.setUpperBound(getAxis(AxisId.Y).getMax());
yAxis.setAutoRanging(true);
} else {
yAxis.setAutoRanging(false);
yAxis.setLowerBound(getAxis(AxisId.Y).getMin());
yAxis.setUpperBound(getAxis(AxisId.Y).getMax());
}
if (getAxis(AxisId.X).isAutoRange()) {
xAxis.setLowerBound(getAxis(AxisId.X).getMin());
xAxis.setUpperBound(getAxis(AxisId.X).getMax());
xAxis.setAutoRanging(true);
} else {
xAxis.setAutoRanging(false);
xAxis.setLowerBound(getAxis(AxisId.X).getMin());
xAxis.setUpperBound(getAxis(AxisId.X).getMax());
}
}
@Override
protected void onAxisRangeChanged(AxisId axis_id) {
NumberAxis axis = null;
switch (axis_id) {
case X:
axis = (NumberAxis) chart.getXAxis();
break;
case Y:
axis = (NumberAxis) chart.getYAxis();
break;
default:
return;
}
axis.setAutoRanging(getAxis(axis_id).isAutoRange());
axis.setLowerBound(getAxis(axis_id).getMin());
axis.setUpperBound(getAxis(axis_id).getMax());
}
ContextMenu contextMenu;
public void setUpContextMenu() {
contextMenu = new ContextMenu();
final CheckMenuItem item1 = new CheckMenuItem("Draw Symbols");
item1.setSelected(getDrawSymbols());
item1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
setDrawSymbols(item1.isSelected());
}
});
final CheckMenuItem item2 = new CheckMenuItem("Show Legend");
item2.setSelected(chart.isLegendVisible());
item2.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
chart.setLegendVisible(item2.isSelected());
}
});
MenuItem item3 = new MenuItem("Reset Zoom");
item3.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
resetZoom();
}
});
contextMenu.getItems().addAll(item1, item2, item3);
}
DecimalFormat format = new DecimalFormat("#.######");
class HoveredThresholdNode extends StackPane {
HoveredThresholdNode(XYChart.Series series, Number x, Number y) {
setPrefSize(8, 8);
getStyleClass().addAll("chart-line-symbol");
getStyleClass().addAll(series.getNode().getStyleClass());
final Label label = new Label("(" + format.format(x) + ", " + format.format(y) + ")");
label.getStyleClass().addAll("chart-line-symbol");
label.getStyleClass().addAll(series.getNode().getStyleClass());
label.setStyle("-fx-font-size: 13; -fx-font-weight: normal;");
//label.setTextFill(Color.FORESTGREEN);
label.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE);
setOnMouseEntered(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
getChildren().setAll(label);
setCursor(Cursor.NONE);
toFront();
}
});
setOnMouseExited(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
getChildren().clear();
setCursor(Cursor.CROSSHAIR);
}
});
}
}
void addSwingMenuItem(final ObservableList<MenuItem> menu, final JMenuItem item) {
if (item instanceof JMenu) {
Menu menu_fx = new Menu(item.getText());
for (Component menuItem : ((JMenu) item).getMenuComponents()) {
if (menuItem instanceof JMenu) {
addSwingMenuItem(menu_fx.getItems(), ((JMenu) menuItem));
} else if (menuItem instanceof JPopupMenu.Separator) {
menu_fx.getItems().add(new SeparatorMenuItem());
} else if (menuItem instanceof JMenuItem) {
addSwingMenuItem(menu_fx.getItems(), ((JMenuItem) menuItem));
}
}
menu.add(menu_fx);
} else if (item instanceof JMenuItem) {
MenuItem itemFX = new MenuItem(item.getText());
itemFX.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
item.doClick();
}
});
menu.add(itemFX);
}
}
protected void addPopupMenuItem(final JMenuItem item) {
Platform.runLater(new Runnable() {
@Override
public void run() {
if (item == null) {
contextMenu.getItems().add(new SeparatorMenuItem());
} else {
addSwingMenuItem(contextMenu.getItems(), item);
}
}
});
}
}
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
package ch.psi.plot.jfree;
import java.awt.Color;
/**
* Utility class for applying a color map
*/
public class ColorManager {
/**
* Get color for a given value
*
* @param v Value to get the color for
* @param vmin Lower end value mapped to the lower end of the color map
* @param vmax Upper end value mapped to the upper end of the color map
* @return Mapped color for the specified value
*/
public static Color getColourForValue(double v, double vmin, double vmax) {
// Standard algorithm for hot-cold color gradient (copied from
// http://local.wasp.uwa.edu.au/~pbourke/texture_colour/colourramp/)
//Init color to white
double r = 1.0;
double g = 1.0;
double b = 1.0;
double dv;
if (v < vmin) {
v = vmin;
}
if (v > vmax) {
v = vmax;
}
dv = vmax - vmin;
if (v < (vmin + 0.25 * dv)) {
r = 0.0;
g = 4 * (v - vmin) / dv;
} else if (v < (vmin + 0.5 * dv)) {
r = 0.0;
b = 1 + 4 * (vmin + 0.25 * dv - v) / dv;
} else if (v < (vmin + 0.75 * dv)) {
r = 4 * (v - vmin - 0.5 * dv) / dv;
b = 0.0;
} else {
g = 1 + 4 * (vmin + 0.75 * dv - v) / dv;
b = 0.0;
}
return new Color(new Double(255.0 * r).intValue(), new Double(255.0 * g).intValue(), new Double(255.0 * b).intValue());
}
/**
* Get a gray value for a given value
*
* @param value the value (must be within the range specified by the lower
* and upper bounds for the scale).
*
* @return a gray scale color.
*/
public static Color getGrayForValue(double value, double vmin, double vmax) {
double v = Math.max(value, vmin);
v = Math.min(v, vmax);
int g = (int) ((v - vmin) / (vmax - vmin) * 255.0);
// FIXME: it probably makes sense to allocate an array of 256 Colors
// and lazily populate this array...
return new Color(g, g, g);
}
}
@@ -1,4 +1,4 @@
package ch.psi.plot.xy.tools;
package ch.psi.plot.jfree;
import java.awt.BasicStroke;
import java.awt.Color;
@@ -10,29 +10,31 @@ import org.jfree.ui.Drawable;
/**
* Class that draws an cross as annotation.
*
* This is an implementation of the {@link Drawable} interface, to illustrate the use of the
* {@link org.jfree.chart.annotations.XYDrawableAnnotation} class.
*
* This is an implementation of the {@link Drawable} interface, to illustrate
* the use of the {@link org.jfree.chart.annotations.XYDrawableAnnotation}
* class.
*/
public class CrossAnnotation implements Drawable {
private final Color color;
private final Color color;
/**
* Creates a new instance.
*/
public CrossAnnotation(Color color) {
this.color = color;
this.color = color;
}
/**
* Draws cross
* @param g2 the graphics device.
* @param area the area in which to draw.
*
* @param g2 the graphics device.
* @param area the area in which to draw.
*/
public void draw(Graphics2D g2, Rectangle2D area) {
// Draw red cross
// Draw red cross
g2.setPaint(color);
g2.setStroke(new BasicStroke(2)); // Stroke width = 2
Line2D line1 = new Line2D.Double(area.getCenterX(), area.getMinY(), area.getCenterX(), area.getMaxY());
@@ -0,0 +1,544 @@
package ch.psi.plot.jfree;
import ch.psi.plot.LinePlotBase;
import ch.psi.plot.LinePlotSeries;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.text.DecimalFormat;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.annotations.XYAnnotation;
import org.jfree.chart.annotations.XYDrawableAnnotation;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.entity.StandardEntityCollection;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.labels.XYToolTipGenerator;
import org.jfree.chart.plot.Marker;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.ValueMarker;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.Range;
import org.jfree.data.xy.XYDataItem;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.Layer;
import org.jfree.ui.RectangleAnchor;
import org.jfree.ui.RefineryUtilities;
import org.jfree.ui.TextAnchor;
public class LinePlot extends LinePlotBase {
private static final Logger logger = Logger.getLogger(LinePlot.class.getName());
private ChartPanel chartPanel;
private static final int chartPanelWidth = 500;
private static final int chartPanelHeight = 270;
//Defining Context Menu Label
private static final String showLegendMenuLabel = "Show Legend";
private static final String hideLegendMenuLabel = "Hide Legend";
private static final String showTooltipsMenuLabel = "Show Tooltips";
private static final String hideTooltipsMenuLabel = "Hide Tooltips";
private XYSeriesCollection data;
JFreeChart chart;
private boolean tooltips = false;
/**
* @param title Title of plot
*/
public LinePlot() {
super();
data = new XYSeriesCollection();
}
@Override
public void onAppendData(LinePlotSeries series, double x, double y) {
XYSeries s = getXYSeries(series);
s.add(new XYDataItem(x, y), false);
}
@Override
protected void onSetData(LinePlotSeries series, double[] x, double[] y) {
XYSeries s = getXYSeries(series);
if (!s.isEmpty()) {
s.clear();
}
for (int i = 0; i < y.length; i++) {
s.add(new XYDataItem(x[i], y[i]), false);
}
}
@Override
protected Object onAddedSeries(LinePlotSeries series) {
final XYSeries s = new XYSeries(series.getName());
data.addSeries(s);
return s;
}
@Override
protected void onRemovedSeries(LinePlotSeries series) {
/*
for (Object s : data.getSeries()) {
if (((XYSeries)s).getKey().equals(series.getName())) {
data.removeSeries(((XYSeries)s));
}
}
*/
if ((series != null) && (series.getToken() != null)) {
data.removeSeries((XYSeries) (series.getToken()));
}
}
@Override
public double[][] getSeriesData(final LinePlotSeries series) {
final XYSeries s = getXYSeries(series);
List<XYDataItem> items = s.getItems();
double[] x = new double[items.size()];
double[] y = new double[items.size()];
for (int i = 0; i < y.length; i++) {
x[i] = items.get(i).getXValue();
y[i] = items.get(i).getYValue();
}
return new double[][]{x, y};
}
@Override
public void onRemovedAllSeries() {
data.removeAllSeries();
}
public void updateSeries(LinePlotSeries series) {
XYSeries s = getXYSeries(series);
s.fireSeriesChanged();
}
XYSeries getXYSeries(LinePlotSeries series) {
/*
for (Object s : data.getSeries()) {
if (((XYSeries)s).getKey().equals(series.getName())) {
return ((XYSeries)s);
}
}
return null;
*/
return (XYSeries) (series.getToken());
}
/**
* Get the chart panel of this plot. The chart panel will be lazily created
* the first time this function is called
*
* @return
*/
@Override
protected JPanel createChartPanel() {
// Create chart
chart = ChartFactory.createXYLineChart(getTitle(), getAxis(AxisId.X).getLabel(), getAxis(AxisId.Y).getLabel(), data, PlotOrientation.VERTICAL, true, tooltips, false);
// Customize chart look and feel
// Customize background (gray: new Color(238,238,238))
chart.setBackgroundPaint(null);
// Customize legend
chart.getLegend().setVisible(false);
chart.getLegend().setBackgroundPaint(null);
chart.getLegend().setBorder(0, 0, 0, 0);
// Customize plot area look and feel
XYPlot plot = (XYPlot) chart.getPlot();
plot.setBackgroundPaint(Color.white);
plot.setDomainGridlinePaint(Color.gray);
plot.setRangeGridlinePaint(Color.gray);
// Show data point
((XYLineAndShapeRenderer) plot.getRenderer()).setBaseShapesVisible(true);
// Include zeros in range (x) axis
((NumberAxis) plot.getRangeAxis()).setAutoRangeIncludesZero(false);
// Lazy creation of the chart panel
chartPanel = new ChartPanel(chart);
chartPanel.setName(getTitle());
// Remove border
chartPanel.getChart().setBorderVisible(false);
// Set size of chart
chartPanel.setPreferredSize(new java.awt.Dimension(chartPanelWidth, chartPanelHeight));
// Add more items to the context menu
amendContextMenu();
//Activate (arrow) keys
addKeyBindings();
return chartPanel;
}
/**
* Change visible part of chart
*
* @param translationVector
*/
private void moverOverPlot(XYDataItem translationVector) {
double translatedDomainIntervalMin = chart.getXYPlot().getDomainAxis().getRange().getLowerBound() + translationVector.getX().doubleValue();
double translatedDomainIntervalMax = chart.getXYPlot().getDomainAxis().getRange().getUpperBound() + translationVector.getX().doubleValue();
double translatedRangeIntervalMin = chart.getXYPlot().getRangeAxis().getRange().getLowerBound() + translationVector.getY().doubleValue();
double translatedRangeIntervalMax = chart.getXYPlot().getRangeAxis().getRange().getUpperBound() + translationVector.getY().doubleValue();
Range domainAxisRange = new Range(translatedDomainIntervalMin, translatedDomainIntervalMax);
Range rangeAxisRange = new Range(translatedRangeIntervalMin, translatedRangeIntervalMax);
//We set notify to false in the first call..
chart.getXYPlot().getDomainAxis().setRange(domainAxisRange, true, false);
//...and true in the last
chart.getXYPlot().getRangeAxis().setRange(rangeAxisRange, true, true);
}
/**
* Add key bindings to chart panel
*/
private void addKeyBindings() {
final String moveUpKey = "move up";
final String moveDownKey = "move down";
final String moveRightKey = "move right";
final String moveLeftKey = "move left";
// Up arrow
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), moveUpKey);
chartPanel.getActionMap().put(moveUpKey, new AbstractAction() {
// Default serial id
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
moverOverPlot(new XYDataItem(0.0, ((NumberAxis) chart.getXYPlot().getRangeAxis()).getTickUnit().getSize()));
}
});
// Down arrow
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), moveDownKey);
chartPanel.getActionMap().put(moveDownKey, new AbstractAction() {
// Default serial id
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
moverOverPlot(new XYDataItem(0.0, -((NumberAxis) chart.getXYPlot().getRangeAxis()).getTickUnit().getSize()));
}
});
// Right arrow
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), moveRightKey);
chartPanel.getActionMap().put(moveRightKey, new AbstractAction() {
// Default serial id
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
moverOverPlot(new XYDataItem(((NumberAxis) chart.getXYPlot().getDomainAxis()).getTickUnit().getSize(), 0.0));
}
});
// Left arrow
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), moveLeftKey);
chartPanel.getActionMap().put(moveLeftKey, new AbstractAction() {
// Default serial id
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
moverOverPlot(new XYDataItem(-((NumberAxis) chart.getXYPlot().getDomainAxis()).getTickUnit().getSize(), 0.0));
}
});
}
@Override
protected void onAxisRangeChanged(AxisId axis_id) {
ValueAxis axis = null;
switch (axis_id) {
case X:
axis = chart.getXYPlot().getDomainAxis();
break;
case Y:
axis = chart.getXYPlot().getRangeAxis();
break;
default:
return;
}
if (getAxis(axis_id).isAutoRange()) {
axis.setAutoRange(true);
} else {
axis.setRange(new Range(getAxis(axis_id).getMin(), getAxis(axis_id).getMax()), true, true);
}
}
/**
* Add additional items to the context menu of the plot
*/
public void amendContextMenu() {
chartPanel.getPopupMenu().addSeparator();
JMenu toolsMenu = new JMenu("Tools");
chartPanel.getPopupMenu().add(toolsMenu);
// Mark average
JMenuItem averageMenuItem = new JMenuItem("Average");
averageMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for (LinePlotSeries series : getAllSeries()) {
double a = series.getAverage();
// Remove all range markers
Collection<?> c = chartPanel.getChart().getXYPlot().getRangeMarkers(Layer.FOREGROUND);
if (c != null) {
for (final Object marker : c) {
SwingUtilities.invokeLater(new Runnable() { // Avoid concurrent modification exception
@Override
public void run() {
chartPanel.getChart().getXYPlot().removeRangeMarker((Marker) marker);
}
});
}
}
final ValueMarker marker = new ValueMarker(a, Color.BLACK, new BasicStroke(1));
marker.setLabel("Average [" + series.getName() + "]: " + String.format("%.6f", a));
marker.setLabelAnchor(RectangleAnchor.CENTER);
marker.setLabelTextAnchor(TextAnchor.TOP_RIGHT);
SwingUtilities.invokeLater(new Runnable() { // Avoid concurrent modification exception
@Override
public void run() {
chartPanel.getChart().getXYPlot().addRangeMarker(marker, Layer.FOREGROUND);
}
});
}
}
});
toolsMenu.add(averageMenuItem);
// Mark minimum value
JMenuItem minimumMenuItem = new JMenuItem("Minimum");
minimumMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for (LinePlotSeries series : getAllSeries()) {
double[] min = series.getMinimum();
// System.out.println("Minimum: "+m.getXValue());
// Remove all annotation for the series
for (Object o : chartPanel.getChart().getXYPlot().getAnnotations()) {
chartPanel.getChart().getXYPlot().removeAnnotation((XYAnnotation) o);
}
XYDrawableAnnotation cross = new XYDrawableAnnotation(min[0], min[1], 10.0, 10.0, new CrossAnnotation(Color.BLACK));
cross.setToolTipText("Minimum: " + min[0] + " / " + min[1]);
chartPanel.getChart().getXYPlot().addAnnotation(cross);
}
}
});
toolsMenu.add(minimumMenuItem);
// Mark maximum value
JMenuItem maximumMenuItem = new JMenuItem("Maximum");
maximumMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for (LinePlotSeries series : getAllSeries()) {
double[] max = series.getMaximum();
// Remove all annotation for the series
for (Object o : chartPanel.getChart().getXYPlot().getAnnotations()) {
chartPanel.getChart().getXYPlot().removeAnnotation((XYAnnotation) o);
}
XYDrawableAnnotation cross = new XYDrawableAnnotation(max[0], max[1], 10.0, 10.0, new CrossAnnotation(Color.BLACK));
cross.setToolTipText("Maximum: " + max[0] + " / " + max[1]);
chartPanel.getChart().getXYPlot().addAnnotation(cross);
}
}
});
toolsMenu.add(maximumMenuItem);
// Show derivative
JMenuItem derivativeMenuItem = new JMenuItem("Derivative");
derivativeMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
LinePlot p = new LinePlot();
p.setTitle("Derivative - " + getTitle());
for (LinePlotSeries series : getAllSeries()) {
double[][] derivative = series.getDerivative();
LinePlotSeries dseries = new LinePlotSeries(series.getName() + "'");
p.addSeries(dseries);
dseries.setData(derivative[0], derivative[1]);
}
JFrame frame = new JFrame();
frame.setContentPane(p.getChartPanel());
frame.pack();
RefineryUtilities.centerFrameOnScreen(frame);
frame.setVisible(true);
}
});
toolsMenu.add(derivativeMenuItem);
// Show integral
JMenuItem integralMenuItem = new JMenuItem("Integral");
integralMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Show new frame
LinePlot p = new LinePlot();
p.setTitle("Integral - " + getTitle());
for (LinePlotSeries series : getAllSeries()) {
double[][] integral = series.getIntegral();
LinePlotSeries dseries = new LinePlotSeries("integral-" + series.getName());
p.addSeries(dseries);
dseries.setData(integral[0], integral[1]);
}
JFrame frame = new JFrame();
frame.setContentPane(p.getChartPanel());
frame.pack();
RefineryUtilities.centerFrameOnScreen(frame);
frame.setVisible(true);
}
});
toolsMenu.add(integralMenuItem);
/*
chartPanel.getPopupMenu().addSeparator();
// Detach plot into a separate frame
JMenuItem detachPlotMenuItem = new JMenuItem("Detach");
detachPlotMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
LinePlot p = new LinePlot();
p.setTitle(getTitle());
for (LinePlotSeries series : LinePlot.this.getAllSeries()) {
LinePlotSeries detachedSeries = new LinePlotSeries(series.getName(), series.getColor());
p.addSeries(detachedSeries);
detachedSeries.setData(series.getX(), series.getY());
}
JFrame frame = new JFrame();
frame.setContentPane(p.getChartPanel());
frame.pack();
RefineryUtilities.centerFrameOnScreen(frame);
frame.setVisible(true);
}
});
chartPanel.getPopupMenu().add(detachPlotMenuItem);
*/
// Hide/Show legend
JMenuItem hideLegendMenuItem = new JMenuItem(showLegendMenuLabel);
hideLegendMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem source = (JMenuItem) (e.getSource());
if (source.getText() == showLegendMenuLabel) {
chart.getLegend().setVisible(true);
source.setText(hideLegendMenuLabel);
} else if (source.getText() == hideLegendMenuLabel) {
chart.getLegend().setVisible(false);
source.setText(showLegendMenuLabel);
}
}
});
chartPanel.getPopupMenu().add(hideLegendMenuItem);
// Hide/Show tooltips
JMenuItem hideToolTipsMenuItem = new JMenuItem(hideTooltipsMenuLabel);
if (!tooltips) {
hideToolTipsMenuItem.setText(showTooltipsMenuLabel);
}
hideToolTipsMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem source = (JMenuItem) (e.getSource());
if (source.getText() == showTooltipsMenuLabel) {
showTooltips();
source.setText(hideTooltipsMenuLabel);
} else if (source.getText() == hideTooltipsMenuLabel) {
hideTooltips();
source.setText(showTooltipsMenuLabel);
}
}
});
chartPanel.getPopupMenu().add(hideToolTipsMenuItem);
}
private void showTooltips() {
tooltips = true;
DecimalFormat dm = new DecimalFormat("0.##########");
XYToolTipGenerator xYToolTipGenerator = new StandardXYToolTipGenerator("{1}/{2}", dm, dm);
chart.getXYPlot().getRenderer().setBaseToolTipGenerator(xYToolTipGenerator);
chartPanel.setDisplayToolTips(true);
chartPanel.getChartRenderingInfo().setEntityCollection(new StandardEntityCollection());
}
private void hideTooltips() {
tooltips = false;
// http://www.jfree.org/phpBB2/viewtopic.php?t=12788&highlight=redraw+speed+performance+problem
chartPanel.getChartRenderingInfo().setEntityCollection(null);
chart.getXYPlot().getRenderer().setBaseToolTipGenerator(null);
}
protected void addPopupMenuItem(final JMenuItem item) {
if (item == null) {
chartPanel.getPopupMenu().addSeparator();
} else {
chartPanel.getPopupMenu().add(item);
}
}
/*
@Override
protected void doUpdate()
if (data != null) {
SwingUtilities.invokeLater(new Runnable() { // Try to avoid concurrent modification exception
@Override
public void run() {
try {
for (XYSeries s : data.getSeries()) {
s.fireSeriesChanged();
}
} catch (ConcurrentModificationException e) {
logger.log(Level.WARNING, "Series got modified concurrently: " + e.getMessage(), e);
}
}
});
}
}
*/
/*
//Trash
@Override
public void setData(Object data) {
super.setData(data);
this.data = (XYSeriesCollection) data;
}
*/
}
@@ -0,0 +1,169 @@
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
package ch.psi.plot.jfree;
import ch.psi.plot.jfree.MatrixPlot;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JTextField;
import javax.swing.JLabel;
import java.awt.Font;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
/**
*
*/
public class ManualScaleDialog extends JDialog {
// Default serial id
private static final long serialVersionUID = 1L;
private final JPanel contentPanel = new JPanel();
private JTextField textFieldHighValue;
private JTextField textFieldLowValue;
private MatrixPlot plot;
private int selectedOption;
/**
* Launch the application.
*/
public static void main(String[] args) {
try {
ManualScaleDialog dialog = new ManualScaleDialog();
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
System.out.println("HERE");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Create the dialog.
*/
public ManualScaleDialog() {
setModal(true); // Block until dialog is disposed.
setBounds(100, 100, 450, 300);
getContentPane().setLayout(new BorderLayout());
contentPanel.setLayout(new FlowLayout());
contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
getContentPane().add(contentPanel, BorderLayout.CENTER);
{
JLabel lblLowValue = new JLabel("Low Value:");
lblLowValue.setFont(new Font("Lucida Grande", Font.BOLD, 13));
contentPanel.add(lblLowValue);
}
{
textFieldLowValue = new JTextField();
contentPanel.add(textFieldLowValue);
textFieldLowValue.setColumns(10);
}
{
JLabel lblHighValue = new JLabel("High Value:");
lblHighValue.setFont(new Font("Lucida Grande", Font.BOLD, 13));
contentPanel.add(lblHighValue);
}
{
textFieldHighValue = new JTextField();
contentPanel.add(textFieldHighValue);
textFieldHighValue.setColumns(10);
}
{
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
getContentPane().add(buttonPane, BorderLayout.SOUTH);
{
JButton okButton = new JButton("OK");
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
// set OK
selectedOption = JOptionPane.OK_OPTION;
dispose();
}
});
{
JButton btnApply = new JButton("Apply");
btnApply.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
// TODO apply values
if (plot != null) {
plot.setColorScale(getLow(), getHigh());
}
}
});
buttonPane.add(btnApply);
}
okButton.setActionCommand("OK");
buttonPane.add(okButton);
getRootPane().setDefaultButton(okButton);
}
{
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
// set Cancel
selectedOption = JOptionPane.CANCEL_OPTION;
dispose();
}
});
cancelButton.setActionCommand("Cancel");
buttonPane.add(cancelButton);
}
}
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
pack();
}
public void showDialog() {
setVisible(true);
}
public void setMatrixPlot(MatrixPlot p) {
plot = p;
}
public void setLow(double low) {
textFieldLowValue.setText(String.format("%.4f", low));
}
public void setHigh(double high) {
textFieldHighValue.setText(String.format("%.4f", high));
}
public double getLow() {
double low = Double.NaN;
try {
low = Double.parseDouble(textFieldLowValue.getText());
} catch (NumberFormatException e) {
}
return low;
}
public double getHigh() {
double high = Double.NaN;
try {
high = Double.parseDouble(textFieldHighValue.getText());
} catch (NumberFormatException e) {
}
return high;
}
/**
* @return the selectedOption
*/
public int getSelectedOption() {
return selectedOption;
}
}
@@ -0,0 +1,490 @@
package ch.psi.plot.jfree;
import ch.psi.plot.MatrixPlotBase;
import ch.psi.plot.MatrixPlotSeries;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.util.Arrays;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.event.AxisChangeEvent;
import org.jfree.chart.event.AxisChangeListener;
import org.jfree.chart.labels.StandardXYZToolTipGenerator;
import org.jfree.chart.labels.XYZToolTipGenerator;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.LookupPaintScale;
import org.jfree.chart.renderer.PaintScale;
import org.jfree.chart.renderer.xy.XYBlockRenderer;
import org.jfree.chart.title.PaintScaleLegend;
import org.jfree.data.Range;
import org.jfree.data.xy.DefaultXYZDataset;
import org.jfree.ui.RectangleAnchor;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
/**
* Returns a matrix plot panel
*/
public class MatrixPlot extends MatrixPlotBase {
private static final int chartPanelWidth = 500;
private static final int chartPanelHeight = 270;
private boolean grayScale = false;
private MatrixPlotSeries series;
private DefaultXYZDataset data;
private JFreeChart chart;
private ChartPanel chartPanel;
double[] xvalues = new double[0];
double[] yvalues = new double[0];
double[] zvalues = new double[0];
/**
* Constructor
*
* @param title
* @param data
*/
XYPlot plot;
final NumberAxis xAxis, yAxis;
final XYBlockRenderer renderer;
public MatrixPlot() {
super();
// Create matrix chart
// Init size of plot area according to min and max set in the datas metadata
// Set axis: (plus half bin size on both sides), since we plot the bins centered.
xAxis = new NumberAxis("");
yAxis = new NumberAxis("");
// Configure block renderer to have the blocks rendered in the correct size
renderer = new XYBlockRenderer();
renderer.setBaseCreateEntities(false);
plot = new XYPlot(null, xAxis, yAxis, renderer);
// Remove background paint/color
plot.setBackgroundPaint(null);
// Set the maximum zoom out to the initial zoom rate This also
// provides a workaround for dynamic plots because there zoom out does not work correctly (zoom out to infinity)
plot.getRangeAxis().addChangeListener(new AxisChangeListener() {
@Override
public void axisChanged(AxisChangeEvent event) {
if (series == null) {
return;
}
ValueAxis axis = ((ValueAxis) event.getAxis());
if (axis.getLowerBound() < yMin || axis.getUpperBound() > yMax) {
Range range = new Range(yMin, yMax);
axis.setRange(range, true, false);
}
}
});
plot.getDomainAxis().addChangeListener(new AxisChangeListener() {
@Override
public void axisChanged(AxisChangeEvent event) {
if (series == null) {
return;
}
ValueAxis axis = ((ValueAxis) event.getAxis());
if (axis.getLowerBound() < xMin || axis.getUpperBound() > xMax) {
Range range = new Range(xMin, xMax);
axis.setRange(range, true, false);
}
}
});
}
double xMin, xMax, yMin, yMax;
@Override
protected Object onAddedSeries(MatrixPlotSeries series) {
this.series = series;
int arraylength = series.getNumberOfBinsX() * series.getNumberOfBinsY();
xvalues = new double[arraylength];
yvalues = new double[arraylength];
zvalues = new double[arraylength];
Arrays.fill(xvalues, Double.NEGATIVE_INFINITY);
Arrays.fill(yvalues, Double.NEGATIVE_INFINITY);
Arrays.fill(zvalues, Double.NEGATIVE_INFINITY);
double[][] dataArray = new double[][]{xvalues, yvalues, zvalues};
//Create the XYDataset (org.jfree), not to be confused with the ch.psi dataSet)
data = new DefaultXYZDataset();
data.addSeries("Data", dataArray);
onAxisRangeChanged(AxisId.X);
onAxisRangeChanged(AxisId.Y);
xAxis.setLabel(getAxis(AxisId.X).getLabel());
yAxis.setLabel(getAxis(AxisId.Y).getLabel());
renderer.setBlockWidth(series.getBinWidthX()); // If this is not set the default block size is 1
renderer.setBlockHeight(series.getBinWidthY()); // If this is not set the default block size is 1
renderer.setBlockAnchor(RectangleAnchor.CENTER);
// Remove background paint/color
plot.setBackgroundPaint(null);
plot.setDataset(data);
return data;
}
@Override
protected void onAxisRangeChanged(AxisId axis_id) {
// The axis min and max values need to be half a bin larger. Otherwise the outer pixels
// will not be plotted correctly (half of the pixel is missing)
if (axis_id == AxisId.X) {
if (getAxis(AxisId.X).isAutoRange()) {
xMin = series.getMinX() - 0.5 * series.getBinWidthX();
xMax = series.getMaxX() + 0.5 * series.getBinWidthX();
} else {
xMin = getAxis(AxisId.X).getMin();
xMax = getAxis(AxisId.X).getMax();
}
xAxis.setLowerBound(xMin);
xAxis.setUpperBound(xMax);
}
if (axis_id == AxisId.Y) {
if (getAxis(AxisId.Y).isAutoRange()) {
yMin = series.getMinY() - 0.5 * series.getBinWidthY();
yMax = series.getMaxY() + 0.5 * series.getBinWidthY();
} else {
yMin = getAxis(AxisId.Y).getMin();
yMax = getAxis(AxisId.Y).getMax();
}
yAxis.setLowerBound(yMin);
yAxis.setUpperBound(yMax);
}
}
@Override
protected void onRemovedSeries(MatrixPlotSeries s) {
series = null;
doUpdate();
}
@Override
protected void onAppendData(MatrixPlotSeries series, int indexX, int indexY, double x, double y, double z) {
final int index = indexY * series.getNumberOfBinsX() + indexX;
//x Value is column, y value is row
xvalues[index] = x;
yvalues[index] = y;
zvalues[index] = z;
}
@Override
protected void onSetData(MatrixPlotSeries series, double[][] data) {
int index = 0;
for (int y = 0; y < data.length; y++) {
for (int x = 0; x < data[0].length; x++) {
//final int index = y * series.getNumberOfBinsX() + x;
xvalues[index] = series.getMinX() + series.getBinWidthX() * x;
yvalues[index] = series.getMinY() + series.getBinWidthY() * y;
zvalues[index++] = data[y][x];
}
}
}
@Override
public void clear() {
if (series != null) {
removeSeries(series);
doUpdate();
}
}
@Override
public double[][] getSeriesData(MatrixPlotSeries s) {
int x = series.getNumberOfBinsX();
int y = series.getNumberOfBinsY();
double[][] ret = new double[y][x];
int index = 0;
for (int i = 0; i < y; i++) {
for (int j = 0; j < x; j++) {
ret[i][j] = data.getZValue(0, index++);
}
}
return ret;
}
// Action Classes that implement methods called after keyboard input
/**
* Adapt the context menu of the chart panel
*/
private void adaptContextMenu(final ChartPanel chartPanel) {
// Show hide tooltips
final String tooltipsMenuLabel = "Tooltips";
final String hideTooltipsMenuLabel = "Hide Tooltips";
JMenuItem contextMenuItemToolTip = new JMenuItem(tooltipsMenuLabel);
contextMenuItemToolTip.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem source = (JMenuItem) (e.getSource());
if (source.getText() == tooltipsMenuLabel) {
showTooltip();
source.setText(hideTooltipsMenuLabel);
} else if (source.getText() == hideTooltipsMenuLabel) {
hideTooltip();
source.setText(tooltipsMenuLabel);
}
}
});
chartPanel.getPopupMenu().add(contextMenuItemToolTip);
// Update colormap
JMenuItem contextMenuItemAdaptScale = new JMenuItem("Update Scale");
contextMenuItemAdaptScale.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
adaptColorMapScale();
}
});
// Set gray scale colormap
JMenuItem contextMenuItemGrayScale = new JMenuItem("Gray Scale");
contextMenuItemGrayScale.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
grayScale = true;
adaptColorMapScale();
}
});
// Set color colormap
JMenuItem contextMenuItemTemperatureColor = new JMenuItem("Color Scale");
contextMenuItemTemperatureColor.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
grayScale = false;
adaptColorMapScale();
}
});
// Set color colormap
JMenuItem menuItemScale = new JMenuItem("Manual Scale");
menuItemScale.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ManualScaleDialog d = new ManualScaleDialog();
d.setLocationRelativeTo(chartPanel);
d.setLow(((PaintScaleLegend) chart.getSubtitles().get(0)).getScale().getLowerBound());
d.setHigh(((PaintScaleLegend) chart.getSubtitles().get(0)).getScale().getUpperBound());
d.setMatrixPlot(MatrixPlot.this);
d.showDialog();
if (d.getSelectedOption() == JOptionPane.OK_OPTION) {
setColorScale(d.getLow(), d.getHigh());
}
}
});
// Group colormap related menu items
JMenuItem contextMenuChooseColorMap = new JMenu("ColorMap");
contextMenuChooseColorMap.add(contextMenuItemAdaptScale);
contextMenuChooseColorMap.add(menuItemScale);
contextMenuChooseColorMap.add(contextMenuItemGrayScale);
contextMenuChooseColorMap.add(contextMenuItemTemperatureColor);
chartPanel.getPopupMenu().add(contextMenuChooseColorMap);
/*
// Add separator
chartPanel.getPopupMenu().addSeparator();
// Detach plot into an own frame
JMenuItem contextMenuItemDetach = new JMenuItem("Detach Plot");
contextMenuItemDetach.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
MatrixPlot p = new MatrixPlot();
p.setTitle(title);
p.setSeries(series);
final JFrame frame = new JFrame(title);
frame.getContentPane();
frame.setContentPane(p.getChartPanel());
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); // Close application if frame is closed
// Set color scale
p.adaptColorMapScale();
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
}
});
chartPanel.getPopupMenu().add(contextMenuItemDetach);
*/
}
/**
* Show Tooltips. This is not done per default since it makes the app slow
* for datasize >= 1M
*/
private void showTooltip() {
//Tooltips are quit expensive
DecimalFormat dm = new DecimalFormat("0.##########");
XYZToolTipGenerator xYZToolTipGenerator = new StandardXYZToolTipGenerator("{0}: ({1} / {2} / {3})", dm, dm, dm);
chart.getXYPlot().getRenderer().setBaseToolTipGenerator(xYZToolTipGenerator);
((XYBlockRenderer) chart.getXYPlot().getRenderer()).setBaseCreateEntities(true);
}
/**
* Clear Tooltips
*/
private void hideTooltip() {
//Tooltips are quit expensive
((XYBlockRenderer) chart.getXYPlot().getRenderer()).setBaseToolTipGenerator(null);
((XYBlockRenderer) chart.getXYPlot().getRenderer()).setBaseCreateEntities(false);
}
/**
* Adapt the lower and upper color map scale to the min and max data values
* of the currently selected region Need to be called AFTER the chart panel
* is created
*/
public void adaptColorMapScale() {
double[] v = series.minMaxZValue();
if (v[0] != Double.NaN && v[1] != Double.NaN && v[0] < v[1]) {
setColorScale(v[0], v[1]);
}
}
/**
* Set the min and max of color map scale to scaleMin and scaleMax
*
* @param scaleMin min value of scale
* @param scaleMax max value of scale
*/
public void setColorScale(double scaleMin, double scaleMax) {
// Create scale for legend
LookupPaintScale legendScale = new LookupPaintScale(scaleMin, scaleMax, Color.GRAY);
setScaleColors(legendScale, scaleMin, scaleMax);
// Create legend
PaintScaleLegend legend = new PaintScaleLegend(legendScale, new NumberAxis());
legend.setPadding(new RectangleInsets(5, 5, 5, 5));
// Width of the legend (colorbar)
legend.setStripWidth(20);
// Position of the legend
legend.setPosition(RectangleEdge.RIGHT);
// Remove background paint/color
legend.setBackgroundPaint(null);
// Add legend to plot panel
chart.clearSubtitles();
chart.addSubtitle(legend);
//We need a second scale for rendering only, where the 'infinities' are in correct color
LookupPaintScale rendererScale = new LookupPaintScale(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Color.GRAY);
setScaleColors(rendererScale, scaleMin, scaleMax);
// Make the paint scale range from - to + infinity
if (grayScale) {
rendererScale.add(Double.NEGATIVE_INFINITY, ColorManager.getGrayForValue(scaleMin, scaleMin, scaleMax));
rendererScale.add(Double.POSITIVE_INFINITY, ColorManager.getGrayForValue(scaleMax, scaleMin, scaleMax));
} else {
rendererScale.add(Double.NEGATIVE_INFINITY, ColorManager.getColourForValue(scaleMin, scaleMin, scaleMax));
rendererScale.add(Double.POSITIVE_INFINITY, ColorManager.getColourForValue(scaleMax, scaleMin, scaleMax));
}
((XYBlockRenderer) chart.getXYPlot().getRenderer()).setPaintScale(rendererScale);
}
/**
* Set the colors for the colored Paint Scale (either single color or
* temperature color)
*
* @param paintScale
* @param scaleMin
* @param scaleMax
*/
private void setScaleColors(PaintScale paintScale, double scaleMin, double scaleMax) {
if (grayScale) {
for (int i = 0; i < 256; i++) {
double value = scaleMin + (i / 255.0) * (scaleMax - scaleMin);
((LookupPaintScale) paintScale).add(value, ColorManager.getGrayForValue(value, scaleMin, scaleMax));
}
} else {
for (int i = 0; i < 256; i++) {
double value = scaleMin + (i / 255.0) * (scaleMax - scaleMin);
((LookupPaintScale) paintScale).add(value, ColorManager.getColourForValue(value, scaleMin, scaleMax));
}
}
}
/**
* Get the chart panel
*
* @return
*/
@Override
protected JPanel createChartPanel() {
chart = new JFreeChart(getTitle(), plot);
//Remove the series label (also called legend)
chart.removeLegend();
//AntiAliasing is used to speed up rendering
// chart.setAntiAlias(false);
// Init PaintScale
setColorScale(0, 1);
//Create the Chartpanel where the chart will be plotted
chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(chartPanelWidth, chartPanelHeight));
//All interactive menu items
adaptContextMenu(chartPanel);
return chartPanel;
}
/* (non-Javadoc)
* @see ch.psi.plot.Plot#update()
*/
@Override
public void doUpdate() {
if (chart != null) {
chart.fireChartChanged();
adaptColorMapScale();
}
}
@Override
public void updateSeries(MatrixPlotSeries series) {
doUpdate();
}
protected void addPopupMenuItem(final JMenuItem item) {
if (item == null) {
chartPanel.getPopupMenu().addSeparator();
} else {
chartPanel.getPopupMenu().add(item);
}
}
//public JFreeChart getChart() {
// return chart;
//}
//@Override
//public void setData(Object data){
// super.setData(data);
// this.data=(MatrixPlotSeries) data;
//}
}
@@ -0,0 +1,242 @@
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
package ch.psi.plot.jlchart;
import ch.psi.plot.LinePlotBase;
import ch.psi.plot.LinePlotSeries;
import ch.psi.plot.utils.MonitoredPanel;
import fr.esrf.tangoatk.widget.util.chart.DataList;
import fr.esrf.tangoatk.widget.util.chart.JLAxis;
import fr.esrf.tangoatk.widget.util.chart.JLChart;
import fr.esrf.tangoatk.widget.util.chart.JLDataView;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.util.ArrayList;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
/**
*
*/
public class LinePlot extends LinePlotBase {
final JLChart plot;
final ArrayList<JLDataView> views = new ArrayList<>();
public LinePlot() {
super();
plot = new JLChart();
plot.getXAxis().setAnnotation(JLAxis.VALUE_ANNO);
//plot.getXAxis().setLabelFormat(JLAxis.SCIENTIFIC_FORMAT);
plot.getY1Axis().setAutoScale(true);
plot.getY2Axis().setAutoScale(true);
plot.getXAxis().setAutoScale(true);
plot.getY1Axis().setGridVisible(true);
plot.getXAxis().setGridVisible(true);
/*
plot.getY1Axis().setAutoScale(false);
plot.getY2Axis().setAutoScale(false);
plot.getXAxis().setAutoScale(false);
plot.getY1Axis().setMinimum(0);
plot.getY1Axis().setMaximum(10);
plot.getY2Axis().setMinimum(0);
plot.getY2Axis().setMaximum(10);
plot.getXAxis().setMinimum(0);
plot.getXAxis().setMaximum(10);
*/
plot.setLabelVisible(false);
plot.setBackground(new Color(240, 240, 240));
setRequireUpdateOnAppend(false);
}
@Override
protected void onAxisRangeChanged(AxisId axis_id) {
JLAxis axis = null;
switch (axis_id) {
case X:
axis = plot.getXAxis();
break;
case Y:
axis = plot.getY1Axis();
break;
default:
return;
}
axis.setAutoScale(getAxis(axis_id).isAutoRange());
axis.setMinimum(getAxis(axis_id).getMin());
axis.setMaximum(getAxis(axis_id).getMax());
update(true);
}
@Override
protected Object onAddedSeries(LinePlotSeries series) {
JLDataView view = new JLDataView();
view.setColor(series.getColor());
//view.setLineWidth(1);
int markerSize = 4;
view.setName(series.getName());
view.setMarkerSize(markerSize);
view.setMarkerColor(series.getColor());
view.setViewType(JLDataView.TYPE_LINE);
if (markerSize > 0) {
view.setMarker(JLDataView.MARKER_DOT);
} else {
view.setMarker(JLDataView.MARKER_NONE);
}
if (series.getAxisY() == 2) {
plot.getY2Axis().addDataView(view);
} else {
plot.getY1Axis().addDataView(view);
}
return view;
}
JLDataView getDataView(LinePlotSeries series) {
return (JLDataView) (series.getToken());
}
@Override
protected void onRemovedSeries(LinePlotSeries series) {
JLDataView view = getDataView(series);
for (int i = 0; i < plot.getY1Axis().getViewNumber(); i++) {
if (view.getName().equals(plot.getY1Axis().getDataView(i).getName())) {
plot.getY1Axis().removeDataView(view);
}
}
for (int i = 0; i < plot.getY2Axis().getViewNumber(); i++) {
if (view.getName().equals(plot.getY2Axis().getDataView(i).getName())) {
plot.getY2Axis().removeDataView(view);
}
}
}
@Override
protected void onAppendData(LinePlotSeries series, double x, double y) {
JLDataView view = getDataView(series);
if (view != null) //view.add(x, y);
{
plot.addData(view, x, y);
}
}
@Override
protected void onSetData(LinePlotSeries series, double[] x, double[] y) {
JLDataView view = getDataView(series);
if (view != null) {
view.setData(x, y);
}
}
@Override
public double[][] getSeriesData(LinePlotSeries series) {
JLDataView view = getDataView(series);
double[] x = new double[view.getDataLength()];
double[] y = new double[x.length];
int index = 0;
DataList data = view.getData();
while (data != null) {
if (index >= x.length) {
break;
}
x[index] = data.x;
y[index] = data.y;
index++;
data = data.next;
}
return new double[][]{x, y};
}
JPanel chartPanel;
@Override
protected JPanel createChartPanel() {
JPanel chartPanel = new MonitoredPanel() {
protected void onShown() {
addKeyBindings();
}
};
chartPanel.setLayout(new BorderLayout());
chartPanel.add(plot);
chartPanel.setPreferredSize(new Dimension(480, 240));
plot.setHeader(getTitle());
plot.getY1Axis().setName(getAxis(AxisId.Y).getLabel());
plot.getXAxis().setName(getAxis(AxisId.Y).getLabel());
return chartPanel;
}
@Override
public void updateSeries(LinePlotSeries series) {
doUpdate();//TODO
}
@Override
public void doUpdate() {
plot.repaint();
}
private void addKeyBindings() {
//The zoom method ois not doing what I expecte, and no documentation...
/*
plot.setFocusable( true );
plot.requestFocusInWindow();
plot.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
doUpdate();
System.out.println("Total " + plot.getXAxis().getMinimum() + "->" + plot.getXAxis().getMaximum());
System.out.println("Zoom " + plot.getXAxis().getMin() + "->" + plot.getXAxis().getMax());
if (plot.isZoomed()){
if (e.getKeyCode()==KeyEvent.VK_RIGHT){
double w = plot.getXAxis().getMax()-plot.getXAxis().getMin();
double r = plot.getXAxis().getMax() + w/10;
//r = Math.min(r,plot.getXAxis().getMaximum());
plot.getXAxis().zoom((int)(r-w),(int)r);
System.out.println("Zooming to " + ((int)(r-w)) + "-" + ((int)r));
requestUpdate();
}
else if (e.getKeyCode()==KeyEvent.VK_LEFT){
double w = plot.getXAxis().getMax()-plot.getXAxis().getMin();
double l = plot.getXAxis().getMin() - w/10;
//l = Math.max(l,plot.getXAxis().getMinimum());
plot.getXAxis().zoom((int)l,(int)(l+w));
System.out.println("Zooming to " + ((int)l) + "-" + ((int)(l+w)));
requestUpdate();
}
}
}
@Override
public void keyReleased(KeyEvent e) {
}
});
*/
}
protected void addPopupMenuItem(final JMenuItem item) {
if (item == null) {
plot.addSeparator();
} else {
plot.addMenuItem(item);
}
}
}
@@ -0,0 +1,856 @@
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
package ch.psi.plot.jzy3d;
import ch.psi.plot.MatrixPlotBase;
import ch.psi.plot.MatrixPlotSeries;
import ch.psi.plot.utils.IO;
import ch.psi.plot.utils.MonitoredPanel;
import ch.psi.plot.utils.SwingUtils;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.SwingUtilities;
import org.jzy3d.chart.Chart;
import org.jzy3d.chart.Settings;
import org.jzy3d.colors.Color;
import org.jzy3d.colors.ColorMapper;
import org.jzy3d.colors.colormaps.ColorMapGrayscale;
import org.jzy3d.colors.colormaps.ColorMapRainbow;
import org.jzy3d.contour.DefaultContourColoringPolicy;
import org.jzy3d.contour.IContourColoringPolicy;
import org.jzy3d.contour.MapperContourPictureGenerator;
import org.jzy3d.maths.BoundingBox3d;
import org.jzy3d.maths.Coord3d;
import org.jzy3d.maths.Range;
import org.jzy3d.plot3d.builder.Builder;
import org.jzy3d.plot3d.builder.Mapper;
import org.jzy3d.plot3d.builder.concrete.OrthonormalGrid;
import org.jzy3d.plot3d.primitives.AbstractDrawable;
import org.jzy3d.plot3d.primitives.Point;
import org.jzy3d.plot3d.primitives.Polygon;
import org.jzy3d.plot3d.primitives.ScatterMultiColor;
import org.jzy3d.plot3d.primitives.Shape;
import org.jzy3d.plot3d.primitives.axes.ContourAxeBox;
import org.jzy3d.plot3d.rendering.legends.colorbars.AWTColorbarLegend;
import org.jzy3d.plot3d.rendering.view.modes.ViewBoundMode;
/**
*
*/
public class MatrixPlot extends MatrixPlotBase {
JPanel panel;
private Chart chart;
private Mapper mapper;
private Shape surface;
private MatrixPlotSeries series;
private double[][] data;
public MatrixPlot() {
super();
panel = new MonitoredPanel() {
protected void onShown() {
checkBounds(true);
}
};
panel.setLayout(new BorderLayout());
//panel.setLayout(new GridLayout(1,1));
setColormap(Colormap.TEMPERATURE);
Settings.getInstance().setHardwareAccelerated(true);
panel.setPreferredSize(new Dimension(640, 480));
setupPopupMenu();
}
@Override
protected Object onAddedSeries(final MatrixPlotSeries s) {
if (!SwingUtilities.isEventDispatchThread()) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
onAddedSeries(s);
}
});
} catch (Exception ex) {
Logger.getLogger(MatrixPlot.class.getName()).log(Level.SEVERE, null, ex);
}
return this;
}
synchronized (chartLock) {
if (s != null) {
if (chart != null) {
chart.clear();
}
}
if (s == null) {
//if (chart != null) {
//chart.clear();
//}
series = null;
data = null;
} else {
if (getAxis(AxisId.X).isAutoRange()) {
rangeX = new Range(s.getMinX(), s.getMaxX());
} else {
rangeX = new Range(getAxis(AxisId.X).getMin(), getAxis(AxisId.X).getMax());
}
if (getAxis(AxisId.Y).isAutoRange()) {
rangeY = new Range(s.getMinY(), s.getMaxY());
} else {
rangeY = new Range(getAxis(AxisId.Y).getMin(), getAxis(AxisId.Y).getMax());
}
//If same series & same dimensions then preserve data
if ((data == null) || (series != s) || (s.getNumberOfBinsY() != data.length) || (s.getNumberOfBinsX() != data[0].length)) {
data = new double[s.getNumberOfBinsY()][s.getNumberOfBinsX()];
for (int i = 0; i < data.length; i++) {
Arrays.fill(data[i], Double.NaN);
}
}
series = s;
}
}
createGraph();
return this;
}
@Override
protected void onAxisRangeChanged(AxisId axis_id) {
if (series != null) {
updateGraph(true);
}
}
@Override
protected void onRemovedSeries(MatrixPlotSeries s) {
series = null;
if (chart != null) {
chart.clear();
}
}
@Override
protected void onAppendData(MatrixPlotSeries s, int indexX, int indexY, double x, double y, double z) {
data[indexY][indexX] = z;
}
@Override
protected void onSetData(MatrixPlotSeries s, double[][] data) {
this.data = data;
}
@Override
public void doUpdate() {
updateGraph(false);
}
public void updateSeries(MatrixPlotSeries s) {
updateGraph(false);
}
@Override
public double[][] getSeriesData(MatrixPlotSeries s) {
return data;
}
@Override
protected JPanel createChartPanel() {
return panel;
}
private Range rangeX;
private Range rangeY;
double[] rangeZ = null;
boolean showLegend = true;
public void setShowLegend(boolean value) {
if (value != showLegend) {
showLegend = value;
if ((panel != null) && (panel.isShowing())) {
updateGraph(true);
}
}
}
public boolean getShowLegend() {
return showLegend;
}
boolean showFace = true;
public void setShowFace(boolean value) {
if (value != showFace) {
showFace = value;
if ((panel != null) && (panel.isShowing())) {
updateGraph(true);
}
}
}
public boolean getShowFace() {
return showFace;
}
boolean showFrame = false;
public void setShowFrame(boolean value) {
if (value != showFrame) {
showFrame = value;
if ((panel != null) && (panel.isShowing())) {
updateGraph(true);
}
}
}
public boolean getShowFrame() {
return showFrame;
}
boolean showAxis = true;
public void setShowAxis(boolean value) {
if (value != showAxis) {
showAxis = value;
if ((panel != null) && (panel.isShowing())) {
updateGraph(true);
}
}
}
public boolean getShowAxis() {
return showAxis;
}
public enum Colormap {
GRAYSCALE,
TEMPERATURE,
}
Colormap colormap = Colormap.TEMPERATURE;
public void setColormap(Colormap value) {
if (value != colormap) {
colormap = value;
if ((panel != null) && (panel.isShowing())) {
updateGraph(true);
}
}
}
public Colormap getColormap() {
return colormap;
}
public enum Quality {
LOW,
MEDIUM,
HIGH,
HIGHEST;
private org.jzy3d.plot3d.rendering.canvas.Quality toJzy3dQuality() {
switch (this) {
case LOW:
return org.jzy3d.plot3d.rendering.canvas.Quality.Fastest;
case MEDIUM:
return org.jzy3d.plot3d.rendering.canvas.Quality.Intermediate;
case HIGH:
return org.jzy3d.plot3d.rendering.canvas.Quality.Advanced;
case HIGHEST:
return org.jzy3d.plot3d.rendering.canvas.Quality.Nicest;
}
return null;
}
}
Quality quality = Quality.HIGH;
public void setQuality(Quality quality) {
this.quality = quality;
if (series != null) {
createGraph();
}
}
public Quality getQuality() {
return quality;
}
public enum Mode {
TOP,
PROFILE,
FREE;
private org.jzy3d.plot3d.rendering.view.modes.ViewPositionMode toJzy3dMode() {
switch (this) {
case TOP:
return org.jzy3d.plot3d.rendering.view.modes.ViewPositionMode.TOP;
case PROFILE:
return org.jzy3d.plot3d.rendering.view.modes.ViewPositionMode.PROFILE;
case FREE:
return org.jzy3d.plot3d.rendering.view.modes.ViewPositionMode.FREE;
}
return null;
}
}
Mode mode = Mode.FREE;
public void setMode(Mode mode) {
this.mode = mode;
if (series != null) {
updateGraph(true);
}
}
public Mode getMode() {
return mode;
}
public enum Contour {
NONE,
NORMAL,
FILLED,
HEIGHT_MAP,
CONTOUR_3D
}
Contour contour = Contour.NONE;
public void setContour(Contour contour) {
this.contour = contour;
if (series != null) {
createGraph();
}
}
public Contour getContour() {
return contour;
}
int contourLevels = 10;
public void setContourLevels(int value) {
contourLevels = value;
updateGraph(true);
}
public int getContourLevels() {
return contourLevels;
}
int contourDensity = 400;
public void setContourDensity(int value) {
contourDensity = value;
updateGraph(true);
}
public int getContourDensity() {
return contourDensity;
}
java.awt.Color frameColor = java.awt.Color.BLACK;
public void setFrameColor(java.awt.Color value) {
frameColor = value;
updateGraph(true);
}
public java.awt.Color getFrameColor() {
return frameColor;
}
JPopupMenu menuPopup;
void setupPopupMenu() {
menuPopup = new JPopupMenu();
JMenuItem menuUpdate = new JMenuItem("Update");
final JCheckBoxMenuItem menuShowAxis = new JCheckBoxMenuItem("Show Axis");
final JCheckBoxMenuItem menuShowLegend = new JCheckBoxMenuItem("Show Legend");
final JCheckBoxMenuItem menuShowFace = new JCheckBoxMenuItem("Show Face");
final JCheckBoxMenuItem menuShowFrame = new JCheckBoxMenuItem("Show Frame");
JMenuItem frameColor = new JMenuItem("Set Frame Color");
final JMenu menuColormap = new JMenu("Colormap");
final JMenu menuMode = new JMenu("Mode");
final JMenu menuContour = new JMenu("Contour");
final JMenu menuQuality = new JMenu("Quality");
menuPopup.add(menuShowAxis);
menuPopup.add(menuShowLegend);
menuPopup.add(menuShowFace);
menuPopup.add(menuShowFrame);
menuPopup.add(frameColor);
menuPopup.add(menuColormap);
menuPopup.add(menuMode);
menuPopup.add(menuContour);
menuPopup.add(menuQuality);
menuPopup.add(menuUpdate);
menuUpdate.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
updateGraph(true);
} catch (Exception ex) {
}
}
});
frameColor.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
String ret = SwingUtils.getString(panel, "Enter frame color (name or R,G,B):", getFrameColor().getRed() + "," + getFrameColor().getGreen() + "," + getFrameColor().getBlue());
if (ret != null) {
java.awt.Color color = null;
if (ret.contains(",")) {
String[] tokens = ret.split(",");
color = new java.awt.Color(Integer.valueOf(tokens[0]), Integer.valueOf(tokens[1]), Integer.valueOf(tokens[2]));
} else {
Field field = java.awt.Color.class.getField(ret);
color = (java.awt.Color) field.get(null);
}
setFrameColor(color);
updateGraph(true);
}
} catch (Exception ex) {
SwingUtils.showException(panel, ex);
}
}
});
menuShowFrame.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setShowFrame(!getShowFrame());
menuShowFrame.setSelected(getShowFrame());
}
});
menuShowFrame.setSelected(getShowFrame());
menuShowLegend.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setShowLegend(!getShowLegend());
menuShowLegend.setSelected(getShowLegend());
}
});
menuShowLegend.setSelected(getShowLegend());
menuShowFace.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setShowFace(!getShowFace());
menuShowLegend.setSelected(getShowFace());
}
});
menuShowFace.setSelected(getShowFace());
menuShowAxis.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setShowAxis(!getShowAxis());
menuShowAxis.setSelected(getShowAxis());
}
});
menuShowAxis.setSelected(getShowAxis());
ButtonGroup colormapGroup = new ButtonGroup();
for (Colormap c : Colormap.values()) {
final JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(c.toString());
colormapGroup.add(menuItem);
menuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setColormap(Colormap.valueOf(e.getActionCommand()));
}
});
menuItem.setSelected(getColormap().toString().equals(menuItem.getText()));
menuColormap.add(menuItem);
}
ButtonGroup modeGroup = new ButtonGroup();
for (Mode q : Mode.values()) {
final JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(q.toString());
modeGroup.add(menuItem);
menuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setMode(Mode.valueOf(e.getActionCommand()));
}
});
menuItem.setSelected(getMode().toString().equals(menuItem.getText()));
menuMode.add(menuItem);
}
ButtonGroup contourGroup = new ButtonGroup();
for (Contour q : Contour.values()) {
final JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(q.toString());
contourGroup.add(menuItem);
menuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setContour(Contour.valueOf(e.getActionCommand()));
}
});
menuItem.setSelected(getContour().toString().equals(menuItem.getText()));
menuContour.add(menuItem);
}
menuContour.addSeparator();
JMenuItem levels = new JMenuItem("Set Levels");
levels.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
String ret = SwingUtils.getString(panel, "Enter number of contour levels:", getContourLevels());
if (ret != null) {
Integer levels = Integer.valueOf(ret);
setContourLevels(levels);
}
} catch (Exception ex) {
SwingUtils.showException(panel, ex);
}
}
});
menuContour.add(levels);
JMenuItem density = new JMenuItem("Set Density");
density.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
String ret = SwingUtils.getString(panel, "Enter contour density:", getContourDensity());
if (ret != null) {
Integer density = Integer.valueOf(ret);
setContourDensity(density);
}
} catch (Exception ex) {
SwingUtils.showException(panel, ex);
}
}
});
menuContour.add(density);
ButtonGroup qualityGroup = new ButtonGroup();
for (Quality q : Quality.values()) {
final JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(q.toString());
qualityGroup.add(menuItem);
menuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setQuality(Quality.valueOf(e.getActionCommand()));
}
});
menuItem.setSelected(getQuality().toString().equals(menuItem.getText()));
menuQuality.add(menuItem);
}
}
protected static void remap(Shape shape, Mapper mapper) {
List<AbstractDrawable> polygons = shape.getDrawables();
for (AbstractDrawable d : polygons) {
if (d instanceof Polygon) {
Polygon p = (Polygon) d;
for (int i = 0; i < p.size(); i++) {
Point pt = p.get(i);
Coord3d c = pt.xyz;
c.z = (float) mapper.f(c.x, c.y);
}
}
}
}
final Object chartLock = new Object();
void createGraph() { /*
if (!SwingUtilities.isEventDispatchThread()) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
createGraph();
}
});
} catch (Exception ex) {
Logger.getLogger(MatrixPlot.class.getName()).log(Level.SEVERE, null, ex);
}
}
*/
synchronized (chartLock) {
if (series != null) {
if ((getContour() == Contour.NONE) || (getContour() == Contour.CONTOUR_3D)) {
chart = org.jzy3d.chart.factories.ContourChartComponentFactory.chart(getQuality().toJzy3dQuality(), "awt");
} else {
chart = new org.jzy3d.chart.factories.ContourChartComponentFactory().newChart(getQuality().toJzy3dQuality(), "awt");
}
if (rangeY == null) {
rangeY = new Range(0, data.length - 1);
}
if (rangeX == null) {
rangeX = new Range(0, data[0].length - 1);
}
mapper = new Mapper() {
@Override
public double f(double x, double y) {
if (data == null) {
return Double.NaN;
}
return data[(int) Math.round((y - rangeY.getMin()) / ((rangeY.getMax() - rangeY.getMin()) / (data.length - 1)))][(int) Math.round((x - rangeX.getMin()) / ((rangeX.getMax() - rangeX.getMin()) / (data[0].length - 1)))];
}
};
Component canvas = (Component) chart.getCanvas();
panel.removeAll();
panel.add(canvas);
//Todo: why it is not displyed if I don'r pack the Window?
if (panel.isVisible()) {
panel.validate();
}
chart.addMouseController();
chart.getAxeLayout().setXAxeLabel(getAxis(AxisId.X).getLabel());
chart.getAxeLayout().setYAxeLabel(getAxis(AxisId.Y).getLabel());
chart.getAxeLayout().setZAxeLabel(getAxis(AxisId.Z).getLabel());
chart.getCanvas().addMouseController(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
checkPopup(e);
}
@Override
public void mousePressed(MouseEvent e) {
checkPopup(e);
}
private void checkPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
menuPopup.show(e.getComponent(), e.getX(), e.getY());
}
}
});
}
updateGraph(true);
}
}
private void updateGraph(final boolean newSeries) {
if (!SwingUtilities.isEventDispatchThread()) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
updateGraph(newSeries);
}
});
return;
}
//long start = System.currentTimeMillis();
synchronized (chartLock) {
Shape former = surface;
if (series == null) {
if (surface != null) {
chart.getScene().getGraph().remove(former, false);
}
surface = null;
} else {
//TODO: Not succeding having the partial updates - and they are not performing much better neither
boolean changedBoundsZ = checkBounds(false);
if ((surface == null) || (newSeries) || getAxis(AxisId.Z).isAutoRange() || changedBoundsZ) {
//if (true) {
surface = (Shape) Builder.buildOrthonormal(
new OrthonormalGrid(rangeX, series.getNumberOfBinsX(), rangeY, series.getNumberOfBinsY()), mapper);
ColorMapper colorMapper = new ColorMapper((colormap == Colormap.TEMPERATURE) ? new ColorMapRainbow() : new ColorMapGrayscale(),
(float) ((getAxis(AxisId.Z).isAutoRange()) ? surface.getBounds().getZmin() : getAxis(AxisId.Z).getMin()),
(float) ((getAxis(AxisId.Z).isAutoRange()) ? surface.getBounds().getZmax() : getAxis(AxisId.Z).getMax()),
new Color(1, 1, 1, .5f));
surface.setColorMapper(colorMapper);
surface.setFaceDisplayed(true);
surface.setWireframeDisplayed(getShowFrame());
surface.setWireframeColor(new Color(frameColor.getRed(), frameColor.getGreen(), frameColor.getBlue(), frameColor.getAlpha()));
surface.setFaceDisplayed(getShowFace());
if (getShowLegend()) {
AWTColorbarLegend cbar = new AWTColorbarLegend(surface, chart.getView().getAxe().getLayout());
surface.setLegend(cbar);
}
if (getContour() != Contour.NONE) {
int xRes = getContourDensity();
int yRes = getContourDensity();
MapperContourPictureGenerator contour = new MapperContourPictureGenerator(mapper, rangeX, rangeY);
IContourColoringPolicy policy = new DefaultContourColoringPolicy(colorMapper);
ContourAxeBox cab = (getContour() == Contour.CONTOUR_3D) ? null : (ContourAxeBox) chart.getView().getAxe();
switch (getContour()) {
case NORMAL:
cab.setContourImg(contour.getContourImage(policy, xRes, yRes, getContourLevels()), rangeX, rangeY);
break;
case FILLED:
cab.setContourImg(contour.getFilledContourImage(policy, xRes, yRes, getContourLevels()), rangeX, rangeY);
break;
case HEIGHT_MAP:
cab.setContourImg(contour.getHeightMap(policy, xRes, yRes, getContourLevels()), rangeX, rangeY);
break;
case CONTOUR_3D:
//int nx=series.getNumberOfBinsX();
//int ny=series.getNumberOfBinsY();
float dx = ((float) series.getNumberOfBinsX()) / xRes;
float dy = ((float) series.getNumberOfBinsY()) / yRes;
double[][] contours = contour.getContourMatrix(xRes, yRes, getContourLevels());
// Create the dot cloud scene and fill with data
int size = xRes * yRes;
Coord3d[] points = new Coord3d[size];
for (int x = 0; x < xRes; x++) {
for (int y = 0; y < yRes; y++) {
float px = (float) ((float) x * dx * series.getBinWidthX() + series.getMinX());
float py = (float) ((float) y * dy * series.getBinWidthY() + series.getMinY());
if (contours[x][y] > -Double.MAX_VALUE) { // Non contours points are -Double.MAX_VALUE and are not painted
points[x * yRes + y] = new Coord3d(px, py, (float) contours[x][y]);
} else {
points[x * yRes + y] = new Coord3d(px, py, Float.NaN);
//points[x*ny+y] = new Coord3d((float)x * series.getBinWidthX()+ series.getMinX(),(float)y* series.getBinWidthY()+ series.getMinY(),(float)0.0);
//points[x*ny+y] = new Coord3d((float)x * series.getBinWidthX()+ series.getMinX(),(float)y* series.getBinWidthY()+ series.getMinY(),(float)mapper.f((float)x * series.getBinWidthX()+ series.getMinX(), (float)y* series.getBinWidthY()+ series.getMinY()));
}
}
}
//ScatterMultiColor scatter = new ScatterMultiColor( points, new ColorMapper( new ColorMapRainbow(), -600.0f, 600.0f ) );
ScatterMultiColor scatter = new ScatterMultiColor(points, colorMapper);
surface.add(scatter);
//chart.getScene().add(scatter);
break;
}
}
chart.setViewMode(getMode().toJzy3dMode());
chart.setAxeDisplayed(getShowAxis());
}
if (surface == former) {
remap(surface, mapper);
chart.render();
} else {
chart.getScene().getGraph().add(surface, false);
if (former != null) {
chart.getScene().getGraph().remove(former, false);
}
boolean changed = checkBounds(true);
//if (!changed)
// chart.getView().updateBounds();
}
}
//System.out.println(System.currentTimeMillis()-start);
}
}
protected boolean checkBounds(boolean updateBounds) {
if (chart == null) {
return false;
}
boolean changed = false;
//If manual bounds
if (!getAxis(AxisId.X).isAutoRange() || !getAxis(AxisId.Y).isAutoRange() || !getAxis(AxisId.Z).isAutoRange()) {
//Deferring setting bounds untiul the panel is displayed
if (panel.isShowing() && (chart != null)) {
if (chart.getView().getBoundsMode() != ViewBoundMode.MANUAL) {
changed = true;
}
BoundingBox3d bounds = chart.getView().getBounds();
if (!getAxis(AxisId.X).isAutoRange()) {
if (bounds.getXmin() != getAxis(AxisId.X).getMin()) {
bounds.setXmin((float) getAxis(AxisId.X).getMin());
changed = true;
}
if (bounds.getXmax() != getAxis(AxisId.X).getMax()) {
bounds.setXmax((float) getAxis(AxisId.X).getMax());
changed = true;
}
}
if (!getAxis(AxisId.Y).isAutoRange()) {
if (bounds.getYmin() != getAxis(AxisId.Y).getMin()) {
bounds.setYmin((float) getAxis(AxisId.Y).getMin());
changed = true;
}
if (bounds.getYmax() != getAxis(AxisId.Y).getMax()) {
bounds.setYmax((float) getAxis(AxisId.Y).getMax());
changed = true;
}
}
if (!getAxis(AxisId.Z).isAutoRange()) {
if (bounds.getZmin() != getAxis(AxisId.Z).getMin()) {
bounds.setZmin((float) getAxis(AxisId.Z).getMin());
changed = true;
}
if (bounds.getZmax() != getAxis(AxisId.Z).getMax()) {
bounds.setZmax((float) getAxis(AxisId.Z).getMax());
changed = true;
}
}
if (changed && updateBounds) {
chart.getView().setBoundManual(bounds);
}
}
} else if (chart.getView().getBoundsMode() != ViewBoundMode.AUTO_FIT) {
if (updateBounds) {
chart.getView().setBoundMode(ViewBoundMode.AUTO_FIT);
}
changed = true;
}
return changed;
}
protected void addPopupMenuItem(final JMenuItem item) {
if (item == null) {
menuPopup.addSeparator();
} else {
menuPopup.add(item);
}
}
@Override
public BufferedImage getSnapshot() {
File temp=null;
try{
temp = File.createTempFile("snapshot", ".bmp");
chart.screenshot(temp);
return IO.readImageFromFile(temp.getAbsolutePath());
}
catch (Exception ex){
return null;
}
finally{
if (temp!=null)
temp.delete();
}
}
public void saveSnapshot(String filename, String format) throws IOException {
if (chart!=null){
chart.screenshot(new File(filename));
}
}
}
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
package ch.psi.plot.utils;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import javax.imageio.ImageIO;
/**
*
*/
public class IO {
public static void writeArrayToFile(String filename, byte arr[]) throws IOException {
OutputStream fout = null;
try {
fout = new BufferedOutputStream(new FileOutputStream(filename, false));
if (arr != null) {
new PrintStream(fout).write(arr, 0, arr.length);
}
fout.flush();
} finally {
if (fout != null) {
fout.close();
}
}
}
public static void writeStringToFile(String filename, String str) throws IOException {
writeArrayToFile(filename, str.getBytes("UTF-8"));
}
public static void writeImageToFile(BufferedImage image, String filename, String format) throws IOException {
if (image != null) {
ImageIO.write(image, format, new File(filename));
}
}
public static BufferedImage readImageFromFile(String filename) throws IOException {
return ImageIO.read(new File(filename));
}
public static String getExtension(File f) {
String ext = null;
String s = f.getName();
int i = s.lastIndexOf('.');
if (i > 0 && i < s.length() - 1) {
ext = s.substring(i + 1).toLowerCase();
}
return ext;
}
}
@@ -0,0 +1,41 @@
package ch.psi.plot.utils;
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import javax.swing.JPanel;
/**
*
*/
public class MonitoredPanel extends JPanel {
public MonitoredPanel() {
addHierarchyListener(new HierarchyListener() {
@Override
public void hierarchyChanged(HierarchyEvent e) {
if ((HierarchyEvent.SHOWING_CHANGED & e.getChangeFlags()) != 0) {
if (isShowing()) {
try {
onShown();
} catch (Exception ex) {
}
} else {
try {
onHidden();
} catch (Exception ex) {
}
}
}
}
});
}
protected void onShown() {
}
protected void onHidden() {
}
}
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
package ch.psi.plot.utils;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JOptionPane;
/**
*
*/
public class SwingUtils {
public static void centerOnParent(Component parent, Component component) {
Rectangle r = parent.getBounds();
Dimension w = component.getSize();
int x = Math.max(r.x + (r.width - w.width) / 2, 4);
int y = Math.max(r.y + (r.height - w.height) / 2, 4);
component.setLocation(x, y);
}
public static void centerOnScreen(Component component) {
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
component.setLocation(dim.width / 2 - component.getSize().width / 2, dim.height / 2 - component.getSize().height / 2);
}
public static Color generateRandomColor() {
Random random = new Random();
Color mix = Color.WHITE;
int red = (random.nextInt(256) + mix.getRed()) / 2;
int green = (random.nextInt(256) + mix.getGreen()) / 2;
int blue = (random.nextInt(256) + mix.getBlue()) / 2;
Color color = new Color(red, green, blue);
return color;
}
public static void showMessage(Component parent, String title, String msg) {
JOptionPane.showMessageDialog(parent, msg, title, JOptionPane.INFORMATION_MESSAGE, null);
}
public static void showException(Component parent, Exception ex) {
JOptionPane.showMessageDialog(parent, ex.getMessage(), "Exception", JOptionPane.WARNING_MESSAGE, null);
}
public static String getString(Component parent, String msg, Object current_value) {
return JOptionPane.showInputDialog(parent, msg, String.valueOf(current_value));
}
public static BufferedImage createImage(Component panel) {
if (panel == null) {
return null;
}
Dimension size = panel.getSize();
BufferedImage image = new BufferedImage(
size.width, size.height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = image.createGraphics();
panel.paint(g2);
return image;
}
}
@@ -1,472 +0,0 @@
package ch.psi.plot.xy;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.text.DecimalFormat;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.annotations.XYAnnotation;
import org.jfree.chart.annotations.XYDrawableAnnotation;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.entity.StandardEntityCollection;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.labels.XYToolTipGenerator;
import org.jfree.chart.plot.Marker;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.ValueMarker;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.Range;
import org.jfree.data.xy.XYDataItem;
import org.jfree.ui.Layer;
import org.jfree.ui.RectangleAnchor;
import org.jfree.ui.RefineryUtilities;
import org.jfree.ui.TextAnchor;
import ch.psi.plot.Plot;
import ch.psi.plot.xy.tools.Average;
import ch.psi.plot.xy.tools.CrossAnnotation;
import ch.psi.plot.xy.tools.Derivative;
import ch.psi.plot.xy.tools.Integral;
import ch.psi.plot.xy.tools.Maximum;
import ch.psi.plot.xy.tools.Minimum;
public class LinePlot implements Plot {
private static final Logger logger = Logger.getLogger(LinePlot.class.getName());
private ChartPanel chartPanel;
private static final int chartPanelWidth = 500;
private static final int chartPanelHeight = 270;
//Defining Context Menu Label
private static final String showLegendMenuLabel = "Show Legend";
private static final String hideLegendMenuLabel = "Hide Legend";
private static final String showTooltipsMenuLabel = "Show Tooltips";
private static final String hideTooltipsMenuLabel = "Hide Tooltips";
private XYSeriesCollectionP data;
JFreeChart chart;
private String title;
private String xAxisLabel = "X";
private String yAxisLabel = "Y";
private boolean tooltips = false;
/**
* @param title Title of plot
*/
public LinePlot(String title){
this(title, new XYSeriesCollectionP());
}
/**
* @param title Title of plot
* @param data Data of plot
*/
public LinePlot(String title, XYSeriesCollectionP data){
this.title = title;
this.data = data;
}
/**
* Get the chart panel of this plot. The chart panel will be lazily created
* the first time this function is called
* @return
*/
@Override
public ChartPanel getChartPanel() {
if(chartPanel == null){
// Create chart
chart = ChartFactory.createXYLineChart(this.title, xAxisLabel, yAxisLabel, data, PlotOrientation.VERTICAL, true, tooltips, false);
// Customize chart look and feel
// Customize background (gray: new Color(238,238,238))
chart.setBackgroundPaint(null);
// Customize legend
chart.getLegend().setVisible(false);
chart.getLegend().setBackgroundPaint(null);
chart.getLegend().setBorder(0, 0, 0, 0);
// Customize plot area look and feel
XYPlot plot = (XYPlot) chart.getPlot();
plot.setBackgroundPaint(Color.white);
plot.setDomainGridlinePaint(Color.gray);
plot.setRangeGridlinePaint(Color.gray);
// Show data point
((XYLineAndShapeRenderer)plot.getRenderer()).setBaseShapesVisible(true);
// Include zeros in range (x) axis
((NumberAxis) plot.getRangeAxis()).setAutoRangeIncludesZero(false);
// Lazy creation of the chart panel
chartPanel = new ChartPanel(chart);
chartPanel.setName(title);
// Remove border
chartPanel.getChart().setBorderVisible(false);
// Set size of chart
chartPanel.setPreferredSize(new java.awt.Dimension(chartPanelWidth, chartPanelHeight));
// Add more items to the context menu
amendContextMenu();
//Activate (arrow) keys
addKeyBindings();
}
return chartPanel;
}
/**
* Change visible part of chart
* @param translationVector
*/
private void moverOverPlot(XYDataItem translationVector) {
double translatedDomainIntervalMin = chart.getXYPlot().getDomainAxis().getRange().getLowerBound() + translationVector.getX().doubleValue();
double translatedDomainIntervalMax = chart.getXYPlot().getDomainAxis().getRange().getUpperBound() + translationVector.getX().doubleValue();
double translatedRangeIntervalMin = chart.getXYPlot().getRangeAxis().getRange().getLowerBound() + translationVector.getY().doubleValue();
double translatedRangeIntervalMax = chart.getXYPlot().getRangeAxis().getRange().getUpperBound() + translationVector.getY().doubleValue();
Range domainAxisRange = new Range(translatedDomainIntervalMin, translatedDomainIntervalMax);
Range rangeAxisRange = new Range(translatedRangeIntervalMin, translatedRangeIntervalMax);
//We set notify to false in the first call..
chart.getXYPlot().getDomainAxis().setRange(domainAxisRange, true, false);
//...and true in the last
chart.getXYPlot().getRangeAxis().setRange(rangeAxisRange, true, true);
}
/**
* Add key bindings to chart panel
*/
private void addKeyBindings(){
final String moveUpKey = "move up";
final String moveDownKey = "move down";
final String moveRightKey = "move right";
final String moveLeftKey = "move left";
// Up arrow
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), moveUpKey);
chartPanel.getActionMap().put(moveUpKey, new AbstractAction() {
// Default serial id
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
moverOverPlot(new XYDataItem(0.0, ((NumberAxis)chart.getXYPlot().getRangeAxis()).getTickUnit().getSize()));
}
});
// Down arrow
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),moveDownKey);
chartPanel.getActionMap().put(moveDownKey, new AbstractAction() {
// Default serial id
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
moverOverPlot(new XYDataItem(0.0, - ((NumberAxis)chart.getXYPlot().getRangeAxis()).getTickUnit().getSize()));
}
});
// Right arrow
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),moveRightKey);
chartPanel.getActionMap().put(moveRightKey, new AbstractAction() {
// Default serial id
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
moverOverPlot(new XYDataItem(((NumberAxis)chart.getXYPlot().getDomainAxis()).getTickUnit().getSize(), 0.0));
}
});
// Left arrow
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),moveLeftKey);
chartPanel.getActionMap().put(moveLeftKey, new AbstractAction() {
// Default serial id
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
moverOverPlot(new XYDataItem(- ((NumberAxis)chart.getXYPlot().getDomainAxis()).getTickUnit().getSize(), 0.0));
}
});
}
/**
* Add additional items to the context menu of the plot
*/
public void amendContextMenu(){
chartPanel.getPopupMenu().addSeparator();
JMenu toolsMenu = new JMenu("Tools");
chartPanel.getPopupMenu().add(toolsMenu);
// Mark average
JMenuItem averageMenuItem = new JMenuItem("Average");
averageMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Average average = new Average();
for (XYSeriesP series : data.getSeries()) {
double a = average.average(series);
// Remove all range markers
Collection<?> c = chartPanel.getChart().getXYPlot().getRangeMarkers(Layer.FOREGROUND);
if(c!=null){
for(final Object marker: c){
SwingUtilities.invokeLater(new Runnable() { // Avoid concurrent modification exception
@Override
public void run() {
chartPanel.getChart().getXYPlot().removeRangeMarker((Marker) marker);
}
});
}
}
final ValueMarker marker = new ValueMarker(a, Color.BLACK, new BasicStroke(1));
marker.setLabel("Average ["+series.getKey()+"]: "+String.format("%.6f", a));
marker.setLabelAnchor(RectangleAnchor.CENTER);
marker.setLabelTextAnchor(TextAnchor.TOP_RIGHT);
SwingUtilities.invokeLater(new Runnable() { // Avoid concurrent modification exception
@Override
public void run() {
chartPanel.getChart().getXYPlot().addRangeMarker(marker, Layer.FOREGROUND);
}
});
}
}
});
toolsMenu.add(averageMenuItem);
// Mark minimum value
JMenuItem minimumMenuItem = new JMenuItem("Minimum");
minimumMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Minimum minimum = new Minimum();
for (XYSeriesP series : data.getSeries()) {
XYDataItem m = minimum.minimum(series);
// System.out.println("Minimum: "+m.getXValue());
// Remove all annotation for the series
for(Object o: chartPanel.getChart().getXYPlot().getAnnotations()){
chartPanel.getChart().getXYPlot().removeAnnotation((XYAnnotation) o);
}
XYDrawableAnnotation cross = new XYDrawableAnnotation(m.getXValue(), m.getYValue(), 10.0, 10.0, new CrossAnnotation(Color.BLACK));
cross.setToolTipText("Minimum: "+m.getXValue() +" / "+ m.getYValue());
chartPanel.getChart().getXYPlot().addAnnotation(cross);
}
}
});
toolsMenu.add(minimumMenuItem);
// Mark maximum value
JMenuItem maximumMenuItem = new JMenuItem("Maximum");
maximumMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Maximum maximum = new Maximum();
for (XYSeriesP series : data.getSeries()) {
XYDataItem m = maximum.maximum(series);
// Remove all annotation for the series
for(Object o: chartPanel.getChart().getXYPlot().getAnnotations()){
chartPanel.getChart().getXYPlot().removeAnnotation((XYAnnotation) o);
}
XYDrawableAnnotation cross = new XYDrawableAnnotation(m.getXValue(), m.getYValue(), 10.0, 10.0, new CrossAnnotation(Color.BLACK));
cross.setToolTipText("Maximum: "+m.getXValue() +" / "+ m.getYValue());
chartPanel.getChart().getXYPlot().addAnnotation(cross);
}
}
});
toolsMenu.add(maximumMenuItem);
// Show derivative
JMenuItem derivativeMenuItem = new JMenuItem("Derivative");
derivativeMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Derivative derivative = new Derivative();
LinePlot p = new LinePlot("Derivative - " + title, derivative.derivative(data));
JFrame frame = new JFrame();
frame.setContentPane(p.getChartPanel());
frame.pack();
RefineryUtilities.centerFrameOnScreen(frame);
frame.setVisible(true);
}
});
toolsMenu.add(derivativeMenuItem);
// Show integral
JMenuItem integralMenuItem = new JMenuItem("Integral");
integralMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Integral integral = new Integral();
// Show new frame
LinePlot p = new LinePlot("Integral - "+title, integral.integral(data));
JFrame frame = new JFrame();
frame.setContentPane(p.getChartPanel());
frame.pack();
RefineryUtilities.centerFrameOnScreen(frame);
frame.setVisible(true);
}
});
toolsMenu.add(integralMenuItem);
chartPanel.getPopupMenu().addSeparator();
// Detach plot into a separate frame
JMenuItem detachPlotMenuItem = new JMenuItem("Detach");
detachPlotMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
LinePlot p = new LinePlot(title, data);
JFrame frame = new JFrame();
frame.setContentPane(p.getChartPanel());
frame.pack();
RefineryUtilities.centerFrameOnScreen(frame);
frame.setVisible(true);
}
});
chartPanel.getPopupMenu().add(detachPlotMenuItem);
// Hide/Show legend
JMenuItem hideLegendMenuItem = new JMenuItem(showLegendMenuLabel);
hideLegendMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem source = (JMenuItem)(e.getSource());
if(source.getText() == showLegendMenuLabel){
chart.getLegend().setVisible(true);
source.setText(hideLegendMenuLabel);
}
else if(source.getText() == hideLegendMenuLabel){
chart.getLegend().setVisible(false);
source.setText(showLegendMenuLabel);
}
}
});
chartPanel.getPopupMenu().add(hideLegendMenuItem);
// Hide/Show tooltips
JMenuItem hideToolTipsMenuItem = new JMenuItem(hideTooltipsMenuLabel);
if(!tooltips){
hideToolTipsMenuItem.setText(showTooltipsMenuLabel);
}
hideToolTipsMenuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem source = (JMenuItem)(e.getSource());
if(source.getText() == showTooltipsMenuLabel){
showTooltips();
source.setText(hideTooltipsMenuLabel);
}
else if(source.getText() == hideTooltipsMenuLabel){
hideTooltips();
source.setText(showTooltipsMenuLabel);
}
}
});
chartPanel.getPopupMenu().add(hideToolTipsMenuItem);
}
private void showTooltips(){
tooltips = true;
DecimalFormat dm = new DecimalFormat("0.##########");
XYToolTipGenerator xYToolTipGenerator = new StandardXYToolTipGenerator( "{1}/{2}", dm, dm);
chart.getXYPlot().getRenderer().setBaseToolTipGenerator(xYToolTipGenerator);
chartPanel.setDisplayToolTips(true);
chartPanel.getChartRenderingInfo().setEntityCollection(new StandardEntityCollection());
}
private void hideTooltips(){
tooltips = false;
// http://www.jfree.org/phpBB2/viewtopic.php?t=12788&highlight=redraw+speed+performance+problem
chartPanel.getChartRenderingInfo().setEntityCollection(null);
chart.getXYPlot().getRenderer().setBaseToolTipGenerator(null);
}
@Override
public void update() {
if(data != null){
SwingUtilities.invokeLater(new Runnable() { // Try to avoid concurrent modification exception
@Override
public void run() {
try{
for(XYSeriesP s:data.getSeries()){
s.fireSeriesChanged();
}
}
catch(ConcurrentModificationException e){
logger.log(Level.WARNING, "Series got modified concurrently: "+e.getMessage(), e);
}
}
});
}
}
@Override
public JFreeChart getChart() {
return chart;
}
// Getter and setter
public XYSeriesCollectionP getData() {
return data;
}
public String getxAxisLabel() {
return xAxisLabel;
}
public void setxAxisLabel(String xAxisLabel) {
this.xAxisLabel = xAxisLabel;
}
public String getyAxisLabel() {
return yAxisLabel;
}
public void setyAxisLabel(String yAxisLabel) {
this.yAxisLabel = yAxisLabel;
}
}
@@ -1,626 +0,0 @@
/* ===========================================================
* JFreeChart : a free chart library for the Java(tm) platform
* ===========================================================
*
* (C) Copyright 2000-2009, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jfreechart/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* -----------------------
* XYSeriesCollection.java
* -----------------------
* (C) Copyright 2001-2009, by Object Refinery Limited and Contributors.
*
* Original Author: David Gilbert (for Object Refinery Limited);
* Contributor(s): Aaron Metzger;
*
* Changes
* -------
* 15-Nov-2001 : Version 1 (DG);
* 03-Apr-2002 : Added change listener code (DG);
* 29-Apr-2002 : Added removeSeries, removeAllSeries methods (ARM);
* 07-Oct-2002 : Fixed errors reported by Checkstyle (DG);
* 26-Mar-2003 : Implemented Serializable (DG);
* 04-Aug-2003 : Added getSeries() method (DG);
* 31-Mar-2004 : Modified to use an XYIntervalDelegate.
* 05-May-2004 : Now extends AbstractIntervalXYDataset (DG);
* 18-Aug-2004 : Moved from org.jfree.data --> org.jfree.data.xy (DG);
* 17-Nov-2004 : Updated for changes to DomainInfo interface (DG);
* 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
* 28-Mar-2005 : Fixed bug in getSeries(int) method (1170825) (DG);
* 05-Oct-2005 : Made the interval delegate a dataset listener (DG);
* ------------- JFREECHART 1.0.x ---------------------------------------------
* 27-Nov-2006 : Added clone() override (DG);
* 08-May-2007 : Added indexOf(XYSeries) method (DG);
* 03-Dec-2007 : Added getSeries(Comparable) method (DG);
* 22-Apr-2008 : Implemented PublicCloneable (DG);
* 27-Feb-2009 : Overridden getDomainOrder() to detect when all series are
* sorted in ascending order (DG);
* 06-Mar-2009 : Implemented RangeInfo (DG);
* 06-Mar-2009 : Fixed equals() implementation (DG);
*
*/
package ch.psi.plot.xy;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.jfree.data.DomainInfo;
import org.jfree.data.DomainOrder;
import org.jfree.data.Range;
import org.jfree.data.RangeInfo;
import org.jfree.data.UnknownKeyException;
import org.jfree.data.general.DatasetChangeEvent;
import org.jfree.data.xy.AbstractIntervalXYDataset;
import org.jfree.data.xy.IntervalXYDataset;
import org.jfree.data.xy.IntervalXYDelegate;
import org.jfree.data.xy.XYDataItem;
/**
* Represents a collection of {@link XYSeries} objects that can be used as a
* dataset.
*/
public class XYSeriesCollectionP extends AbstractIntervalXYDataset
implements IntervalXYDataset, DomainInfo, RangeInfo,
Serializable {
/** For serialization. */
private static final long serialVersionUID = -7590013825931496766L;
/** The series that are included in the collection. */
private List<XYSeriesP> data;
/** The interval delegate (used to calculate the start and end x-values). */
private IntervalXYDelegate intervalDelegate;
/**
* Constructs an empty dataset.
*/
public XYSeriesCollectionP() {
this(null);
}
/**
* Constructs a dataset and populates it with a single series.
*
* @param series the series (<code>null</code> ignored).
*/
public XYSeriesCollectionP(XYSeriesP series) {
this.data = new ArrayList<XYSeriesP>();
this.intervalDelegate = new IntervalXYDelegate(this, false);
addChangeListener(this.intervalDelegate);
if (series != null) {
this.data.add(series);
series.addChangeListener(this);
}
}
/**
* Returns the order of the domain (X) values, if this is known.
*
* @return The domain order.
*/
public DomainOrder getDomainOrder() {
return DomainOrder.NONE; // No specific order
// return DomainOrder.ASCENDING;
}
/**
* Adds a series to the collection and sends a {@link DatasetChangeEvent}
* to all registered listeners.
*
* @param series the series (<code>null</code> not permitted).
*/
public void addSeries(XYSeriesP series) {
if (series == null) {
throw new IllegalArgumentException("Null 'series' argument.");
}
this.data.add(series);
series.addChangeListener(this);
fireDatasetChanged();
}
/**
* Removes a series from the collection and sends a
* {@link DatasetChangeEvent} to all registered listeners.
*
* @param series the series index (zero-based).
*/
public void removeSeries(int series) {
if ((series < 0) || (series >= getSeriesCount())) {
throw new IllegalArgumentException("Series index out of bounds.");
}
// fetch the series, remove the change listener, then remove the series.
XYSeriesP ts = (XYSeriesP) this.data.get(series);
ts.removeChangeListener(this);
this.data.remove(series);
fireDatasetChanged();
}
/**
* Removes a series from the collection and sends a
* {@link DatasetChangeEvent} to all registered listeners.
*
* @param series the series (<code>null</code> not permitted).
*/
public void removeSeries(XYSeriesP series) {
if (series == null) {
throw new IllegalArgumentException("Null 'series' argument.");
}
if (this.data.contains(series)) {
series.removeChangeListener(this);
this.data.remove(series);
fireDatasetChanged();
}
}
/**
* Removes all the series from the collection and sends a
* {@link DatasetChangeEvent} to all registered listeners.
*/
public void removeAllSeries() {
// Unregister the collection as a change listener to each series in
// the collection.
for (int i = 0; i < this.data.size(); i++) {
XYSeriesP series = (XYSeriesP) this.data.get(i);
series.removeChangeListener(this);
}
// Remove all the series from the collection and notify listeners.
this.data.clear();
fireDatasetChanged();
}
/**
* Returns the number of series in the collection.
*
* @return The series count.
*/
public int getSeriesCount() {
return this.data.size();
}
/**
* Returns a list of all the series in the collection.
*
* @return The list (which is unmodifiable).
*/
public List<XYSeriesP> getSeries() {
return Collections.unmodifiableList(this.data);
}
/**
* Returns the index of the specified series, or -1 if that series is not
* present in the dataset.
*
* @param series the series (<code>null</code> not permitted).
*
* @return The series index.
*
* @since 1.0.6
*/
public int indexOf(XYSeriesP series) {
if (series == null) {
throw new IllegalArgumentException("Null 'series' argument.");
}
return this.data.indexOf(series);
}
/**
* Returns a series from the collection.
*
* @param series the series index (zero-based).
*
* @return The series.
*
* @throws IllegalArgumentException if <code>series</code> is not in the
* range <code>0</code> to <code>getSeriesCount() - 1</code>.
*/
public XYSeriesP getSeries(int series) {
if ((series < 0) || (series >= getSeriesCount())) {
throw new IllegalArgumentException("Series index out of bounds");
}
return (XYSeriesP) this.data.get(series);
}
/**
* Returns a series from the collection.
*
* @param key the key (<code>null</code> not permitted).
*
* @return The series with the specified key.
*
* @throws UnknownKeyException if <code>key</code> is not found in the
* collection.
*
* @since 1.0.9
*/
public XYSeriesP getSeries(Comparable<?> key) {
if (key == null) {
throw new IllegalArgumentException("Null 'key' argument.");
}
for (XYSeriesP series: this.data) {
if (key.equals(series.getKey())) {
return series;
}
}
throw new UnknownKeyException("Key not found: " + key);
}
/**
* Returns the key for a series.
*
* @param series the series index (in the range <code>0</code> to
* <code>getSeriesCount() - 1</code>).
*
* @return The key for a series.
*
* @throws IllegalArgumentException if <code>series</code> is not in the
* specified range.
*/
public Comparable<?> getSeriesKey(int series) {
// defer argument checking
return getSeries(series).getKey();
}
/**
* Returns the number of items in the specified series.
*
* @param series the series (zero-based index).
*
* @return The item count.
*
* @throws IllegalArgumentException if <code>series</code> is not in the
* range <code>0</code> to <code>getSeriesCount() - 1</code>.
*/
public int getItemCount(int series) {
// defer argument checking
return getSeries(series).getItemCount();
}
/**
* Returns the x-value for the specified series and item.
*
* @param series the series (zero-based index).
* @param item the item (zero-based index).
*
* @return The value.
*/
public Number getX(int series, int item) {
XYSeriesP ts = (XYSeriesP) this.data.get(series);
XYDataItem xyItem = ts.getDataItem(item);
return xyItem.getX();
}
/**
* Returns the starting X value for the specified series and item.
*
* @param series the series (zero-based index).
* @param item the item (zero-based index).
*
* @return The starting X value.
*/
public Number getStartX(int series, int item) {
return this.intervalDelegate.getStartX(series, item);
}
/**
* Returns the ending X value for the specified series and item.
*
* @param series the series (zero-based index).
* @param item the item (zero-based index).
*
* @return The ending X value.
*/
public Number getEndX(int series, int item) {
return this.intervalDelegate.getEndX(series, item);
}
/**
* Returns the y-value for the specified series and item.
*
* @param series the series (zero-based index).
* @param index the index of the item of interest (zero-based).
*
* @return The value (possibly <code>null</code>).
*/
public Number getY(int series, int index) {
XYSeriesP ts = (XYSeriesP) this.data.get(series);
XYDataItem xyItem = ts.getDataItem(index);
return xyItem.getY();
}
/**
* Returns the starting Y value for the specified series and item.
*
* @param series the series (zero-based index).
* @param item the item (zero-based index).
*
* @return The starting Y value.
*/
public Number getStartY(int series, int item) {
return getY(series, item);
}
/**
* Returns the ending Y value for the specified series and item.
*
* @param series the series (zero-based index).
* @param item the item (zero-based index).
*
* @return The ending Y value.
*/
public Number getEndY(int series, int item) {
return getY(series, item);
}
/**
* Returns the minimum x-value in the dataset.
*
* @param includeInterval a flag that determines whether or not the
* x-interval is taken into account.
*
* @return The minimum value.
*/
public double getDomainLowerBound(boolean includeInterval) {
if (includeInterval) {
return this.intervalDelegate.getDomainLowerBound(includeInterval);
}
else {
double result = Double.NaN;
int seriesCount = getSeriesCount();
for (int s = 0; s < seriesCount; s++) {
XYSeriesP series = getSeries(s);
double lowX = series.getMinX();
if (Double.isNaN(result)) {
result = lowX;
}
else {
if (!Double.isNaN(lowX)) {
result = Math.min(result, lowX);
}
}
}
return result;
}
}
/**
* Returns the maximum x-value in the dataset.
*
* @param includeInterval a flag that determines whether or not the
* x-interval is taken into account.
*
* @return The maximum value.
*/
public double getDomainUpperBound(boolean includeInterval) {
if (includeInterval) {
return this.intervalDelegate.getDomainUpperBound(includeInterval);
}
else {
double result = Double.NaN;
int seriesCount = getSeriesCount();
for (int s = 0; s < seriesCount; s++) {
XYSeriesP series = getSeries(s);
double hiX = series.getMaxX();
if (Double.isNaN(result)) {
result = hiX;
}
else {
if (!Double.isNaN(hiX)) {
result = Math.max(result, hiX);
}
}
}
return result;
}
}
/**
* Returns the range of the values in this dataset's domain.
*
* @param includeInterval a flag that determines whether or not the
* x-interval is taken into account.
*
* @return The range (or <code>null</code> if the dataset contains no
* values).
*/
public Range getDomainBounds(boolean includeInterval) {
if (includeInterval) {
return this.intervalDelegate.getDomainBounds(includeInterval);
}
else {
double lower = Double.POSITIVE_INFINITY;
double upper = Double.NEGATIVE_INFINITY;
int seriesCount = getSeriesCount();
for (int s = 0; s < seriesCount; s++) {
XYSeriesP series = getSeries(s);
double minX = series.getMinX();
if (!Double.isNaN(minX)) {
lower = Math.min(lower, minX);
}
double maxX = series.getMaxX();
if (!Double.isNaN(maxX)) {
upper = Math.max(upper, maxX);
}
}
if (lower > upper) {
return null;
}
else {
return new Range(lower, upper);
}
}
}
/**
* Returns the interval width. This is used to calculate the start and end
* x-values, if/when the dataset is used as an {@link IntervalXYDataset}.
*
* @return The interval width.
*/
public double getIntervalWidth() {
return this.intervalDelegate.getIntervalWidth();
}
/**
* Sets the interval width and sends a {@link DatasetChangeEvent} to all
* registered listeners.
*
* @param width the width (negative values not permitted).
*/
public void setIntervalWidth(double width) {
if (width < 0.0) {
throw new IllegalArgumentException("Negative 'width' argument.");
}
this.intervalDelegate.setFixedIntervalWidth(width);
fireDatasetChanged();
}
/**
* Returns the interval position factor.
*
* @return The interval position factor.
*/
public double getIntervalPositionFactor() {
return this.intervalDelegate.getIntervalPositionFactor();
}
/**
* Sets the interval position factor. This controls where the x-value is in
* relation to the interval surrounding the x-value (0.0 means the x-value
* will be positioned at the start, 0.5 in the middle, and 1.0 at the end).
*
* @param factor the factor.
*/
public void setIntervalPositionFactor(double factor) {
this.intervalDelegate.setIntervalPositionFactor(factor);
fireDatasetChanged();
}
/**
* Returns whether the interval width is automatically calculated or not.
*
* @return Whether the width is automatically calculated or not.
*/
public boolean isAutoWidth() {
return this.intervalDelegate.isAutoWidth();
}
/**
* Sets the flag that indicates wether the interval width is automatically
* calculated or not.
*
* @param b a boolean.
*/
public void setAutoWidth(boolean b) {
this.intervalDelegate.setAutoWidth(b);
fireDatasetChanged();
}
/**
* Returns the range of the values in this dataset's range.
*
* @param includeInterval ignored.
*
* @return The range (or <code>null</code> if the dataset contains no
* values).
*/
public Range getRangeBounds(boolean includeInterval) {
double lower = Double.POSITIVE_INFINITY;
double upper = Double.NEGATIVE_INFINITY;
int seriesCount = getSeriesCount();
for (int s = 0; s < seriesCount; s++) {
XYSeriesP series = getSeries(s);
double minY = series.getMinY();
if (!Double.isNaN(minY)) {
lower = Math.min(lower, minY);
}
double maxY = series.getMaxY();
if (!Double.isNaN(maxY)) {
upper = Math.max(upper, maxY);
}
}
if (lower > upper) {
return null;
}
else {
return new Range(lower, upper);
}
}
/**
* Returns the minimum y-value in the dataset.
*
* @param includeInterval a flag that determines whether or not the
* y-interval is taken into account.
*
* @return The minimum value.
*/
public double getRangeLowerBound(boolean includeInterval) {
double result = Double.NaN;
int seriesCount = getSeriesCount();
for (int s = 0; s < seriesCount; s++) {
XYSeriesP series = getSeries(s);
double lowY = series.getMinY();
if (Double.isNaN(result)) {
result = lowY;
}
else {
if (!Double.isNaN(lowY)) {
result = Math.min(result, lowY);
}
}
}
return result;
}
/**
* Returns the maximum y-value in the dataset.
*
* @param includeInterval a flag that determines whether or not the
* y-interval is taken into account.
*
* @return The maximum value.
*/
public double getRangeUpperBound(boolean includeInterval) {
double result = Double.NaN;
int seriesCount = getSeriesCount();
for (int s = 0; s < seriesCount; s++) {
XYSeriesP series = getSeries(s);
double hiY = series.getMaxY();
if (Double.isNaN(result)) {
result = hiY;
}
else {
if (!Double.isNaN(hiY)) {
result = Math.max(result, hiY);
}
}
}
return result;
}
}
@@ -1,454 +0,0 @@
package ch.psi.plot.xy;
/* ===========================================================
* JFreeChart : a free chart library for the Java(tm) platform
* ===========================================================
*
* (C) Copyright 2000-2009, by Object Refinery Limited and Contributors.
*
* Project Info: http://www.jfree.org/jfreechart/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* -------------
* XYSeries.java
* -------------
* (C) Copyright 2001-2009, Object Refinery Limited and Contributors.
*
* Original Author: David Gilbert (for Object Refinery Limited);
* Contributor(s): Aaron Metzger;
* Jonathan Gabbai;
* Richard Atkinson;
* Michel Santos;
* Ted Schwartz (fix for bug 1955483);
*
* Changes
* -------
* 15-Nov-2001 : Version 1 (DG);
* 03-Apr-2002 : Added an add(double, double) method (DG);
* 29-Apr-2002 : Added a clear() method (ARM);
* 06-Jun-2002 : Updated Javadoc comments (DG);
* 29-Aug-2002 : Modified to give user control over whether or not duplicate
* x-values are allowed (DG);
* 07-Oct-2002 : Fixed errors reported by Checkstyle (DG);
* 11-Nov-2002 : Added maximum item count, code contributed by Jonathan
* Gabbai (DG);
* 26-Mar-2003 : Implemented Serializable (DG);
* 04-Aug-2003 : Added getItems() method (DG);
* 15-Aug-2003 : Changed 'data' from private to protected, added new add()
* methods with a 'notify' argument (DG);
* 22-Sep-2003 : Added getAllowDuplicateXValues() method (RA);
* 29-Jan-2004 : Added autoSort attribute, based on a contribution by
* Michel Santos - see patch 886740 (DG);
* 03-Feb-2004 : Added indexOf() method (DG);
* 16-Feb-2004 : Added remove() method (DG);
* 18-Aug-2004 : Moved from org.jfree.data --> org.jfree.data.xy (DG);
* 21-Feb-2005 : Added update(Number, Number) and addOrUpdate(Number, Number)
* methods (DG);
* 03-May-2005 : Added a new constructor, fixed the setMaximumItemCount()
* method to remove items (and notify listeners) if necessary,
* fixed the add() and addOrUpdate() methods to handle unsorted
* series (DG);
* ------------- JFreeChart 1.0.x ---------------------------------------------
* 11-Jan-2005 : Renamed update(int, Number) --> updateByIndex() (DG);
* 15-Jan-2007 : Added toArray() method (DG);
* 31-Oct-2007 : Implemented faster hashCode() (DG);
* 22-Nov-2007 : Reimplemented clone() (DG);
* 01-May-2008 : Fixed bug 1955483 in addOrUpdate() method, thanks to
* Ted Schwartz (DG);
* 24-Nov-2008 : Further fix for 1955483 (DG);
* 06-Mar-2009 : Added minX, maxX, minY and maxY fields (DG);
*
*/
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.jfree.data.general.Series;
import org.jfree.data.general.SeriesChangeEvent;
import org.jfree.data.general.SeriesException;
import org.jfree.data.xy.XYDataItem;
/**
* Represents a sequence of zero or more data items in the form (x, y). By
* default, items in the series will be sorted into ascending order by x-value,
* and duplicate x-values are permitted. Both the sorting and duplicate
* defaults can be changed in the constructor. Y-values can be
* <code>null</code> to represent missing values.
*/
public class XYSeriesP extends Series implements Cloneable, Serializable {
/** For serialization. */
static final long serialVersionUID = -5908509288197150436L;
// In version 0.9.12, in response to several developer requests, I changed
// the 'data' attribute from 'private' to 'protected', so that others can
// make subclasses that work directly with the underlying data structure.
/** Storage for the data items in the series. */
protected List<XYDataItem> data;
/** The maximum number of items for the series. */
private int maximumItemCount = Integer.MAX_VALUE;
/**
* A flag that controls whether the items are automatically sorted
* (by x-value ascending).
*/
/** The lowest x-value in the series, excluding Double.NaN values. */
private double minX;
/** The highest x-value in the series, excluding Double.NaN values. */
private double maxX;
/** The lowest y-value in the series, excluding Double.NaN values. */
private double minY;
/** The highest y-value in the series, excluding Double.NaN values. */
private double maxY;
/**
* Creates a new empty series. By default, items added to the series will
* be sorted into ascending order by x-value, and duplicate x-values will
* be allowed (these defaults can be modified with another constructor.
*
* @param key the series key (<code>null</code> not permitted).
*/
public XYSeriesP(Comparable<?> key) {
this(key, true, true);
}
/**
* Constructs a new empty series, with the auto-sort flag set as requested,
* and duplicate values allowed.
*
* @param key the series key (<code>null</code> not permitted).
* @param autoSort a flag that controls whether or not the items in the
* series are sorted.
*/
public XYSeriesP(Comparable<?> key, boolean autoSort) {
this(key, autoSort, true);
}
/**
* Constructs a new xy-series that contains no data. You can specify
* whether or not duplicate x-values are allowed for the series.
*
* @param key the series key (<code>null</code> not permitted).
* @param autoSort a flag that controls whether or not the items in the
* series are sorted.
* @param allowDuplicateXValues a flag that controls whether duplicate
* x-values are allowed.
*/
public XYSeriesP(Comparable<?> key, boolean autoSort,
boolean allowDuplicateXValues) {
super(key);
this.data = new ArrayList<XYDataItem>(1000); // allocate memory already for 1000 items
this.minX = Double.NaN;
this.maxX = Double.NaN;
this.minY = Double.NaN;
this.maxY = Double.NaN;
}
/**
* Returns the smallest x-value in the series, ignoring any Double.NaN
* values. This method returns Double.NaN if there is no smallest x-value
* (for example, when the series is empty).
*
* @return The smallest x-value.
*
* @see #getMaxX()
*
* @since 1.0.13
*/
public double getMinX() {
return this.minX;
}
/**
* Returns the largest x-value in the series, ignoring any Double.NaN
* values. This method returns Double.NaN if there is no largest x-value
* (for example, when the series is empty).
*
* @return The largest x-value.
*
* @see #getMinX()
*
* @since 1.0.13
*/
public double getMaxX() {
return this.maxX;
}
/**
* Returns the smallest y-value in the series, ignoring any null and
* Double.NaN values. This method returns Double.NaN if there is no
* smallest y-value (for example, when the series is empty).
*
* @return The smallest y-value.
*
* @see #getMaxY()
*
* @since 1.0.13
*/
public double getMinY() {
return this.minY;
}
/**
* Returns the largest y-value in the series, ignoring any Double.NaN
* values. This method returns Double.NaN if there is no largest y-value
* (for example, when the series is empty).
*
* @return The largest y-value.
*
* @see #getMinY()
*
* @since 1.0.13
*/
public double getMaxY() {
return this.maxY;
}
/**
* Updates the cached values for the minimum and maximum data values.
*
* @param item the item added (<code>null</code> not permitted).
*
* @since 1.0.13
*/
private void updateBoundsForAddedItem(XYDataItem item) {
double x = item.getXValue();
this.minX = minIgnoreNaN(this.minX, x);
this.maxX = maxIgnoreNaN(this.maxX, x);
if (item.getY() != null) {
double y = item.getYValue();
this.minY = minIgnoreNaN(this.minY, y);
this.maxY = maxIgnoreNaN(this.maxY, y);
}
}
/**
* Finds the bounds of the x and y values for the series, by iterating
* through all the data items.
*
* @since 1.0.13
*/
private void findBoundsByIteration() {
this.minX = Double.NaN;
this.maxX = Double.NaN;
this.minY = Double.NaN;
this.maxY = Double.NaN;
for(XYDataItem item: data){
updateBoundsForAddedItem(item);
}
}
/**
* Returns the number of items in the series.
*
* @return The item count.
*
* @see #getItems()
*/
public int getItemCount() {
return this.data.size();
}
/**
* Returns the list of data items for the series (the list contains
* {@link XYDataItem} objects and is unmodifiable).
*
* @return The list of data items.
*/
public List<XYDataItem> getItems() {
return Collections.unmodifiableList(this.data);
}
/**
* Returns the maximum number of items that will be retained in the series.
* The default value is <code>Integer.MAX_VALUE</code>.
*
* @return The maximum item count.
*
* @see #setMaximumItemCount(int)
*/
public int getMaximumItemCount() {
return this.maximumItemCount;
}
/**
* Sets the maximum number of items that will be retained in the series.
* If you add a new item to the series such that the number of items will
* exceed the maximum item count, then the first element in the series is
* automatically removed, ensuring that the maximum item count is not
* exceeded.
* <p>
* Typically this value is set before the series is populated with data,
* but if it is applied later, it may cause some items to be removed from
* the series (in which case a {@link SeriesChangeEvent} will be sent to
* all registered listeners).
*
* @param maximum the maximum number of items for the series.
*/
public void setMaximumItemCount(int maximum) {
this.maximumItemCount = maximum;
int remove = this.data.size() - maximum;
if (remove > 0) {
this.data.subList(0, remove).clear();
findBoundsByIteration();
fireSeriesChanged();
}
}
/**
* Adds a new data item to the series (in the correct position if the
* <code>autoSort</code> flag is set for the series) and sends a
* {@link SeriesChangeEvent} to all registered listeners.
* <P>
* Throws an exception if the x-value is a duplicate AND the
* allowDuplicateXValues flag is false.
*
* @param x the x-value (<code>null</code> not permitted).
* @param y the y-value (<code>null</code> permitted).
*
* @throws SeriesException if the x-value is a duplicate and the
* <code>allowDuplicateXValues</code> flag is not set for this series.
*/
public void add(Number x, Number y) {
// argument checking delegated...
add(new XYDataItem(x, y), true);
}
/**
* Adds new data to the series and, if requested, sends a
* {@link SeriesChangeEvent} to all registered listeners.
* <P>
* Throws an exception if the x-value is a duplicate AND the
* allowDuplicateXValues flag is false.
*
* @param x the x-value (<code>null</code> not permitted).
* @param y the y-value (<code>null</code> permitted).
* @param notify a flag the controls whether or not a
* {@link SeriesChangeEvent} is sent to all registered
* listeners.
*/
public void add(Number x, Number y, boolean notify) {
// delegate argument checking to XYDataItem...
XYDataItem item = new XYDataItem(x, y);
add(item, notify);
}
/**
* Adds a data item to the series and, if requested, sends a
* {@link SeriesChangeEvent} to all registered listeners.
*
* @param item the (x, y) item (<code>null</code> not permitted).
* @param notify a flag that controls whether or not a
* {@link SeriesChangeEvent} is sent to all registered
* listeners.
*/
public void add(XYDataItem item, boolean notify) {
if (item == null) {
throw new IllegalArgumentException("Null 'item' argument.");
}
this.data.add(item);
if (notify) {
fireSeriesChanged();
}
}
/**
* Removes all data items from the series and sends a
* {@link SeriesChangeEvent} to all registered listeners.
*/
public void clear() {
if (this.data.size() > 0) {
this.data.clear();
this.minX = Double.NaN;
this.maxX = Double.NaN;
this.minY = Double.NaN;
this.maxY = Double.NaN;
fireSeriesChanged();
}
}
/**
* Return the data item with the specified index.
*
* @param index the index.
*
* @return The data item with the specified index.
*/
public XYDataItem getDataItem(int index) {
return (XYDataItem) this.data.get(index);
}
/**
* A function to find the minimum of two values, but ignoring any
* Double.NaN values.
*
* @param a the first value.
* @param b the second value.
*
* @return The minimum of the two values.
*/
private double minIgnoreNaN(double a, double b) {
if (Double.isNaN(a)) {
return b;
}
else {
if (Double.isNaN(b)) {
return a;
}
else {
return Math.min(a, b);
}
}
}
/**
* A function to find the maximum of two values, but ignoring any
* Double.NaN values.
*
* @param a the first value.
* @param b the second value.
*
* @return The maximum of the two values.
*/
private double maxIgnoreNaN(double a, double b) {
if (Double.isNaN(a)) {
return b;
}
else {
if (Double.isNaN(b)) {
return a;
}
else {
return Math.max(a, b);
}
}
}
}
@@ -1,61 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.plot.xy.tools;
import org.jfree.data.xy.XYDataItem;
import ch.psi.plot.xy.XYSeriesCollectionP;
import ch.psi.plot.xy.XYSeriesP;
/**
* Calculate average of series
*/
public class Average {
/**
* Calculate average of the passed series collection
*
* @param collection
* @return Average value of the collection
*/
public double average(XYSeriesCollectionP collection){
double average = 0.0;
for (XYSeriesP series : collection.getSeries()) {
average = average + average(series);
}
return average/collection.getSeriesCount();
}
/**
* Calculate average value for a series
* @param series
* @return
*/
public double average(XYSeriesP series){
double average = 0.0;
for(XYDataItem item: series.getItems()){
average = average+item.getYValue();
}
return average/series.getItemCount();
}
}
@@ -1,80 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.plot.xy.tools;
import org.jfree.data.xy.XYDataItem;
import ch.psi.plot.xy.XYSeriesCollectionP;
import ch.psi.plot.xy.XYSeriesP;
/**
* Calculate derivative of series
*/
public class Derivative {
/**
* Calculate derivatives for all series in the passed collection
* @param collection
* @return Collection of series holding the derivatives
*/
public XYSeriesCollectionP derivative(XYSeriesCollectionP collection){
XYSeriesCollectionP dcollection = new XYSeriesCollectionP();
for (XYSeriesP series : collection.getSeries()) {
dcollection.addSeries(derivative(series));
}
return dcollection;
}
/**
* Calculate derivative (first and/or second order) of a given function.
* derivative is based upon 3 points.
*
* @param series
* @return
*/
public XYSeriesP derivative(XYSeriesP series){
XYSeriesP derivative = new XYSeriesP(series.getKey() + "'");
for (int i = 1; i < series.getItemCount() - 1; i++) { // do not start at 0 but 1 - stop 1 before end
XYDataItem m = series.getDataItem(i - 1);
XYDataItem p = series.getDataItem(i + 1);
double xi = series.getDataItem(i).getXValue();
double ximinus1 = m.getXValue();
double xiplus1 = p.getXValue();
double yiminus1 = m.getYValue();
double yiplus1 = p.getYValue();
if (xiplus1-ximinus1 != 0.0) {
double di = (yiplus1 - yiminus1) / (xiplus1-ximinus1);
derivative.add(xi, di);
}
else{
derivative.add(xi, Double.NaN);
}
}
return derivative;
}
}
@@ -1,65 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.plot.xy.tools;
import org.jfree.data.xy.XYDataItem;
import ch.psi.plot.xy.XYSeriesCollectionP;
import ch.psi.plot.xy.XYSeriesP;
/**
* Calculate integral of series
*/
public class Integral {
/**
* Calculate integral for all series in passed collection
* @param collection
* @return Collection of series
*/
public XYSeriesCollectionP integral(XYSeriesCollectionP collection){
XYSeriesCollectionP icollection = new XYSeriesCollectionP();
for (XYSeriesP series : collection.getSeries()) {
icollection.addSeries(integral(series));
}
return icollection;
}
/**
* Calculate integral of the function
* @param series
* @return
*/
public XYSeriesP integral(XYSeriesP series) {
XYSeriesP integral = new XYSeriesP("integral-" + series.getKey());
double value = 0.0;
for (int i = 1; i < series.getItemCount(); i++) { // Leave out 1. point
XYDataItem item = series.getDataItem(i);
XYDataItem itemM = series.getDataItem(i - 1);
value += (item.getXValue() - itemM.getXValue()) * (item.getYValue() + itemM.getYValue()) / 2.0;
integral.add(item.getXValue(), value);
}
return integral;
}
}
@@ -1,51 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.plot.xy.tools;
import org.jfree.data.xy.XYDataItem;
import ch.psi.plot.xy.XYSeriesP;
/**
* Find maximum of series
*/
public class Maximum {
/**
* Find maximum in series
* @param series
* @return maximum data point
*/
public XYDataItem maximum(XYSeriesP series){
XYDataItem maximum = null;
for(XYDataItem item: series.getItems()){
if(maximum==null){ // set first item as maximum
maximum = item;
}
else{
if(item.getYValue()>maximum.getYValue()){
maximum = item;
}
}
}
return maximum;
}
}
@@ -1,51 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.plot.xy.tools;
import org.jfree.data.xy.XYDataItem;
import ch.psi.plot.xy.XYSeriesP;
/**
* Find minimum of series
*/
public class Minimum {
/**
* Find minimum in series
* @param series
* @return minimum data point
*/
public XYDataItem minimum(XYSeriesP series){
XYDataItem minimum = null;
for(XYDataItem item: series.getItems()){
if(minimum == null){
minimum = item;
}
else{
if(item.getYValue()<minimum.getYValue()){
minimum = item;
}
}
}
return minimum;
}
}
@@ -1,86 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.plot.xyz;
import java.awt.Color;
/**
* Utility class for applying a color map
*/
public class ColorManager {
/**
* Get color for a given value
* @param v Value to get the color for
* @param vmin Lower end value mapped to the lower end of the color map
* @param vmax Upper end value mapped to the upper end of the color map
* @return Mapped color for the specified value
*/
public static Color getColourForValue(double v, double vmin, double vmax)
{
// Standard algorithm for hot-cold color gradient (copied from
// http://local.wasp.uwa.edu.au/~pbourke/texture_colour/colourramp/)
//Init color to white
double r = 1.0;
double g = 1.0;
double b = 1.0;
double dv;
if (v < vmin)
v = vmin;
if (v > vmax)
v = vmax;
dv = vmax - vmin;
if (v < (vmin + 0.25 * dv)) {
r = 0.0;
g = 4 * (v - vmin) / dv;
} else if (v < (vmin + 0.5 * dv)) {
r = 0.0;
b = 1 + 4 * (vmin + 0.25 * dv - v) / dv;
} else if (v < (vmin + 0.75 * dv)) {
r = 4 * (v - vmin - 0.5 * dv) / dv;
b = 0.0;
} else {
g = 1 + 4 * (vmin + 0.75 * dv - v) / dv;
b = 0.0;
}
return new Color( new Double(255.0*r).intValue(), new Double(255.0*g).intValue(), new Double(255.0*b).intValue());
}
/**
* Get a gray value for a given value
* @param value the value (must be within the range specified by the
* lower and upper bounds for the scale).
*
* @return a gray scale color.
*/
public static Color getGrayForValue(double value, double vmin, double vmax) {
double v = Math.max(value, vmin);
v = Math.min(v, vmax);
int g = (int) ((v - vmin) / (vmax- vmin) * 255.0);
// FIXME: it probably makes sense to allocate an array of 256 Colors
// and lazily populate this array...
return new Color(g, g, g);
}
}
@@ -1,245 +0,0 @@
/**
*
* Copyright 2011 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This code is distributed in the hope that it will be useful, but without any
* warranty; without even the implied warranty of merchantability or fitness for
* a particular purpose. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.plot.xyz;
import java.util.ArrayList;
import java.util.List;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.renderer.xy.XYBlockRenderer;
import org.jfree.data.DomainOrder;
import org.jfree.data.general.DatasetChangeListener;
import org.jfree.data.general.DatasetGroup;
import org.jfree.data.xy.XYZDataset;
import org.jfree.ui.RectangleAnchor;
/**
* Dynamic dataset
*/
public class DynamicXYZDataset implements XYZDataset{
private final double xResolution;
private final double yResolution;
private final NumberAxis xAxis = new NumberAxis();
private double xLowerBound = Double.NaN;
private double xUpperBound = Double.NaN;
private final NumberAxis yAxis = new NumberAxis();
private double yLowerBound = Double.NaN;
private double yUpperBound = Double.NaN;
private double zLowerBound = Double.NaN;
private double zUpperBound = Double.NaN;
private final XYBlockRenderer renderer = new XYBlockRenderer();
private List<DynamicXYZDataset.Vector> items = new ArrayList<DynamicXYZDataset.Vector>();
/**
* Default constructor
*/
public DynamicXYZDataset(){
xResolution = 1.0;
yResolution = 1.0;
xAxis.setRange(xLowerBound, xUpperBound);
yAxis.setRange(yLowerBound, yUpperBound);
renderer.setBlockWidth(xResolution); // If this is not set the default block size is 1
renderer.setBlockHeight(yResolution); // If this is not set the default block size is 1
renderer.setBlockAnchor(RectangleAnchor.CENTER);
renderer.setBaseCreateEntities(false);
}
public void addData(double x, double y, double z){
items.add(new DynamicXYZDataset.Vector(x,y,z));
}
@Override
public int getItemCount(int series) {
return items.size();
}
@Override
public Number getX(int series, int item) {
return items.get(item).getX();
}
@Override
public double getXValue(int series, int item) {
return items.get(item).getX();
}
@Override
public Number getY(int series, int item) {
return items.get(item).getY();
}
@Override
public double getYValue(int series, int item) {
return items.get(item).getY();
}
@Override
public Number getZ(int series, int item) {
return items.get(item).getZ();
}
@Override
public double getZValue(int series, int item) {
return items.get(item).getZ();
}
@Override
public DomainOrder getDomainOrder() {
return DomainOrder.NONE;
}
@Override
public int getSeriesCount() {
// Series not implemented/used - dataset only holds one series
return 1;
}
@SuppressWarnings("rawtypes")
@Override
public Comparable getSeriesKey(int series) {
// Series not implemented/used
return "";
}
@SuppressWarnings("rawtypes")
@Override
public int indexOf(Comparable seriesKey) {
// Series not implemented/used
return 0;
}
@Override
public DatasetGroup getGroup() {
// Not implemented/used
return null;
}
@Override
public void setGroup(DatasetGroup group) {
// Not implemented/used
}
@Override
public void addChangeListener(DatasetChangeListener listener) {
}
@Override
public void removeChangeListener(DatasetChangeListener listener) {
}
// Convenient methods
public double getzLowerBound() {
return zLowerBound;
}
public double getzUpperBound() {
return zUpperBound;
}
public NumberAxis getxAxis() {
return xAxis;
}
public NumberAxis getyAxis() {
return yAxis;
}
public XYBlockRenderer getRenderer() {
return renderer;
}
public double getxLowerBound() {
return xLowerBound;
}
public double getxUpperBound() {
return xUpperBound;
}
public double getyLowerBound() {
return yLowerBound;
}
public double getyUpperBound() {
return yUpperBound;
}
class Vector{
private double x;
private double y;
private double z;
/**
* Default constructor
*/
public Vector(){
}
/**
* @param x2
* @param y2
* @param z2
*/
public Vector(double x, double y, double z) {
// Right now x and xvalue are the same. This might change if we introduce a virtual grid ...
this.x = x;
this.y = y;
this.z = z;
}
/**
* @return the x
*/
public double getX() {
return x;
}
/**
* @param x the x to set
*/
public void setX(double x) {
this.x = x;
}
/**
* @return the y
*/
public double getY() {
return y;
}
/**
* @param y the y to set
*/
public void setY(double y) {
this.y = y;
}
/**
* @return the z
*/
public double getZ() {
return z;
}
/**
* @param z the z to set
*/
public void setZ(double z) {
this.z = z;
}
}
}
@@ -1,374 +0,0 @@
/**
*
* Copyright 2011 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This code is distributed in the hope that it will be useful, but without any
* warranty; without even the implied warranty of merchantability or fitness for
* a particular purpose. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.plot.xyz;
import java.util.ArrayList;
import java.util.List;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.renderer.xy.XYBlockRenderer;
import org.jfree.data.DomainOrder;
import org.jfree.data.general.DatasetChangeListener;
import org.jfree.data.general.DatasetGroup;
import org.jfree.data.xy.XYZDataset;
import org.jfree.ui.RectangleAnchor;
/**
* Dynamic dataset
* @author ebner
*
*/
public class DynamicXYZDatasetList implements XYZDataset{
private final double xResolution;
private final double yResolution;
private final NumberAxis xAxis = new NumberAxis();
private final NumberAxis yAxis = new NumberAxis();
private double zLowerBound = Double.NaN;
private double zUpperBound = Double.NaN;
private final XYBlockRenderer renderer = new XYBlockRenderer();
private final List<DatasetChangeListener> listeners = new ArrayList<DatasetChangeListener>();
private List<Double> xitems = new ArrayList<Double>(100000);
private List<Double> yitems = new ArrayList<Double>(100000);
private List<Double> zitems = new ArrayList<Double>(100000);
/**
* Default constructor
*/
public DynamicXYZDatasetList(){
xResolution = 1.0;
yResolution = 1.0;
xAxis.setRange(0, 100);
yAxis.setRange(0, 100);
renderer.setBlockWidth(xResolution); // If this is not set the default block size is 1
renderer.setBlockHeight(yResolution); // If this is not set the default block size is 1
renderer.setBlockAnchor(RectangleAnchor.CENTER);
}
/**
* Add datapoint
* @param x
* @param y
* @param z
*/
public void addData(Double x, Double y, Double z){
System.out.println(x +" "+ y +" "+ z);
xitems.add(x);
yitems.add(y);
zitems.add(z);
// items.add(new DynamicXYZDatasetList.Vector(x,y,z));
// Update axis
// final double xv = x.doubleValue();
// final double yv = y.doubleValue();
// final double zv = z.doubleValue();
//
// if(Double.isNaN(xLowerBound) && Double.isNaN(xUpperBound)){
// xLowerBound = xv-incX;
// xUpperBound = xv+incX;
// xAxis.setRange(xLowerBound, xUpperBound);
// }
// else{
// if(xv>(xUpperBound+incX)){
// xUpperBound = xv+incX;
// xAxis.setUpperBound(xUpperBound);
// }
// else if(xv<xLowerBound-incX){
// xLowerBound = xv-incX;
// xAxis.setLowerBound(xLowerBound);
// }
// }
//
// if(Double.isNaN(yLowerBound) && Double.isNaN(yUpperBound)){
// yLowerBound = y.doubleValue()-incY;
// yUpperBound = y.doubleValue()+incY;
// yAxis.setRange(yLowerBound, yUpperBound);
// }
// else{
// if(yv>(yUpperBound+incY)){
// yUpperBound = yv+incY;
// yAxis.setUpperBound(yUpperBound);
// }
// else if(yv<yLowerBound-incY){
// yLowerBound = yv-incY;
// yAxis.setLowerBound(yLowerBound);
// }
// }
//
// if(Double.isNaN(zLowerBound) && Double.isNaN(zUpperBound)){
// zLowerBound = zv;
// zUpperBound = zv;
// }
// else{
// if(zv>zUpperBound){
// zUpperBound = zv;
// }
// else if(zv<zLowerBound){
// zLowerBound = zv;
// }
// }
// Inform change listeners
// DatasetChangeEvent event = new DatasetChangeEvent(this, this);
// for(DatasetChangeListener l: listeners){
// l.datasetChanged(event );
// }
}
/* (non-Javadoc)
* @see org.jfree.data.xy.XYDataset#getItemCount(int)
*/
@Override
public int getItemCount(int series) {
return xitems.size();
}
/* (non-Javadoc)
* @see org.jfree.data.xy.XYDataset#getX(int, int)
*/
@Override
public Number getX(int series, int item) {
return xitems.get(item);
}
/* (non-Javadoc)
* @see org.jfree.data.xy.XYDataset#getXValue(int, int)
*/
@Override
public double getXValue(int series, int item) {
return xitems.get(item);
}
/* (non-Javadoc)
* @see org.jfree.data.xy.XYDataset#getY(int, int)
*/
@Override
public Number getY(int series, int item) {
return yitems.get(item);
}
/* (non-Javadoc)
* @see org.jfree.data.xy.XYDataset#getYValue(int, int)
*/
@Override
public double getYValue(int series, int item) {
return yitems.get(item);
}
/* (non-Javadoc)
* @see org.jfree.data.xy.XYZDataset#getZ(int, int)
*/
@Override
public Number getZ(int series, int item) {
return zitems.get(item);
}
/* (non-Javadoc)
* @see org.jfree.data.xy.XYZDataset#getZValue(int, int)
*/
@Override
public double getZValue(int series, int item) {
return zitems.get(item);
}
/* (non-Javadoc)
* @see org.jfree.data.xy.XYDataset#getDomainOrder()
*/
@Override
public DomainOrder getDomainOrder() {
return DomainOrder.NONE;
}
/* (non-Javadoc)
* @see org.jfree.data.general.SeriesDataset#getSeriesCount()
*/
@Override
public int getSeriesCount() {
// Series not implemented/used - dataset only holds one series
return 1;
}
/* (non-Javadoc)
* @see org.jfree.data.general.SeriesDataset#getSeriesKey(int)
*/
@SuppressWarnings("rawtypes")
@Override
public Comparable getSeriesKey(int series) {
// Series not implemented/used
return "";
}
/* (non-Javadoc)
* @see org.jfree.data.general.SeriesDataset#indexOf(java.lang.Comparable)
*/
@SuppressWarnings("rawtypes")
@Override
public int indexOf(Comparable seriesKey) {
// Series not implemented/used
return 0;
}
/* (non-Javadoc)
* @see org.jfree.data.general.Dataset#getGroup()
*/
@Override
public DatasetGroup getGroup() {
// Not implemented/used
return null;
}
/* (non-Javadoc)
* @see org.jfree.data.general.Dataset#setGroup(org.jfree.data.general.DatasetGroup)
*/
@Override
public void setGroup(DatasetGroup group) {
// Not implemented/used
}
// Listener concept implementation
/* (non-Javadoc)
* @see org.jfree.data.general.Dataset#addChangeListener(org.jfree.data.general.DatasetChangeListener)
*/
@Override
public void addChangeListener(DatasetChangeListener listener) {
listeners.add(listener);
}
/* (non-Javadoc)
* @see org.jfree.data.general.Dataset#removeChangeListener(org.jfree.data.general.DatasetChangeListener)
*/
@Override
public void removeChangeListener(DatasetChangeListener listener) {
listeners.remove(listener);
}
// Convenient methods
/**
* @return the zLowerBound
*/
public double getzLowerBound() {
return zLowerBound;
}
/**
* @return the zUpperBound
*/
public double getzUpperBound() {
return zUpperBound;
}
/**
* @return the xAxis
*/
public NumberAxis getxAxis() {
return xAxis;
}
/**
* @return the yAxis
*/
public NumberAxis getyAxis() {
return yAxis;
}
/**
* @return the renderer
*/
public XYBlockRenderer getRenderer() {
return renderer;
}
class Vector{
private Number x;
private Number y;
private Number z;
/**
* Default constructor
*/
public Vector(){
}
/**
* @param x2
* @param y2
* @param z2
*/
public Vector(Number x, Number y, Number z) {
// Right now x and xvalue are the same. This might change if we introduce a virtual grid ...
this.x = x;
this.y = y;
this.z = z;
}
/**
* @return the x
*/
public Number getX() {
return x;
}
/**
* @param x the x to set
*/
public void setX(Number x) {
this.x = x;
}
/**
* @return the y
*/
public Number getY() {
return y;
}
/**
* @param y the y to set
*/
public void setY(Number y) {
this.y = y;
}
/**
* @return the z
*/
public Number getZ() {
return z;
}
/**
* @param z the z to set
*/
public void setZ(Number z) {
this.z = z;
}
}
}
@@ -1,378 +0,0 @@
/**
*
* Copyright 2011 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This code is distributed in the hope that it will be useful, but without any
* warranty; without even the implied warranty of merchantability or fitness for
* a particular purpose. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.plot.xyz;
import java.util.ArrayList;
import java.util.List;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.renderer.xy.XYBlockRenderer;
import org.jfree.data.DomainOrder;
import org.jfree.data.general.DatasetChangeListener;
import org.jfree.data.general.DatasetGroup;
import org.jfree.data.xy.XYZDataset;
import org.jfree.ui.RectangleAnchor;
/**
* Dynamic dataset
*/
public class DynamicXYZDatasetNumber implements XYZDataset{
private final double xResolution;
private final double yResolution;
private final double incX;
private final double incY;
private final NumberAxis xAxis = new NumberAxis();
private double xLowerBound = Double.NaN;
private double xUpperBound = Double.NaN;
private final NumberAxis yAxis = new NumberAxis();
private double yLowerBound = Double.NaN;
private double yUpperBound = Double.NaN;
private double zLowerBound = Double.NaN;
private double zUpperBound = Double.NaN;
private final XYBlockRenderer renderer = new XYBlockRenderer();
private final List<DatasetChangeListener> listeners = new ArrayList<DatasetChangeListener>();
private List<DynamicXYZDatasetNumber.Vector> items = new ArrayList<DynamicXYZDatasetNumber.Vector>();
/**
* Default constructor
*/
public DynamicXYZDatasetNumber(){
xResolution = 1.0;
yResolution = 1.0;
incX = xResolution/2;
incY = yResolution/2;
xAxis.setRange(xLowerBound, xUpperBound);
yAxis.setRange(yLowerBound, yUpperBound);
renderer.setBlockWidth(xResolution); // If this is not set the default block size is 1
renderer.setBlockHeight(yResolution); // If this is not set the default block size is 1
renderer.setBlockAnchor(RectangleAnchor.CENTER);
renderer.setBaseCreateEntities(false);
}
/**
* Add datapoint
* @param x
* @param y
* @param z
*/
public void addData(Number x, Number y, Number z){
items.add(new DynamicXYZDatasetNumber.Vector(x,y,z));
// Update axis
final double xv = x.doubleValue();
final double yv = y.doubleValue();
final double zv = z.doubleValue();
if(Double.isNaN(xLowerBound) && Double.isNaN(xUpperBound)){
xLowerBound = xv-incX;
xUpperBound = xv+incX;
xAxis.setRange(xLowerBound, xUpperBound);
}
else{
if(xv>(xUpperBound+incX)){
xUpperBound = xv+incX;
xAxis.setUpperBound(xUpperBound);
}
else if(xv<xLowerBound-incX){
xLowerBound = xv-incX;
xAxis.setLowerBound(xLowerBound);
}
}
if(Double.isNaN(yLowerBound) && Double.isNaN(yUpperBound)){
yLowerBound = y.doubleValue()-incY;
yUpperBound = y.doubleValue()+incY;
yAxis.setRange(yLowerBound, yUpperBound);
}
else{
if(yv>(yUpperBound+incY)){
yUpperBound = yv+incY;
yAxis.setUpperBound(yUpperBound);
}
else if(yv<yLowerBound-incY){
yLowerBound = yv-incY;
yAxis.setLowerBound(yLowerBound);
}
}
if(Double.isNaN(zLowerBound) && Double.isNaN(zUpperBound)){
zLowerBound = zv;
zUpperBound = zv;
}
else{
if(zv>zUpperBound){
zUpperBound = zv;
}
else if(zv<zLowerBound){
zLowerBound = zv;
}
}
// Inform change listeners
// DatasetChangeEvent event = new DatasetChangeEvent(this, this);
// for(DatasetChangeListener l: listeners){
// l.datasetChanged(event );
// }
}
/* (non-Javadoc)
* @see org.jfree.data.xy.XYDataset#getItemCount(int)
*/
@Override
public int getItemCount(int series) {
return items.size();
}
/* (non-Javadoc)
* @see org.jfree.data.xy.XYDataset#getX(int, int)
*/
@Override
public Number getX(int series, int item) {
return items.get(item).getX();
}
/* (non-Javadoc)
* @see org.jfree.data.xy.XYDataset#getXValue(int, int)
*/
@Override
public double getXValue(int series, int item) {
return items.get(item).getX().doubleValue();
}
/* (non-Javadoc)
* @see org.jfree.data.xy.XYDataset#getY(int, int)
*/
@Override
public Number getY(int series, int item) {
return items.get(item).getY();
}
/* (non-Javadoc)
* @see org.jfree.data.xy.XYDataset#getYValue(int, int)
*/
@Override
public double getYValue(int series, int item) {
return items.get(item).getY().doubleValue();
}
/* (non-Javadoc)
* @see org.jfree.data.xy.XYZDataset#getZ(int, int)
*/
@Override
public Number getZ(int series, int item) {
return items.get(item).getZ();
}
/* (non-Javadoc)
* @see org.jfree.data.xy.XYZDataset#getZValue(int, int)
*/
@Override
public double getZValue(int series, int item) {
return items.get(item).getZ().doubleValue();
}
/* (non-Javadoc)
* @see org.jfree.data.xy.XYDataset#getDomainOrder()
*/
@Override
public DomainOrder getDomainOrder() {
return DomainOrder.NONE;
}
/* (non-Javadoc)
* @see org.jfree.data.general.SeriesDataset#getSeriesCount()
*/
@Override
public int getSeriesCount() {
// Series not implemented/used - dataset only holds one series
return 1;
}
/* (non-Javadoc)
* @see org.jfree.data.general.SeriesDataset#getSeriesKey(int)
*/
@SuppressWarnings("rawtypes")
@Override
public Comparable getSeriesKey(int series) {
// Series not implemented/used
return "";
}
/* (non-Javadoc)
* @see org.jfree.data.general.SeriesDataset#indexOf(java.lang.Comparable)
*/
@SuppressWarnings("rawtypes")
@Override
public int indexOf(Comparable seriesKey) {
// Series not implemented/used
return 0;
}
/* (non-Javadoc)
* @see org.jfree.data.general.Dataset#getGroup()
*/
@Override
public DatasetGroup getGroup() {
// Not implemented/used
return null;
}
/* (non-Javadoc)
* @see org.jfree.data.general.Dataset#setGroup(org.jfree.data.general.DatasetGroup)
*/
@Override
public void setGroup(DatasetGroup group) {
// Not implemented/used
}
// Listener concept implementation
/* (non-Javadoc)
* @see org.jfree.data.general.Dataset#addChangeListener(org.jfree.data.general.DatasetChangeListener)
*/
@Override
public void addChangeListener(DatasetChangeListener listener) {
listeners.add(listener);
}
/* (non-Javadoc)
* @see org.jfree.data.general.Dataset#removeChangeListener(org.jfree.data.general.DatasetChangeListener)
*/
@Override
public void removeChangeListener(DatasetChangeListener listener) {
listeners.remove(listener);
}
// Convenient methods
/**
* @return the zLowerBound
*/
public double getzLowerBound() {
return zLowerBound;
}
/**
* @return the zUpperBound
*/
public double getzUpperBound() {
return zUpperBound;
}
/**
* @return the xAxis
*/
public NumberAxis getxAxis() {
return xAxis;
}
/**
* @return the yAxis
*/
public NumberAxis getyAxis() {
return yAxis;
}
/**
* @return the renderer
*/
public XYBlockRenderer getRenderer() {
return renderer;
}
class Vector{
private Number x;
private Number y;
private Number z;
/**
* Default constructor
*/
public Vector(){
}
/**
* @param x2
* @param y2
* @param z2
*/
public Vector(Number x, Number y, Number z) {
// Right now x and xvalue are the same. This might change if we introduce a virtual grid ...
this.x = x;
this.y = y;
this.z = z;
}
/**
* @return the x
*/
public Number getX() {
return x;
}
/**
* @param x the x to set
*/
public void setX(Number x) {
this.x = x;
}
/**
* @return the y
*/
public Number getY() {
return y;
}
/**
* @param y the y to set
*/
public void setY(Number y) {
this.y = y;
}
/**
* @return the z
*/
public Number getZ() {
return z;
}
/**
* @param z the z to set
*/
public void setZ(Number z) {
this.z = z;
}
}
}
@@ -1,185 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.plot.xyz;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JTextField;
import javax.swing.JLabel;
import java.awt.Font;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
/**
* @author ebner
*
*/
public class ManualScaleDialog extends JDialog {
// Default serial id
private static final long serialVersionUID = 1L;
private final JPanel contentPanel = new JPanel();
private JTextField textFieldHighValue;
private JTextField textFieldLowValue;
private MatrixPlot plot;
private int selectedOption;
/**
* Launch the application.
*/
public static void main(String[] args) {
try {
ManualScaleDialog dialog = new ManualScaleDialog();
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
System.out.println("HERE");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Create the dialog.
*/
public ManualScaleDialog() {
setModal(true); // Block until dialog is disposed.
setBounds(100, 100, 450, 300);
getContentPane().setLayout(new BorderLayout());
contentPanel.setLayout(new FlowLayout());
contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
getContentPane().add(contentPanel, BorderLayout.CENTER);
{
JLabel lblLowValue = new JLabel("Low Value:");
lblLowValue.setFont(new Font("Lucida Grande", Font.BOLD, 13));
contentPanel.add(lblLowValue);
}
{
textFieldLowValue = new JTextField();
contentPanel.add(textFieldLowValue);
textFieldLowValue.setColumns(10);
}
{
JLabel lblHighValue = new JLabel("High Value:");
lblHighValue.setFont(new Font("Lucida Grande", Font.BOLD, 13));
contentPanel.add(lblHighValue);
}
{
textFieldHighValue = new JTextField();
contentPanel.add(textFieldHighValue);
textFieldHighValue.setColumns(10);
}
{
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
getContentPane().add(buttonPane, BorderLayout.SOUTH);
{
JButton okButton = new JButton("OK");
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
// set OK
selectedOption = JOptionPane.OK_OPTION;
dispose();
}
});
{
JButton btnApply = new JButton("Apply");
btnApply.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
// TODO apply values
if(plot!=null){
plot.setColorScale(getLow(), getHigh());
}
}
});
buttonPane.add(btnApply);
}
okButton.setActionCommand("OK");
buttonPane.add(okButton);
getRootPane().setDefaultButton(okButton);
}
{
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
// set Cancel
selectedOption = JOptionPane.CANCEL_OPTION;
dispose();
}
});
cancelButton.setActionCommand("Cancel");
buttonPane.add(cancelButton);
}
}
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
pack();
}
public void showDialog(){
setVisible(true);
}
public void setMatrixPlot(MatrixPlot p){
plot = p;
}
public void setLow(double low){
textFieldLowValue.setText(String.format("%.4f", low));
}
public void setHigh(double high){
textFieldHighValue.setText(String.format("%.4f", high));
}
public double getLow(){
double low = Double.NaN;
try{
low = Double.parseDouble(textFieldLowValue.getText());
}
catch(NumberFormatException e){
}
return low;
}
public double getHigh(){
double high = Double.NaN;
try{
high = Double.parseDouble(textFieldHighValue.getText());
}
catch(NumberFormatException e){
}
return high;
}
/**
* @return the selectedOption
*/
public int getSelectedOption() {
return selectedOption;
}
}
@@ -1,379 +0,0 @@
package ch.psi.plot.xyz;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.WindowConstants;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.event.AxisChangeEvent;
import org.jfree.chart.event.AxisChangeListener;
import org.jfree.chart.labels.StandardXYZToolTipGenerator;
import org.jfree.chart.labels.XYZToolTipGenerator;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.LookupPaintScale;
import org.jfree.chart.renderer.PaintScale;
import org.jfree.chart.renderer.xy.XYBlockRenderer;
import org.jfree.chart.title.PaintScaleLegend;
import org.jfree.data.Range;
import org.jfree.ui.RectangleAnchor;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import ch.psi.plot.Plot;
/**
* Returns a matrix plot panel
*/
public class MatrixPlot implements Plot {
private static final int chartPanelWidth = 500;
private static final int chartPanelHeight = 270;
private String title;
private String xAxisLabel = "X";
private String yAxisLabel = "Y";
private boolean grayScale = false;
private MatrixPlotData data;
private JFreeChart chart;
private ChartPanel chartPanel;
/**
* Constructor
* @param title
* @param data
*/
public MatrixPlot(String title, final MatrixPlotData data) {
this.title = title;
this.data = data;
}
// Action Classes that implement methods called after keyboard input
/**
* Adapt the context menu of the chart panel
*/
private void adaptContextMenu(final ChartPanel chartPanel){
// Show hide tooltips
final String tooltipsMenuLabel = "Tooltips";
final String hideTooltipsMenuLabel = "Hide Tooltips";
JMenuItem contextMenuItemToolTip = new JMenuItem(tooltipsMenuLabel);
contextMenuItemToolTip.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem source = (JMenuItem)(e.getSource());
if (source.getText() == tooltipsMenuLabel){
showTooltip();
source.setText(hideTooltipsMenuLabel);
}
else if (source.getText() == hideTooltipsMenuLabel){
hideTooltip();
source.setText(tooltipsMenuLabel);
}
}
});
chartPanel.getPopupMenu().add(contextMenuItemToolTip);
// Update colormap
JMenuItem contextMenuItemAdaptScale = new JMenuItem("Update Scale");
contextMenuItemAdaptScale.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
adaptColorMapScale();
}
});
// Set gray scale colormap
JMenuItem contextMenuItemGrayScale = new JMenuItem("Gray Scale");
contextMenuItemGrayScale.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
grayScale = true;
adaptColorMapScale();
}
});
// Set color colormap
JMenuItem contextMenuItemTemperatureColor = new JMenuItem("Color Scale");
contextMenuItemTemperatureColor.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
grayScale = false;
adaptColorMapScale();
}
});
// Set color colormap
JMenuItem menuItemScale = new JMenuItem("Manual Scale");
menuItemScale.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ManualScaleDialog d = new ManualScaleDialog();
d.setLocationRelativeTo(chartPanel);
d.setLow(((PaintScaleLegend) chart.getSubtitles().get(0)).getScale().getLowerBound());
d.setHigh(((PaintScaleLegend) chart.getSubtitles().get(0)).getScale().getUpperBound());
d.setMatrixPlot(MatrixPlot.this);
d.showDialog();
if(d.getSelectedOption()==JOptionPane.OK_OPTION){
setColorScale(d.getLow(), d.getHigh());
}
}
});
// Group colormap related menu items
JMenuItem contextMenuChooseColorMap = new JMenu("ColorMap");
contextMenuChooseColorMap.add(contextMenuItemAdaptScale);
contextMenuChooseColorMap.add(menuItemScale);
contextMenuChooseColorMap.add(contextMenuItemGrayScale);
contextMenuChooseColorMap.add(contextMenuItemTemperatureColor);
chartPanel.getPopupMenu().add(contextMenuChooseColorMap);
// Add separator
chartPanel.getPopupMenu().addSeparator();
// Detach plot into an own frame
JMenuItem contextMenuItemDetach = new JMenuItem("Detach Plot");
contextMenuItemDetach.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
MatrixPlot p = new MatrixPlot(title, data);
final JFrame frame = new JFrame(title);
frame.getContentPane();
frame.setContentPane(p.getChartPanel());
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); // Close application if frame is closed
// Set color scale
p.adaptColorMapScale();
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
}
});
chartPanel.getPopupMenu().add(contextMenuItemDetach);
}
/**
* Show Tooltips. This is not done per default since it makes the app slow for datasize >= 1M
*/
private void showTooltip(){
//Tooltips are quit expensive
DecimalFormat dm = new DecimalFormat("0.##########");
XYZToolTipGenerator xYZToolTipGenerator = new StandardXYZToolTipGenerator("{0}: ({1} / {2} / {3})", dm, dm, dm);
chart.getXYPlot().getRenderer().setBaseToolTipGenerator(xYZToolTipGenerator);
((XYBlockRenderer)chart.getXYPlot().getRenderer()).setBaseCreateEntities(true);
}
/**
* Clear Tooltips
*/
private void hideTooltip(){
//Tooltips are quit expensive
((XYBlockRenderer)chart.getXYPlot().getRenderer()).setBaseToolTipGenerator(null);
((XYBlockRenderer)chart.getXYPlot().getRenderer()).setBaseCreateEntities(false);
}
/**
* Adapt the lower and upper color map scale to the min and max data values of the currently selected region
* Need to be called AFTER the chart panel is created
*/
public void adaptColorMapScale(){
double[] v = XYZDatasetUtil.minMaxZValue(data.getData());
if(v[0]!=Double.NaN && v[1]!=Double.NaN && v[0]<v[1]){
setColorScale(v[0],v[1]);
}
}
/**
* Set the min and max of color map scale to scaleMin and scaleMax
* @param scaleMin min value of scale
* @param scaleMax max value of scale
*/
public void setColorScale(double scaleMin, double scaleMax){
// Create scale for legend
LookupPaintScale legendScale = new LookupPaintScale(scaleMin, scaleMax, Color.GRAY);
setScaleColors(legendScale, scaleMin, scaleMax);
// Create legend
PaintScaleLegend legend = new PaintScaleLegend(legendScale, new NumberAxis());
legend.setPadding(new RectangleInsets(5, 5, 5, 5));
// Width of the legend (colorbar)
legend.setStripWidth(20);
// Position of the legend
legend.setPosition(RectangleEdge.RIGHT);
// Remove background paint/color
legend.setBackgroundPaint(null);
// Add legend to plot panel
chart.clearSubtitles();
chart.addSubtitle(legend);
//We need a second scale for rendering only, where the 'infinities' are in correct color
LookupPaintScale rendererScale = new LookupPaintScale(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Color.GRAY);
setScaleColors(rendererScale, scaleMin, scaleMax);
// Make the paint scale range from - to + infinity
if (grayScale) {
rendererScale.add(Double.NEGATIVE_INFINITY, ColorManager.getGrayForValue(scaleMin, scaleMin, scaleMax));
rendererScale.add(Double.POSITIVE_INFINITY, ColorManager.getGrayForValue(scaleMax, scaleMin, scaleMax));
} else {
rendererScale.add(Double.NEGATIVE_INFINITY, ColorManager.getColourForValue(scaleMin, scaleMin, scaleMax));
rendererScale.add(Double.POSITIVE_INFINITY, ColorManager.getColourForValue(scaleMax, scaleMin, scaleMax));
}
((XYBlockRenderer) chart.getXYPlot().getRenderer()).setPaintScale(rendererScale);
}
/**
* Set the colors for the colored Paint Scale (either single color or temperature color)
* @param paintScale
* @param scaleMin
* @param scaleMax
*/
private void setScaleColors(PaintScale paintScale, double scaleMin, double scaleMax){
if (grayScale) {
for (int i = 0; i < 256; i++) {
double value = scaleMin + (i / 255.0) * (scaleMax - scaleMin);
((LookupPaintScale) paintScale).add(value, ColorManager.getGrayForValue(value, scaleMin, scaleMax));
}
}
else {
for (int i = 0; i < 256; i++) {
double value = scaleMin + (i / 255.0) * (scaleMax - scaleMin);
((LookupPaintScale) paintScale).add(value, ColorManager.getColourForValue(value, scaleMin, scaleMax));
}
}
}
/**
* Get plot data
* @return
*/
public MatrixPlotData getData() {
return data;
}
/**
* Get the chart panel
* @return
*/
@Override
public ChartPanel getChartPanel() {
if(chartPanel == null){
// Create matrix chart
// Init size of plot area according to min and max set in the datas metadata
// Set axis: (plus half bin size on both sides), since we plot the bins centered.
NumberAxis xAxis = new NumberAxis(xAxisLabel);
xAxis.setLowerBound(data.getAxisMinX());
xAxis.setUpperBound(data.getAxisMaxX());
NumberAxis yAxis = new NumberAxis(yAxisLabel);
yAxis.setLowerBound(data.getAxisMinY());
yAxis.setUpperBound(data.getAxisMaxY());
// Configure block renderer to have the blocks rendered in the correct size
XYBlockRenderer renderer = new XYBlockRenderer();
renderer.setBlockWidth(data.getBinWidthX()); // If this is not set the default block size is 1
renderer.setBlockHeight(data.getBinWidthY()); // If this is not set the default block size is 1
renderer.setBlockAnchor(RectangleAnchor.CENTER);
renderer.setBaseCreateEntities(false);
XYPlot plot = new XYPlot(data.getData(), xAxis, yAxis, renderer);
// Remove background paint/color
plot.setBackgroundPaint(null);
// Set the maximum zoom out to the initial zoom rate This also
// provides a workaround for dynamic plots because there zoom out does not work correctly (zoom out to infinity)
plot.getRangeAxis().addChangeListener(new AxisChangeListener() {
@Override
public void axisChanged(AxisChangeEvent event) {
ValueAxis axis = ((ValueAxis)event.getAxis());
if(axis.getLowerBound() < data.getAxisMinY() || axis.getUpperBound() > data.getAxisMaxY()){
Range range = new Range(data.getAxisMinY(), data.getAxisMaxY());
axis.setRange(range, true, false);
}
}
});
plot.getDomainAxis().addChangeListener(new AxisChangeListener() {
@Override
public void axisChanged(AxisChangeEvent event) {
ValueAxis axis = ((ValueAxis)event.getAxis());
if(axis.getLowerBound() < data.getAxisMinX() || axis.getUpperBound() > data.getAxisMaxX()){
Range range = new Range(data.getAxisMinX(), data.getAxisMaxX());
axis.setRange(range, true, false);
}
}
});
chart = new JFreeChart(title, plot);
//Remove the series label (also called legend)
chart.removeLegend();
//AntiAliasing is used to speed up rendering
// chart.setAntiAlias(false);
// Init PaintScale
setColorScale(0,1);
//Create the Chartpanel where the chart will be plotted
chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(chartPanelWidth, chartPanelHeight));
//All interactive menu items
adaptContextMenu(chartPanel);
}
return chartPanel;
}
/* (non-Javadoc)
* @see ch.psi.plot.Plot#update()
*/
@Override
public void update() {
chart.fireChartChanged();
adaptColorMapScale();
}
/* (non-Javadoc)
* @see ch.psi.plot.Plot#getChart()
*/
@Override
public JFreeChart getChart() {
return chart;
}
}
@@ -1,352 +0,0 @@
package ch.psi.plot.xyz;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.WindowConstants;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.StandardXYZToolTipGenerator;
import org.jfree.chart.labels.XYZToolTipGenerator;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.LookupPaintScale;
import org.jfree.chart.renderer.PaintScale;
import org.jfree.chart.renderer.xy.XYBlockRenderer;
import org.jfree.chart.title.PaintScaleLegend;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import ch.psi.plot.Plot;
/**
* Returns a matrix plot panel
*/
public class MatrixPlot2 implements Plot {
private static final int chartPanelWidth = 500;
private static final int chartPanelHeight = 270;
private String title;
private boolean grayScale = false;
private DynamicXYZDatasetList data;
private JFreeChart chart;
private ChartPanel chartPanel;
/**
* @param title
* @param data
*/
public MatrixPlot2(String title, final DynamicXYZDatasetList data) {
this.title = title;
this.data = data;
}
// Action Classes that implement methods called after keyboard input
/**
* Adapt the context menu of the chart panel
*/
private void adaptContextMenu(final ChartPanel chartPanel){
// Show hide tooltips
final String tooltipsMenuLabel = "Tooltips";
final String hideTooltipsMenuLabel = "Hide Tooltips";
JMenuItem contextMenuItemToolTip = new JMenuItem(tooltipsMenuLabel);
contextMenuItemToolTip.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem source = (JMenuItem)(e.getSource());
if (source.getText() == tooltipsMenuLabel){
showTooltip();
source.setText(hideTooltipsMenuLabel);
}
else if (source.getText() == hideTooltipsMenuLabel){
hideTooltip();
source.setText(tooltipsMenuLabel);
}
}
});
chartPanel.getPopupMenu().add(contextMenuItemToolTip);
// Update colormap
JMenuItem contextMenuItemAdaptScale = new JMenuItem("Update Scale");
contextMenuItemAdaptScale.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
adaptColorMapScale();
}
});
// Set gray scale colormap
JMenuItem contextMenuItemGrayScale = new JMenuItem("Gray Scale");
contextMenuItemGrayScale.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
grayScale = true;
adaptColorMapScale();
}
});
// Set color colormap
JMenuItem contextMenuItemTemperatureColor = new JMenuItem("Color Scale");
contextMenuItemTemperatureColor.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
grayScale = false;
adaptColorMapScale();
}
});
// // Set color colormap
// JMenuItem menuItemScale = new JMenuItem("Manual Scale");
// menuItemScale.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent e) {
// ManualScaleDialog d = new ManualScaleDialog();
// d.setLocationRelativeTo(chartPanel);
// d.setLow(((PaintScaleLegend) chart.getSubtitles().get(0)).getScale().getLowerBound());
// d.setHigh(((PaintScaleLegend) chart.getSubtitles().get(0)).getScale().getUpperBound());
// d.setMatrixPlot(MatrixPlot2.this);
//
// d.showDialog();
// if(d.getSelectedOption()==JOptionPane.OK_OPTION){
// setColorScale(d.getLow(), d.getHigh());
// }
// }
// });
// Group colormap related menu items
JMenuItem contextMenuChooseColorMap = new JMenu("ColorMap");
contextMenuChooseColorMap.add(contextMenuItemAdaptScale);
// contextMenuChooseColorMap.add(menuItemScale);
contextMenuChooseColorMap.add(contextMenuItemGrayScale);
contextMenuChooseColorMap.add(contextMenuItemTemperatureColor);
chartPanel.getPopupMenu().add(contextMenuChooseColorMap);
// Add separator
chartPanel.getPopupMenu().addSeparator();
// Detach plot into an own frame
JMenuItem contextMenuItemDetach = new JMenuItem("Detach Plot");
contextMenuItemDetach.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
MatrixPlot2 p = new MatrixPlot2(title, data);
final JFrame frame = new JFrame(title);
frame.getContentPane();
frame.setContentPane(p.getChartPanel());
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); // Close application if frame is closed
// Set color scale
p.adaptColorMapScale();
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
}
});
chartPanel.getPopupMenu().add(contextMenuItemDetach);
}
/**
* Show Tooltips. This is not done per default since it makes the app slow for datasize >= 1M
*/
private void showTooltip(){
//Tooltips are quit expensive
DecimalFormat dm = new DecimalFormat("0.##########");
XYZToolTipGenerator xYZToolTipGenerator = new StandardXYZToolTipGenerator("{0}: ({1} / {2} / {3})", dm, dm, dm);
chart.getXYPlot().getRenderer().setBaseToolTipGenerator(xYZToolTipGenerator);
((XYBlockRenderer)chart.getXYPlot().getRenderer()).setBaseCreateEntities(true);
}
/**
* Clear Tooltips
*/
private void hideTooltip(){
//Tooltips are quit expensive
((XYBlockRenderer)chart.getXYPlot().getRenderer()).setBaseToolTipGenerator(null);
((XYBlockRenderer)chart.getXYPlot().getRenderer()).setBaseCreateEntities(false);
}
/**
* Adapt the lower and upper color map scale to the min and max data values of the currently selected region
* Need to be called AFTER the chart panel is created
*/
public void adaptColorMapScale(){
if(!Double.isNaN(data.getzLowerBound()) && !Double.isNaN(data.getzUpperBound())){
setColorScale(data.getzLowerBound(),data.getzUpperBound());
}
}
/**
* Set the min and max of color map scale to scaleMin and scaleMax
* @param scaleMin min value of scale
* @param scaleMax max value of scale
*/
public void setColorScale(double scaleMin, double scaleMax){
// Create scale for legend
LookupPaintScale legendScale = new LookupPaintScale(scaleMin, scaleMax, Color.GRAY);
setScaleColors(legendScale, scaleMin, scaleMax);
// Create legend
PaintScaleLegend legend = new PaintScaleLegend(legendScale, new NumberAxis());
legend.setPadding(new RectangleInsets(5, 5, 5, 5));
// Width of the legend (colorbar)
legend.setStripWidth(20);
// Position of the legend
legend.setPosition(RectangleEdge.RIGHT);
// Remove background paint/color
legend.setBackgroundPaint(null);
// Add legend to plot panel
chart.clearSubtitles();
chart.addSubtitle(legend);
//We need a second scale for rendering only, where the 'infinities' are in correct color
LookupPaintScale rendererScale = new LookupPaintScale(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Color.GRAY);
setScaleColors(rendererScale, scaleMin, scaleMax);
// Make the paint scale range from - to + infinity
if (grayScale) {
rendererScale.add(Double.NEGATIVE_INFINITY, ColorManager.getGrayForValue(scaleMin, scaleMin, scaleMax));
rendererScale.add(Double.POSITIVE_INFINITY, ColorManager.getGrayForValue(scaleMax, scaleMin, scaleMax));
} else {
rendererScale.add(Double.NEGATIVE_INFINITY, ColorManager.getColourForValue(scaleMin, scaleMin, scaleMax));
rendererScale.add(Double.POSITIVE_INFINITY, ColorManager.getColourForValue(scaleMax, scaleMin, scaleMax));
}
((XYBlockRenderer) chart.getXYPlot().getRenderer()).setPaintScale(rendererScale);
}
/**
* Set the colors for the colored Paint Scale (either single color or temperature color)
* @param paintScale
* @param scaleMin
* @param scaleMax
*/
private void setScaleColors(PaintScale paintScale, double scaleMin, double scaleMax){
if (grayScale) {
for (int i = 0; i < 256; i++) {
double value = scaleMin + (i / 255.0) * (scaleMax - scaleMin);
((LookupPaintScale) paintScale).add(value, ColorManager.getGrayForValue(value, scaleMin, scaleMax));
}
}
else {
for (int i = 0; i < 256; i++) {
double value = scaleMin + (i / 255.0) * (scaleMax - scaleMin);
((LookupPaintScale) paintScale).add(value, ColorManager.getColourForValue(value, scaleMin, scaleMax));
}
}
}
/**
* Get plot data
* @return
*/
public DynamicXYZDatasetList getData() {
return data;
}
/**
* Get the chart panel
* @return
*/
@Override
public ChartPanel getChartPanel() {
if(chartPanel == null){
XYPlot plot = new XYPlot(data, data.getxAxis(), data.getyAxis(), data.getRenderer());
// Remove background paint/color
plot.setBackgroundPaint(null);
// Set the maximum zoom out to the initial zoom rate This also
// provides a workaround for dynamic plots because there zoom out does not work correctly (zoom out to infinity)
// plot.getRangeAxis().addChangeListener(new AxisChangeListener() {
// @Override
// public void axisChanged(AxisChangeEvent event) {
// ValueAxis axis = ((ValueAxis)event.getAxis());
// if(axis.getLowerBound() < data.getyLowerBound() || axis.getUpperBound() > data.getyUpperBound()){
// Range range = new Range(data.getyLowerBound(), data.getyUpperBound());
// axis.setRange(range, true, false);
// }
// }
// });
// plot.getDomainAxis().addChangeListener(new AxisChangeListener() {
// @Override
// public void axisChanged(AxisChangeEvent event) {
// ValueAxis axis = ((ValueAxis)event.getAxis());
// if(axis.getLowerBound() < data.getxLowerBound() || axis.getUpperBound() > data.getxUpperBound()){
// Range range = new Range(data.getxLowerBound(), data.getxUpperBound());
// axis.setRange(range, true, false);
// }
// }
// });
chart = new JFreeChart(title, plot);
//Remove the series label (also called legend)
chart.removeLegend();
//AntiAliasing is used to speed up rendering
// chart.setAntiAlias(false);
// Init PaintScale
setColorScale(0,1);
//Create the Chartpanel where the chart will be plotted
chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new java.awt.Dimension(chartPanelWidth, chartPanelHeight));
//All interactive menu items
adaptContextMenu(chartPanel);
}
return chartPanel;
}
/* (non-Javadoc)
* @see ch.psi.plot.Plot#update()
*/
@Override
public void update() {
chart.fireChartChanged();
adaptColorMapScale();
}
/* (non-Javadoc)
* @see ch.psi.plot.Plot#getChart()
*/
@Override
public JFreeChart getChart() {
return chart;
}
}
@@ -1,191 +0,0 @@
package ch.psi.plot.xyz;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jfree.data.xy.DefaultXYZDataset;
import org.jfree.data.xy.XYZDataset;
/**
* PlotData implementation optimized for matrix data.
* ...
*/
public class MatrixPlotData {
private static final Logger logger = Logger.getLogger(MatrixPlotData.class.getName());
private final double minX;
private final double maxX;
private final int numberOfBinsX;
private final double binWidthX;
private final double minY;
private final double maxY;
private final int numberOfBinsY;
private final double binWidthY;
private final double axisMinX;
private final double axisMaxX;
private final double axisMinY;
private final double axisMaxY;
double[] xvalues;
double[] yvalues;
double[] zvalues;
private XYZDataset data;
public MatrixPlotData(double minX, double maxX, int nX, double minY, double maxY, int nY){
this.minX = minX;
this.maxX = maxX;
this.numberOfBinsX = nX;
this.minY = minY;
this.maxY = maxY;
this.numberOfBinsY = nY;
this.binWidthX = (maxX - minX)/(double) (numberOfBinsX - 1);
this.binWidthY = (maxY - minY)/(double) (numberOfBinsY - 1);
// The axis min and max values need to be half a bin larger. Otherwise the outer pixels
// will not be plotted correctly (half of the pixel is missing)
this.axisMinX = minX - 0.5*binWidthX;
this.axisMaxX = maxX + 0.5*binWidthX;
this.axisMinY = minY - 0.5*binWidthY;
this.axisMaxY = maxY + 0.5*binWidthY;
int arraylength = numberOfBinsX*numberOfBinsY;
xvalues = new double[arraylength];
yvalues = new double[arraylength];
zvalues = new double[arraylength];
Arrays.fill(xvalues, Double.NEGATIVE_INFINITY);
Arrays.fill(yvalues, Double.NEGATIVE_INFINITY);
Arrays.fill(zvalues, Double.NEGATIVE_INFINITY);
double[][] dataArray = new double[][] {xvalues, yvalues, zvalues};
//Create the XYDataset (org.jfree), not to be confused with the ch.psi dataSet)
data = new DefaultXYZDataset();
((DefaultXYZDataset)data).addSeries("Data" , dataArray);
}
public XYZDataset getData() {
return data;
}
public void addData(final double x, final double y, final double z) {
final int xBin = ((int) ((x - axisMinX)/binWidthX));
final int yBin = ((int) ((y - axisMinY)/binWidthY));
final int index = yBin * numberOfBinsX + xBin;
try{
//x Value is column, y value is row
xvalues[index] = x;
yvalues[index] = y;
zvalues[index] = z;
}
catch(ArrayIndexOutOfBoundsException e){
logger.log(Level.WARNING, "Unable to add data point at index "+index+" [x: "+x+" y: "+y+"]", e);
}
}
public void clear(){
Arrays.fill(xvalues, Double.NEGATIVE_INFINITY);
Arrays.fill(yvalues, Double.NEGATIVE_INFINITY);
Arrays.fill(zvalues, Double.NEGATIVE_INFINITY);
}
/**
* @return the axisMinX
*/
public double getAxisMinX() {
return axisMinX;
}
/**
* @return the axisMinY
*/
public double getAxisMinY() {
return axisMinY;
}
/**
* @return the binWidthX
*/
public double getBinWidthX() {
return binWidthX;
}
/**
* @return the binWidthY
*/
public double getBinWidthY() {
return binWidthY;
}
/**
* @return the minX
*/
public double getMinX() {
return minX;
}
/**
* @return the maxX
*/
public double getMaxX() {
return maxX;
}
/**
* @return the minY
*/
public double getMinY() {
return minY;
}
/**
* @return the maxY
*/
public double getMaxY() {
return maxY;
}
/**
* @return the axisMaxX
*/
public double getAxisMaxX() {
return axisMaxX;
}
/**
* @return the axisMaxY
*/
public double getAxisMaxY() {
return axisMaxY;
}
/**
* @return the numberOfBinsX
*/
public int getNumberOfBinsX() {
return numberOfBinsX;
}
/**
* @return the numberOfBinsY
*/
public int getNumberOfBinsY() {
return numberOfBinsY;
}
}
@@ -1,71 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.plot.xyz;
import org.jfree.data.xy.XYZDataset;
/**
*/
public class XYZDatasetUtil {
/**
* Find the minimum and maximum value of the dataset
* @param dataset Dataset to find the min and max value
* @return Double array with min in element 0 and max in element 1
*/
public static double[] minMaxZValue(XYZDataset dataset){
double min = Double.NaN;
double max = Double.NaN;
if(dataset != null){
int seriesCount = dataset.getSeriesCount();
for(int s=0;s<seriesCount;s++){
int itemCount = dataset.getItemCount(s);
boolean first = true;
for(int i=0;i<itemCount;i++){
double v = dataset.getZValue(s, i);
if(v!=Double.NEGATIVE_INFINITY){
if(first){
min=v;
max=v;
first=false;
}
else{
if(v>max){
max=v;
}
if(v<min){
min=v;
}
}
}
}
}
}
double[] value = new double[2];
value[0]=min;
value[1]=max;
return value;
}
}
@@ -0,0 +1 @@
ch.psi.plot.jfree.LinePlot
@@ -0,0 +1,87 @@
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
import ch.psi.plot.LinePlot;
import ch.psi.plot.LinePlotSeries;
import ch.psi.plot.Plot;
import ch.psi.plot.utils.SwingUtils;
import ch.psi.plot.xy.generator.Sinus;
import ch.psi.plot.xy.generator.XYGenerator;
import javax.swing.JFrame;
/**
* Test for the LinePlot class
*/
public class LinePlotTest {
public static void main(final String[] args) throws InterruptedException {
//for(int i=0;i<10;i++)
{
//LinePlot linePlot = ServiceLoader.load(LinePlot.class).iterator().next();
//LinePlot linePlot = new ch.psi.plot.jlchart.LinePlot();
//LinePlot linePlot = new ch.psi.plot.jfree.LinePlot();
LinePlot linePlot = new ch.psi.plot.javafx.LinePlot() ;
linePlot.setTitle("Title");
//linePlot.setRangeX(0,10000);
//linePlot.setRangeY(0,10);
//linePlot.setData(getDataFromGenerator(1));
addDataFromGenerator(0, 10, 1000, linePlot);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(linePlot.getChartPanel());
frame.pack();
SwingUtils.centerOnScreen(frame);
frame.setVisible(true);
frame.requestFocus();
// Thread.sleep(2000);
//addDataFromGenerator(0, 10, 1000, linePlot);
//linePlot.getAxis(Plot.AxisId.X).setRange(100,500);
//linePlot.getAxis(Plot.AxisId.Y).setRange(0,5);
//Thread.sleep(2000);
//linePlot.getAxis(Plot.AxisId.X).setAutoRange();
//linePlot.getAxis(Plot.AxisId.Y).setAutoRange();
}
Thread.sleep(3600000);
}
private static void addDataFromGenerator(final int sleep, final int series, final int size, final LinePlot plot) {
final String seriesBaseName = "Generator Data";
final XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, size, false);
Thread t = new Thread(new Runnable() {
@Override
public void run() {
long start = System.currentTimeMillis();
for (int t = 0; t < series; t++) {
// Reset generator
generator.reset();
String seriesName = seriesBaseName + " - " + t;
LinePlotSeries series = new LinePlotSeries(seriesName);
plot.addSeries(series);
double[] xy;
while ((xy = generator.getNewPoint()) != null) {
series.appendData(xy[0], xy[1] + t); // Add t to the y value to see the plotted line
// data.getSeries(seriesName).add(xy[0], xy[1]+t,false); // No notification send - Update of GUI will be performed periodically
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
}
}
}
System.out.println("DONE: " + (System.currentTimeMillis() - start));
}
});
t.start();
}
}
@@ -0,0 +1,112 @@
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
import ch.psi.plot.MatrixPlotSeries;
import ch.psi.plot.Plot;
import ch.psi.plot.xyz.generator.Gauss2D;
//import ch.psi.sls.xasec.data.DataSet;
//import ch.psi.sls.xasec.data.DataSetUtils;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
/**
* Test case for MatrixPlot class
*
*/
public class MatrixPlotTest {
final static int sleepTime = 0;
final static double startX = 10;
final static double stepSizeX = 1;
final static int stepsX = 100;
final static double startY = 300;
final static double stepSizeY = 2;
final static int stepsY = 200;
final static MatrixPlotSeries data = new MatrixPlotSeries("", startX, startX + stepsX * stepSizeX, stepsX + 1, startY, startY + stepsY * stepSizeY, stepsY + 1);
final static Gauss2D generator = new Gauss2D(50, 500, 40, 800, 2);
public static void main(final String[] args) throws InterruptedException {
final ch.psi.plot.MatrixPlot plot = new ch.psi.plot.jzy3d.MatrixPlot();
//final ch.psi.plot.MatrixPlot plot=new ch.psi.plot.jfree.MatrixPlot();
//plot.getAxis(Plot.AxisId.Z).setRange(0.0, 4.0);
//final XYZGenerator generator = new XYZGenerator(new Sinus2D(2, 4), startX, stepSizeX, stepsX, startY, stepSizeY, stepsY, false);
//final SphericalWave generator = new SphericalWave(50, 1000, 10, 200, 1);
plot.setTitle("Matrix Plot Test");
//plot.getAxis(Plot.AxisId.Z).setRange(2.0, 3.0);
//plot.addSeries(data);
final JFrame frame = new JFrame("");
frame.setContentPane(plot.getChartPanel());
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
//runnable.run();
}
});
//plot.getAxis(Plot.AxisId.Z).setRange(2.0, 4.0);
//plot.getAxis(Plot.AxisId.X).setRange(40, 60);
//plot.getAxis(Plot.AxisId.Y).setRange(400, 600);
Thread.sleep(1000);
plot.addSeries(data);
Thread t = new Thread(runnable);
t.start();
/*
plot.setUpdatesEnabled(false);
for (int i=0;i<20;i++){
Thread.sleep(1000);
plot.requestUpdate();
}
while(t.isAlive())
Thread.sleep(10);
plot.requestUpdate();
*/
/*
Thread.sleep(2000);
//plot.getAxis(Plot.AxisId.Z).setRange(2.0, 3.0);
plot.getAxis(Plot.AxisId.X).setRange(40, 60);
plot.getAxis(Plot.AxisId.Y).setRange(400, 600);
Thread.sleep(5000);
plot.getAxis(Plot.AxisId.X).setAutoRange();
plot.getAxis(Plot.AxisId.Y).setAutoRange();
//plot.getAxis(Plot.AxisId.Z).setAutoRange();
Thread.sleep(5000);
//plot.removeSeries(data);
plot.clear();
*/
Thread.sleep(360000);
}
static Runnable runnable = new Runnable() {
@Override
public void run() {
long start = System.currentTimeMillis();
double[] xyz;
//while ((xyz = generator.getNewPoint()) != null) {
// data.appendData(xyz[0], xyz[1], xyz[2]);
for (double y = startY; y <= startY + stepsY * stepSizeY; y += stepSizeY) {
for (double x = startX; x <= startX + stepsX * stepSizeX; x += stepSizeX) {
data.appendData(x, y, generator.generate(x, y) + 2);
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
}
}
}
System.out.println("------" + (System.currentTimeMillis() - start));
// }
}
};
}
+47
View File
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
*/
import org.jzy3d.analysis.AbstractAnalysis;
import org.jzy3d.analysis.AnalysisLauncher;
import org.jzy3d.chart.factories.AWTChartComponentFactory;
import org.jzy3d.chart.Settings;
import org.jzy3d.colors.Color;
import org.jzy3d.colors.ColorMapper;
import org.jzy3d.colors.colormaps.ColorMapRainbow;
import org.jzy3d.maths.Range;
import org.jzy3d.plot3d.builder.Builder;
import org.jzy3d.plot3d.builder.Mapper;
import org.jzy3d.plot3d.builder.concrete.OrthonormalGrid;
import org.jzy3d.plot3d.primitives.Shape;
import org.jzy3d.plot3d.rendering.canvas.Quality;
public class TestJZY extends AbstractAnalysis {
public static void main(String[] args) throws Exception {
AnalysisLauncher.open(new TestJZY());
}
@Override
public void init() {
// Define a function to plot
Mapper mapper = new Mapper() {
public double f(double x, double y) {
return x * Math.sin(x * y);
}
};
// Define range and precision for the function to plot
Range range = new Range(-3, 3);
int steps = 100;
// Create the object to represent the function over the given range.
final Shape surface = Builder.buildOrthonormal(new OrthonormalGrid(range, steps, range, steps), mapper);
surface.setColorMapper(new ColorMapper(new ColorMapRainbow(), surface.getBounds().getZmin(), surface.getBounds().getZmax(), new Color(1, 1, 1, .5f)));
surface.setFaceDisplayed(true);
surface.setWireframeDisplayed(false);
// Create a chart
chart = AWTChartComponentFactory.chart(Quality.Advanced, getCanvasType());
chart.getScene().getGraph().add(surface);
}
}
@@ -1,316 +1,323 @@
/**
*
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
*
* This code is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This code is distributed in the hope that it will be useful, but without any
* warranty; without even the implied warranty of merchantability or fitness for
* a particular purpose. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
package ch.psi.plot.xy;
import ch.psi.plot.LinePlot;
import ch.psi.plot.LinePlotSeries;
import ch.psi.plot.utils.SwingUtils;
import ch.psi.plot.xy.generator.Sinus;
import ch.psi.plot.xy.generator.XYGenerator;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import org.jfree.chart.ChartPanel;
import org.jfree.ui.RefineryUtilities;
import javax.swing.JPanel;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import ch.psi.plot.xy.LinePlot;
import ch.psi.plot.xy.generator.Sinus;
import ch.psi.plot.xy.generator.XYGenerator;
/**
* Test for the LinePlot class
* @author ebner
*
*/
public class LinePlotTest {
private final File file = new File("../ch.psi.sls.xasec/testfiles/text/beamCurrent.txt");
private final long timeToClose = 7200000; // 2 hours
@Before
public void setUp() throws Exception {
}
private final File file = new File("../ch.psi.sls.xasec/testfiles/text/beamCurrent.txt");
private final long timeToClose = 7200000; // 2 hours
static LinePlot linePlot;
@After
public void tearDown() throws Exception {
}
/**
* Test LinePlot rendering point by point (getting data from a generator)
* @throws IOException
* @throws InterruptedException
*/
@Test
public void testLinePlotGeneratorPerformance() throws IOException, InterruptedException {
for(int i=0;i<10;i++){
LinePlot linePlot = new LinePlot("Title ", getDataFromGenerator(1)) ;
// linePlot.plot();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(linePlot.getChartPanel());
frame.pack();
RefineryUtilities.centerFrameOnScreen(frame);
frame.setVisible(true);
}
Thread.sleep(timeToClose);
}
/**
* Test LinePlot rendering point by point (getting data from a generator)
* @throws IOException
* @throws InterruptedException
*/
@Test
public void testLinePlotAllDataAvailable() throws IOException, InterruptedException {
for(int i=0;i<1;i++){
XYSeriesCollectionP d = loadDataFromGenerator();
LinePlot linePlot = new LinePlot("Title ", d) ;
ChartPanel chartPanel = linePlot.getChartPanel();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(chartPanel);
frame.pack();
RefineryUtilities.centerFrameOnScreen(frame);
frame.setVisible(true);
frame.setContentPane(chartPanel);
}
Thread.sleep(timeToClose);
}
/**
* Test LinePlot rendering point by point (getting data from a generator)
* @throws IOException
* @throws InterruptedException
*/
@Test
public void testLinePlotGenerator() throws IOException, InterruptedException {
for(int i=0;i<1;i++){
LinePlot linePlot = new LinePlot("Title ", getDataFromGenerator(1)) ;
// linePlot.plot();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(linePlot.getChartPanel());
frame.pack();
RefineryUtilities.centerFrameOnScreen(frame);
frame.setVisible(true);
}
Thread.sleep(timeToClose);
}
@Test
public void testLinePlotGeneratorOne() throws IOException, InterruptedException {
@Before
public void setUp() throws Exception {
linePlot = new ch.psi.plot.jfree.LinePlot();
//linePlot = new ch.psi.plot.jlchart.LinePlot() ;
linePlot.setTitle("Title");
}
XYSeriesCollectionP data = new XYSeriesCollectionP();
XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 1000, false);
@After
public void tearDown() throws Exception {
}
generator.reset();
/**
* Test LinePlot rendering point by point (getting data from a generator)
*
* @throws IOException
* @throws InterruptedException
*/
@Test
public void testLinePlotGeneratorPerformance() throws IOException, InterruptedException {
linePlot.clear();
//for(int i=0;i<10;i++)
{
LinePlotSeries[] series = getDataFromGenerator(0, linePlot);
//linePlot.addSeries(series);
String seriesName = "test";
XYSeriesP serie = new XYSeriesP(seriesName);
data.addSeries(serie);
//addDataFromGenerator(0, 10, 1000, linePlot);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(linePlot.getChartPanel());
frame.pack();
SwingUtils.centerOnScreen(frame);
frame.setVisible(true);
}
double[] xy;
while ((xy = generator.getNewPoint()) != null) {
serie.add(xy[0], xy[1]); // Add t to the y value to see the plotted line
}
Thread.sleep(timeToClose);
}
LinePlot linePlot = new LinePlot("Title ", data);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(linePlot.getChartPanel());
frame.pack();
RefineryUtilities.centerFrameOnScreen(frame);
frame.setVisible(true);
/**
* Test LinePlot rendering point by point (getting data from a generator)
*
* @throws IOException
* @throws InterruptedException
*/
@Test
public void testLinePlotAllDataAvailable() throws IOException, InterruptedException {
linePlot.clear();
for (int i = 0; i < 1; i++) {
LinePlotSeries[] d = loadDataFromGenerator(linePlot);
//linePlot.addSeries(d);
JPanel chartPanel = linePlot.getChartPanel();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(chartPanel);
frame.pack();
SwingUtils.centerOnScreen(frame);
frame.setVisible(true);
frame.setContentPane(chartPanel);
}
Thread.sleep(timeToClose);
}
/**
* Test LinePlot rendering point by point (getting data from a generator)
* @throws IOException
* @throws InterruptedException
*/
@Test
public void testLinePlotGenerator65536() throws IOException, InterruptedException {
LinePlot linePlot = new LinePlot("Title ", loadDataFromGenerator65536(0)) ;
Thread.sleep(timeToClose);
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(linePlot.getChartPanel());
frame.pack();
RefineryUtilities.centerFrameOnScreen(frame);
frame.setVisible(true);
int cnt = 1;
while(true){
Thread.sleep(5000);
linePlot.getData().removeAllSeries();
linePlot.getData().addSeries(loadDataFromGenerator65536(cnt).getSeries(0));
cnt++;
}
}
/**
* Test LinePlot rendering point by point (getting data from a file)
* @throws IOException
* @throws InterruptedException
*/
@Test
public void testLinePlotFile() throws IOException, InterruptedException {
LinePlot linePlot = new LinePlot("Title ", getDataFromFile()) ;
// linePlot.plot();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(linePlot.getChartPanel());
frame.pack();
RefineryUtilities.centerFrameOnScreen(frame);
frame.setVisible(true);
Thread.sleep(timeToClose);
}
/**
* Test LinePlot rendering point by point (getting data from a generator)
*
* @throws IOException
* @throws InterruptedException
*/
@Test
public void testLinePlotGenerator() throws IOException, InterruptedException {
linePlot.clear();
for (int i = 0; i < 1; i++) {
linePlot.addSeries(getDataFromGenerator(1, linePlot));
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(linePlot.getChartPanel());
frame.pack();
SwingUtils.centerOnScreen(frame);
frame.setVisible(true);
}
/**
* Get data from file
* @return
* @throws IOException
*/
private XYSeriesCollectionP getDataFromFile() throws IOException{
String seriesName = "File Data";
XYSeriesCollectionP data = new XYSeriesCollectionP();
LineNumberReader in = new LineNumberReader(new FileReader(file));
// Update data
data.addSeries(new XYSeriesP(seriesName));
// Read data
String s;
while ((s = in.readLine()) != null) {
double x = (double) in.getLineNumber();
double y = Double.parseDouble(s);
data.getSeries(seriesName).add(x, y);
}
in.close();
return(data);
}
/**
* Get data from a generator
* @param sleeptime Time between data points
* @return
*/
private XYSeriesCollectionP getDataFromGenerator(final long sleeptime){
final String seriesBaseName = "Generator Data";
final XYSeriesCollectionP data = new XYSeriesCollectionP();
final XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 1000, false);
Thread t = new Thread(new Runnable() {
@Override
public void run() {
for(int t=0;t<1000;t++){
// Reset generator
generator.reset();
String seriesName = seriesBaseName+" - "+t;
XYSeriesP serie = new XYSeriesP(seriesName);
data.addSeries(serie);
double[] xy;
while((xy=generator.getNewPoint())!=null){
serie.add(xy[0], xy[1]+t); // Add t to the y value to see the plotted line
// data.getSeries(seriesName).add(xy[0], xy[1]+t,false); // No notification send - Update of GUI will be performed periodically
try {
Thread.sleep(sleeptime);
} catch (InterruptedException e) {
}
}
}
System.out.println("DONE");
}
});
t.start();
return data;
}
private XYSeriesCollectionP loadDataFromGenerator() {
final String seriesBaseName = "Generator Data";
final XYSeriesCollectionP data = new XYSeriesCollectionP();
final XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 1000, false);
Thread.sleep(timeToClose);
}
for (int t = 0; t < 1000; t++) {
// Reset generator
generator.reset();
@Test
public void testLinePlotGeneratorOne() throws IOException, InterruptedException {
String seriesName = seriesBaseName + " - " + t;
final XYSeriesP f = new XYSeriesP(seriesName);
data.addSeries(f);
XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 1000, false);
double[] xy;
while ((xy = generator.getNewPoint()) != null) {
// f.add(xy[0], xy[1] + t); // Add t to the y value to see the plotted line
f.add(xy[0], xy[1] + t, false); // No notification send - use this if all data is available before plotting
}
}
generator.reset();
System.out.println("DONE");
String seriesName = "test";
LinePlotSeries series = new LinePlotSeries(seriesName);
return data;
}
private XYSeriesCollectionP loadDataFromGenerator65536(int count) {
final String seriesBaseName = "Generator Data";
final XYSeriesCollectionP data = new XYSeriesCollectionP();
final XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 65536, false);
String seriesName = seriesBaseName;
final XYSeriesP f = new XYSeriesP(seriesName);
data.addSeries(f);
double[] xy;
while ((xy = generator.getNewPoint()) != null) {
series.appendData(xy[0], xy[1]); // Add t to the y value to see the plotted line
}
double[] xy;
while ((xy = generator.getNewPoint()) != null) {
f.add(xy[0], xy[1]+count, false); // No notification send - use this if all data is available before plotting
}
linePlot.clear();
linePlot.addSeries(series);
System.out.println("DONE");
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(linePlot.getChartPanel());
frame.pack();
SwingUtils.centerOnScreen(frame);
frame.setVisible(true);
Thread.sleep(timeToClose);
}
/**
* Test LinePlot rendering point by point (getting data from a generator)
*
* @throws IOException
* @throws InterruptedException
*/
@Test
public void testLinePlotGenerator65536() throws IOException, InterruptedException {
linePlot.clear();
linePlot.addSeries(loadDataFromGenerator65536(0, linePlot));
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(linePlot.getChartPanel());
frame.pack();
SwingUtils.centerOnScreen(frame);
frame.setVisible(true);
int cnt = 1;
while (true) {
Thread.sleep(5000);
linePlot.clear();
linePlot.addSeries(loadDataFromGenerator65536(cnt, linePlot));
cnt++;
}
}
/**
* Test LinePlot rendering point by point (getting data from a file)
*
* @throws IOException
* @throws InterruptedException
*/
@Test
public void testLinePlotFile() throws IOException, InterruptedException {
linePlot.clear();
linePlot.addSeries(getDataFromFile());
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(linePlot.getChartPanel());
frame.pack();
SwingUtils.centerOnScreen(frame);
frame.setVisible(true);
Thread.sleep(timeToClose);
}
/**
* Get data from file
*
* @return
* @throws IOException
*/
private LinePlotSeries getDataFromFile() throws IOException {
String seriesName = "File Data";
LineNumberReader in = new LineNumberReader(new FileReader(file));
// Update data
LinePlotSeries series = new LinePlotSeries(seriesName);
// Read data
String s;
while ((s = in.readLine()) != null) {
double x = (double) in.getLineNumber();
double y = Double.parseDouble(s);
series.appendData(x, y);
}
in.close();
return (series);
}
/**
* Get data from a generator
*
* @param sleeptime Time between data points
* @return
*/
private LinePlotSeries[] getDataFromGenerator(final long sleeptime, final LinePlot plot) {
final String seriesBaseName = "Generator Data";
final LinePlotSeries[] series = new LinePlotSeries[100];
for (int i = 0; i < series.length; i++) {
String seriesName = seriesBaseName + " - " + i;
series[i] = new LinePlotSeries(seriesName);
}
plot.addSeries(series);
final XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 1000, false);
Thread t = new Thread(new Runnable() {
@Override
public void run() {
long start = System.currentTimeMillis();
for (int i = 0; i < series.length; i++) {
// Reset generator
generator.reset();
double[] xy;
while ((xy = generator.getNewPoint()) != null) {
series[i].appendData(xy[0], xy[1] + i); // Add t to the y value to see the plotted line
try {
Thread.sleep(sleeptime);
} catch (InterruptedException e) {
}
}
}
System.out.println("DONE: " + (System.currentTimeMillis() - start));
}
});
t.start();
return series;
}
private LinePlotSeries[] loadDataFromGenerator(final LinePlot plot) {
final String seriesBaseName = "Generator Data";
final LinePlotSeries[] series = new LinePlotSeries[10];
for (int i = 0; i < series.length; i++) {
String seriesName = seriesBaseName + " - " + i;
series[i] = new LinePlotSeries(seriesName);
}
plot.addSeries(series);
final XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 1000, false);
plot.setUpdatesEnabled(false);
for (int t = 0; t < 1000; t++) {
// Reset generator
generator.reset();
double[] xy;
while ((xy = generator.getNewPoint()) != null) {
series[t].appendData(xy[0], xy[1] + t); // Add t to the y value to see the plotted line
}
plot.requestSeriesUpdate(series[t]);
}
plot.setUpdatesEnabled(true);
System.out.println("DONE");
return series;
}
private LinePlotSeries loadDataFromGenerator65536(int count, final LinePlot plot) {
final String seriesBaseName = "Generator Data";
LinePlotSeries series = new LinePlotSeries(seriesBaseName);
final XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 65536, false);
plot.setUpdatesEnabled(false);
double[] xy;
plot.setUpdatesEnabled(false);
while ((xy = generator.getNewPoint()) != null) {
series.appendData(xy[0], xy[1] + count); // No notification send - use this if all data is available before plotting
}
plot.setUpdatesEnabled(true);
plot.update(true);
System.out.println("DONE");
return series;
}
return data;
}
}
@@ -1,212 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.plot.xyz;
import java.util.Random;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
//import ch.psi.sls.xasec.data.DataSet;
//import ch.psi.sls.xasec.data.DataSetUtils;
import ch.psi.plot.xyz.MatrixPlot;
import ch.psi.plot.xyz.MatrixPlotData;
import ch.psi.plot.xyz.generator.DataGenerator;
import ch.psi.plot.xyz.generator.Sinus2D;
import ch.psi.plot.xyz.generator.XYZGenerator;
/**
* Test case for MatrixPlot class
* @author ebner
*
*/
public class MatrixPlot2Test {
// Get Logger
private static final Logger logger = Logger.getLogger(MatrixPlot2Test.class.getName());
private final long timeToClose = 7200000; // 2 hours
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
/**
* Test case for MatrixPlot (getting data from a generator)
* @throws InterruptedException
*/
@Test
public void testMatrixPlot() throws InterruptedException {
double startX = 0;
double stepSizeX = 1;
int stepsX = 50;
double startY = 0;
double stepSizeY = 1;
int stepsY = 50;
final DynamicXYZDatasetList data = new DynamicXYZDatasetList();
final XYZGenerator generator = new XYZGenerator(new Sinus2D(2,4), startX, stepSizeX, stepsX, startY, stepSizeY, stepsY, false);
final MatrixPlot2 plot = new MatrixPlot2("Matrix Plot Test", data);
final JFrame frame = new JFrame("");
frame.setContentPane(plot.getChartPanel());
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
Thread t = new Thread(new Runnable() {
@Override
public void run() {
// for(int t=0;t<200;t++){
// // Reset generator
// generator.reset();
// int count = 0;
double[] xyz;
while((xyz=generator.getNewPoint())!=null){
data.addData(xyz[0], xyz[1], xyz[2]);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
// or set matrixChart.setNotify(false); in MatrixPlot Line 431 ...
// if(count==10){
// plot.update();
// count=0;
// }
// else{
// count++;
// }
}
System.out.println("Generator done");
// }
}
});
t.start();
Thread.sleep(timeToClose);
}
@Test
public void testPlotConverterGeneratorMatrixPlot() throws InterruptedException {
DataGenerator generator = new DataGenerator(new Sinus2D(2,4));
generator.generateData();
MatrixPlot plot = new MatrixPlot("Matrix Plot Test", generator.getData());
// converter.generateData();
//// Thread t = new Thread(converter);
//// t.start();
final JFrame frame = new JFrame("");
frame.setContentPane(plot.getChartPanel());
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
Thread.sleep(timeToClose);
}
@Test
public void testPlotMatrixPlot() throws InterruptedException {
MatrixPlotData data = new MatrixPlotData(-10, -1, 10, -10, -1, 10);
Random r = new Random();
for (double i = data.getMinX(); i <= data.getMaxX(); i++) {
for (double t = data.getMinY(); t <= data.getMaxY(); t++) {
data.addData(i, t, r.nextDouble() * 10);
}
}
MatrixPlot plot = new MatrixPlot("Matrix Plot Test", data);
final JFrame frame = new JFrame("");
frame.setContentPane(plot.getChartPanel());
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
Thread.sleep(timeToClose);
}
@Test
public void testPlotMatrixPlot2() throws InterruptedException {
MatrixPlotData data = new MatrixPlotData(-11.5, -11.0, 6, -10.5, -10.0, 6);
Random r = new Random();
for (double i = data.getMinX(); i <= data.getMaxX(); i=i+0.1) {
for (double t = data.getMinY(); t <= data.getMaxY(); t=t+0.1) {
logger.info("Add data: "+i+" "+t);
if(t==data.getMinY()){
continue;
}
data.addData(i, t, r.nextDouble() * 10);
}
}
MatrixPlot plot = new MatrixPlot("Matrix Plot Test", data);
final JFrame frame = new JFrame("");
frame.setContentPane(plot.getChartPanel());
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
Thread.sleep(timeToClose);
}
}
@@ -1,211 +0,0 @@
/**
*
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this code. If not, see <http://www.gnu.org/licenses/>.
*
*/
package ch.psi.plot.xyz;
import java.util.Random;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
//import ch.psi.sls.xasec.data.DataSet;
//import ch.psi.sls.xasec.data.DataSetUtils;
import ch.psi.plot.xyz.MatrixPlot;
import ch.psi.plot.xyz.MatrixPlotData;
import ch.psi.plot.xyz.generator.DataGenerator;
import ch.psi.plot.xyz.generator.Sinus2D;
import ch.psi.plot.xyz.generator.XYZGenerator;
/**
* Test case for MatrixPlot class
* @author ebner
*
*/
public class MatrixPlotTest {
// Get Logger
private static final Logger logger = Logger.getLogger(MatrixPlotTest.class.getName());
private final long timeToClose = 7200000; // 2 hours
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
/**
* Test case for MatrixPlot (getting data from a generator)
* @throws InterruptedException
*/
@Test
public void testMatrixPlot() throws InterruptedException {
double startX = 10;
double stepSizeX = 1;
int stepsX = 1000;
double startY = 10;
double stepSizeY = 1;
int stepsY = 1000;
final MatrixPlotData data = new MatrixPlotData(startX, startX+stepsX*stepSizeX, stepsX, startY, startY+stepsY*stepSizeY, stepsY);
final XYZGenerator generator = new XYZGenerator(new Sinus2D(2,4), startX, stepSizeX, stepsX, startY, stepSizeY, stepsY, false);
final MatrixPlot plot = new MatrixPlot("Matrix Plot Test", data);
final JFrame frame = new JFrame("");
frame.setContentPane(plot.getChartPanel());
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
Thread t = new Thread(new Runnable() {
@Override
public void run() {
// for(int t=0;t<200;t++){
// // Reset generator
// generator.reset();
// int count = 0;
double[] xyz;
while((xyz=generator.getNewPoint())!=null){
data.addData(xyz[0], xyz[1], xyz[2]);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
}
// or set matrixChart.setNotify(false); in MatrixPlot Line 431 ...
// if(count==10){
// plot.update();
// count=0;
// }
// else{
// count++;
// }
}
// }
}
});
t.start();
Thread.sleep(timeToClose);
}
@Test
public void testPlotConverterGeneratorMatrixPlot() throws InterruptedException {
DataGenerator generator = new DataGenerator(new Sinus2D(2,4));
generator.generateData();
MatrixPlot plot = new MatrixPlot("Matrix Plot Test", generator.getData());
// converter.generateData();
//// Thread t = new Thread(converter);
//// t.start();
final JFrame frame = new JFrame("");
frame.setContentPane(plot.getChartPanel());
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
Thread.sleep(timeToClose);
}
@Test
public void testPlotMatrixPlot() throws InterruptedException {
MatrixPlotData data = new MatrixPlotData(-10, -1, 10, -10, -1, 10);
Random r = new Random();
for (double i = data.getMinX(); i <= data.getMaxX(); i++) {
for (double t = data.getMinY(); t <= data.getMaxY(); t++) {
data.addData(i, t, r.nextDouble() * 10);
}
}
MatrixPlot plot = new MatrixPlot("Matrix Plot Test", data);
final JFrame frame = new JFrame("");
frame.setContentPane(plot.getChartPanel());
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
Thread.sleep(timeToClose);
}
@Test
public void testPlotMatrixPlot2() throws InterruptedException {
MatrixPlotData data = new MatrixPlotData(-11.5, -11.0, 6, -10.5, -10.0, 6);
Random r = new Random();
for (double i = data.getMinX(); i <= data.getMaxX(); i=i+0.1) {
for (double t = data.getMinY(); t <= data.getMaxY(); t=t+0.1) {
logger.info("Add data: "+i+" "+t);
if(t==data.getMinY()){
continue;
}
data.addData(i, t, r.nextDouble() * 10);
}
}
MatrixPlot plot = new MatrixPlot("Matrix Plot Test", data);
final JFrame frame = new JFrame("");
frame.setContentPane(plot.getChartPanel());
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // Close application if frame is closed
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
Thread.sleep(timeToClose);
}
}
@@ -3,7 +3,7 @@ package ch.psi.plot.xyz.generator;
import java.util.logging.Logger;
import ch.psi.plot.xy.generator.Noise;
import ch.psi.plot.xyz.MatrixPlotData;
import ch.psi.plot.MatrixPlotSeries;
/**
* Converter object converting a file into PixelPlot data
@@ -12,7 +12,7 @@ public class DataGenerator implements Runnable {
private static Logger logger = Logger.getLogger(DataGenerator.class.getName());
private final MatrixPlotData data;
private final MatrixPlotSeries data;
private XYZGeneratorFunction function;
double xMin = 0;
@@ -38,7 +38,7 @@ public class DataGenerator implements Runnable {
public DataGenerator(XYZGeneratorFunction function, boolean noise, boolean metaDataAvailable){
this.function = function;
data = new MatrixPlotData(xMin,xMax,xNStep,yMin,yMax,yNStep);
data = new MatrixPlotSeries(null, xMin,xMax,xNStep,yMin,yMax,yNStep);
if(noise){
noiseFunctionX = new Noise(data.getBinWidthX());
@@ -70,7 +70,7 @@ public class DataGenerator implements Runnable {
}
logger.fine("x: "+x+" y: "+y+" z: "+function.generate(x, y));
data.addData(x, y, function.generate(x, y));
data.appendData(x, y, function.generate(x, y));
// try {
// Thread.sleep(1);
// } catch (InterruptedException e1) {
@@ -80,7 +80,7 @@ public class DataGenerator implements Runnable {
}
}
public MatrixPlotData getData() {
public MatrixPlotSeries getData() {
return data;
}
@@ -43,12 +43,12 @@ public class XYZGenerator {
this.startX = startX;
this.stepSizeX = stepSizeX;
this.stepsX = stepsX;
this.currentStepX = startX;
this.currentStepX = 0;
this.startY = startY;
this.stepSizeY = stepSizeY;
this.stepsY = stepsY;
this.currentStepY = startY;
this.currentStepY = 0;
if(noise){
this.noiseGeneratorX = new Noise(stepSizeX);
-76
View File
@@ -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;
}
}
-44
View File
@@ -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);
}
}
-82
View File
@@ -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();
}
}
-56
View File
@@ -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;
}
}
}
-150
View File
@@ -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>
-29
View File
@@ -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 );
}
}
-60
View File
@@ -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;
}
}
-985
View File
@@ -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);
}
}
-46
View File
@@ -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;
}
}
-28
View File
@@ -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();
}
}
-148
View File
@@ -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;
}
}
-131
View File
@@ -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>
* &lt;complexType name="menuNodeType">
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;choice>
* &lt;sequence>
* &lt;element name="submenu" type="{}menuNodeType" maxOccurs="unbounded" minOccurs="0"/>
* &lt;/sequence>
* &lt;element name="utilityClass" type="{}utilityClassType"/>
* &lt;/choice>
* &lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/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;
}
}
-74
View File
@@ -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>
* &lt;complexType name="menuTreeType">
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;sequence>
* &lt;element name="menuNode" type="{}menuNodeType" maxOccurs="unbounded" minOccurs="0"/>
* &lt;/sequence>
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/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;
}
}
-28
View File
@@ -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();
}
}
-96
View File
@@ -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);
}
}
-6
View File
@@ -1,6 +0,0 @@
package ch.psi.plot.plot.done;
public interface PlugableUtil {
public enum PlotType {oneDim, twoDim};
public String getLabel();
}
-8
View File
@@ -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>
* &lt;complexType name="utilityClassType">
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/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;
}
}
-70
View File
@@ -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;
}
}
-28
View File
@@ -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>
-36
View File
@@ -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>
-33
View File
@@ -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;
}
}
}
-193
View File
@@ -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
}
-70
View File
@@ -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;
}
}
-97
View File
@@ -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;
}
}
-140
View File
@@ -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;
}
}
-230
View File
@@ -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);
}
}
-216
View File
@@ -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;
}
}
-109
View File
@@ -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();
}
}
}
-75
View File
@@ -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();
}
}
}
-122
View File
@@ -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
}
}
-87
View File
@@ -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();
}
}
-41
View File
@@ -1,41 +0,0 @@
package ch.psi.plot.xyz.plugable;
/**
* Abstract filter class
*/
public abstract class Filter {
/**
* Get the filter data entry of filter row i and column j
* @param i Row of the filter
* @param j Column of the filter
* @return Filter entry
*/
public abstract double getDataEntry(int i, int j);
/**
* Get the number of rows of the filter
* @return Number of rows
*/
public abstract int getNumberOfRows();
/**
* Get the number of columns of the filter
* @return Number of columns
*/
public abstract int getNumberOfColumns();
/**
* Get whether filter dimensions are odd or even
* @return True if either the number of rows or the number of columns is odd, False otherwise
*/
public boolean isDimensionOdd(){
if( (getNumberOfRows() % 2 == 0) || (getNumberOfColumns() % 2 == 0)){
return false;
}
else{
return true;
}
}
}
@@ -1,79 +0,0 @@
package ch.psi.plot.xyz.plugable;
import java.util.LinkedList;
import java.util.Queue;
import java.util.logging.Logger;
import ch.psi.plot.xyz.JFreeMatrixPlotData;
public class FilterTransformation {
private static Logger logger = Logger.getLogger(FilterTransformation.class.getName());
/**
* Apply specified filter to the passed data object
* @param plotData
* @param filter
*/
public static void applyFilter(JFreeMatrixPlotData plotData, Filter filter){
int numberOfXBins = plotData.getMetadata().getNumberOfBinsX();
int numberOfYBins = plotData.getMetadata().getNumberOfBinsY();
logger.fine("Number of X bins: "+ numberOfXBins);
logger.fine("Number of Y bins: "+ numberOfYBins);
if(!filter.isDimensionOdd()){
logger.severe("Dimension of Filter Matrix must be odd");
return;
}
//We need a queue to store the transformed values since we don't want the old values to
//be overwritten. (not before their not used anymore for a later row)
Queue<double[]> queue = new LinkedList<double[]>();
int requiredQueueSize = (filter.getNumberOfRows() - 1)/2;
int rowEdges = requiredQueueSize;
int columnEdges = (filter.getNumberOfColumns() - 1)/2;
for (int i = rowEdges; i < numberOfYBins - rowEdges; i++) {
double[] filteredPointsQueuing = new double[numberOfXBins - 2*columnEdges];
for (int j = columnEdges; j < numberOfXBins - columnEdges; j++) {
double filteredPoint = 0.0;
for (int f = 0; f < filter.getNumberOfRows(); f++) {
for (int g = 0; g < filter.getNumberOfColumns(); g++) {
int positionOfFilterPointInMatrixRow = i - rowEdges + f;
int positionOfFilterPointInMatrixColumn = j - columnEdges + g;
//getValue is called (row, column)
filteredPoint += filter.getDataEntry(f, g) * plotData.getValue(positionOfFilterPointInMatrixRow, positionOfFilterPointInMatrixColumn );
}
}//filtered point is calculated
filteredPointsQueuing[j - columnEdges] = filteredPoint;
}
queue.add(filteredPointsQueuing);
if(queue.size() > requiredQueueSize){
double[] filteredPointsPolled = new double[numberOfXBins - 2*columnEdges];
filteredPointsPolled = queue.poll();
//Write the polled data back
for (int j = columnEdges; j < numberOfXBins - columnEdges; j++) {
plotData.setValue(i - requiredQueueSize, j, filteredPointsPolled[j - columnEdges]);
}
}
}
//empty stack if last line is reached
while(queue.size() > 0){
double[] filteredPointsPolled = new double[numberOfXBins - 2*columnEdges];
filteredPointsPolled = queue.poll();
//Write the polled data back
for (int j = columnEdges; j < numberOfXBins - columnEdges; j++) {
//setZValue is called (column, row, value)
plotData.setValue(numberOfYBins - 1 - rowEdges - queue.size(), j, filteredPointsPolled[j - columnEdges]);
}
}
}
}
@@ -1,106 +0,0 @@
package ch.psi.plot.xyz.plugable;
import java.util.ArrayList;
import java.util.logging.Logger;
import org.apache.commons.math.complex.Complex;
import org.apache.commons.math.transform.FastFourierTransformer;
import ch.psi.plot.xy.plugable.FourierTransformer;
import ch.psi.plot.xyz.JFreeMatrixPlot;
import ch.psi.plot.xyz.JFreeMatrixPlotData;
import ch.psi.plot.xyz.JFreeMatrixPlotMetadata;
import ch.psi.plot.xyz.MatrixPlotData;
public class FourierTransformation implements PlugableUtilXYZ{
private static Logger logger = Logger.getLogger(FourierTransformation.class.getName());
/**
* Apply fourier transformation to the data and return a new data matrix
* TODO to be checked
* @param plotData
* @return
*/
private JFreeMatrixPlotData calculateFFT(JFreeMatrixPlotData plotData){
int powerOf2InputDataLengthX = FourierTransformer.getPreviousPowerOf2(plotData.getMetadata().getNumberOfBinsX());
int powerOf2InputDataLengthY = FourierTransformer.getPreviousPowerOf2(plotData.getMetadata().getNumberOfBinsY());
//Allocate input for FFT
Complex[][] inputData = new Complex[powerOf2InputDataLengthY][powerOf2InputDataLengthX];
//define Input for FFT
for (int i = 0; i < powerOf2InputDataLengthY; i++) {
for (int j = 0; j < powerOf2InputDataLengthX; j++) {
//Imaginary part of InputData is zero
inputData[i][j] = new Complex(plotData.getValue(i, j), 0.0);
}
}
//Do 2D FFT
FastFourierTransformer fastFourierTransformer = new FastFourierTransformer();
Complex[][] fourierTransformedData = (Complex[][]) fastFourierTransformer.mdfft(inputData,true);
//calculate interval in fourier space
double fourierSpaceScaleFaktorX = (2*Math.PI)/(plotData.getMetadata().getBinWidthX()*powerOf2InputDataLengthX);
double fourierSpaceScaleFaktorY = (2*Math.PI)/(plotData.getMetadata().getBinWidthY()*powerOf2InputDataLengthY);
//Now we know all metadata
// New FourierPlotDataInstance
JFreeMatrixPlotMetadata metadata = new JFreeMatrixPlotMetadata();
metadata.setMinX(0.0);
metadata.setMaxX(fourierSpaceScaleFaktorX*powerOf2InputDataLengthX);
metadata.setNumberOfBinsX(powerOf2InputDataLengthX);
metadata.setMinY(0.0);
metadata.setMaxY(fourierSpaceScaleFaktorY*powerOf2InputDataLengthY);
metadata.setNumberOfBinsY(powerOf2InputDataLengthY);
metadata.setMinValue(Double.NEGATIVE_INFINITY);
metadata.setMaxValue(Double.POSITIVE_INFINITY);
MatrixPlotData fourierPlotData = new MatrixPlotData(metadata);
//Fill the data of the new instance with the fourier transform
ArrayList<Double> powerSpectrumValues = new ArrayList<Double>(powerOf2InputDataLengthX*powerOf2InputDataLengthY);
for (int i = 0; i < powerOf2InputDataLengthY; i++) {
for (int j = 0; j < powerOf2InputDataLengthX; j++) {
double kx = fourierSpaceScaleFaktorX*j + fourierSpaceScaleFaktorX/2.0;
double ky = fourierSpaceScaleFaktorY*i + fourierSpaceScaleFaktorY/2.0;
//Only Power Spectrum
double powerSpectrumValue = fourierTransformedData[i][j].abs();
//double imagPartValue = fourierTransformedData[i][j].getImaginary();
//double realPartValue = fourierTransformedData[i][j].getReal();
fourierPlotData.addData(kx,ky,powerSpectrumValue);
powerSpectrumValues.add(new Double(powerSpectrumValue));
}
}
return fourierPlotData;
}
/**
* Show Fourier transformation of the underlying data
*/
@Override
public void execute(final JFreeMatrixPlot jFreeMatrixPlot) {
Thread t = new Thread( new Runnable(){
public void run(){
try {
JFreeMatrixPlot plot = new JFreeMatrixPlot("Fourier Transformation", calculateFFT(jFreeMatrixPlot.getData()));
plot.adaptColorMapScale();
plot.plot(false);
} catch (Exception e) {
logger.warning(e.getMessage());
}
}});
t.start();
}
@Override
public String getLabel() {
return this.getClass().getSimpleName();
}
}
@@ -1,71 +0,0 @@
package ch.psi.plot.xyz.plugable;
import java.util.logging.Logger;
import ch.psi.plot.xyz.JFreeMatrixPlot;
public class GaussFilter implements PlugableUtilXYZ{
private static Logger logger = Logger.getLogger(GaussFilter.class.getName());
@Override
public void execute(final JFreeMatrixPlot jFreeMatrixPlot) {
Thread t = new Thread( new Runnable(){
public void run(){
Class<?> pluginClass = null;
String classname = "ch.psi.plot.xyz.plugable.IntegratedXValues";
try {//Load class according to its name
pluginClass = Class.forName(classname);
} catch (ClassNotFoundException e) {
logger.warning("Class " + classname + " not found " + e.getMessage());
}
IntegratedXValues integratedXValues = null;
try {
integratedXValues = (IntegratedXValues) pluginClass.newInstance();
} catch (InstantiationException e) {
logger.warning("Unable to instantiate " + classname + " : " + e.getMessage());
} catch (IllegalAccessException e) {
logger.warning("Unable to access " + classname + " : " + e.getMessage());
}
try {
final int sizeMin = 3;
final double filteringRange = 0.02;
int n = (int) (filteringRange*jFreeMatrixPlot.getData().getMetadata().getNumberOfBinsY());
int m = (int) (filteringRange*jFreeMatrixPlot.getData().getMetadata().getNumberOfBinsX());
int nOdd = n + (n+1) % 2;
int mOdd = m + (m+1) % 2;
final int nFilter = Math.max(nOdd, sizeMin);
final int mFilter = Math.max(mOdd, sizeMin);
logger.info("Total Integral before smoothing: " + integratedXValues.integrate(jFreeMatrixPlot.getData(), jFreeMatrixPlot.getLowerLeftChartCorner(), jFreeMatrixPlot.getUpperRightChartCorner()));
FilterTransformation.applyFilter(jFreeMatrixPlot.getData(), new GaussFilterMatrix(nFilter, mFilter));
logger.info("Total Integral after smoothing: " + integratedXValues.integrate(jFreeMatrixPlot.getData(), jFreeMatrixPlot.getLowerLeftChartCorner(), jFreeMatrixPlot.getUpperRightChartCorner()));
jFreeMatrixPlot.getMatrixPlotPanel().getChart().fireChartChanged();
} catch (Exception e) {
logger.warning(e.getMessage());
}
}});
t.start();
}
@Override
public String getLabel() {
return this.getClass().getSimpleName();
}
}
@@ -1,61 +0,0 @@
package ch.psi.plot.xyz.plugable;
/**
* Gauss filter implementation 5x5
*/
public class GaussFilterMatrix extends Filter {
private int numberOfRows;
private int numberOfColumns;
private double[][] data;
private double weight = 0.0;
private double sigma = 1.0;
/**
* Create Gauss Filter
*/
public GaussFilterMatrix(int n, int m) {
this.numberOfRows = n;
this.numberOfColumns = m;
data = new double[numberOfRows][numberOfColumns];
sigma = (double) 2.0*Math.PI*Math.sqrt(n*n + m*m);
//The entry 0,0 is lower left edge! (not upper left edge)
//(doesn't matter for symmetric matrices)
for (int i = 0; i < numberOfRows; i++) {
for (int j = 0; j < numberOfColumns; j++) {
data[i][j] = Math.exp(-Math.pow(1.0/sigma,2.0)*
(Math.pow((i-(numberOfRows-1)/2.0),2.0) +
Math.pow((j-(numberOfColumns-1)/2),2.0)));
weight += data[i][j];
}
}
for (int i = 0; i < numberOfRows; i++) {
for (int j = 0; j < numberOfColumns; j++) {
data[i][j] *= 1.0/weight;
}
}
}
@Override
public double getDataEntry(int i, int j) {
return data[i][j];
}
@Override
public int getNumberOfColumns() {
return numberOfColumns;
}
@Override
public int getNumberOfRows() {
return numberOfRows;
}
}
-113
View File
@@ -1,113 +0,0 @@
package ch.psi.plot.xyz.plugable;
import java.util.logging.Logger;
import org.jfree.data.xy.VectorSeries;
import org.jfree.data.xy.VectorSeriesCollection;
import ch.psi.plot.util.XYPoint;
import ch.psi.plot.xyz.JFreeMatrixPlot;
import ch.psi.plot.xyz.JFreeMatrixPlotData;
public class Gradient implements PlugableUtilXYZ{
private static Logger logger = Logger.getLogger(Gradient.class.getName());
/**
* Calculates the normalized gradient field of the visible part of the scalar field
* @param plotData
* @param lowerLeftChartCorner
* @param upperRightChartCorner
* @return
*/
private VectorSeriesCollection calculateGradientField(JFreeMatrixPlotData plotData, XYPoint lowerLeftChartCorner, XYPoint upperRightChartCorner){
double xBinWidth = plotData.getMetadata().getBinWidthX();
double yBinWidth = plotData.getMetadata().getBinWidthY();
logger.fine("x-width: "+xBinWidth+" y-width: "+yBinWidth);
VectorSeriesCollection gradientField = new VectorSeriesCollection();
VectorSeries vectorSeries = new VectorSeries("gradient field of detector");
gradientField.addSeries(vectorSeries);
//calculate gradient, except at the borders.
//the borders are either given by selection, or - if plot is still being updated, by the current XBin value
int selectedXminBin = plotData.getXBin(lowerLeftChartCorner.getX());
int selectedYminBin = plotData.getYBin(lowerLeftChartCorner.getY());
int selectedXmaxBin = plotData.getXBin(upperRightChartCorner.getX());
int selectedYmaxBin = plotData.getYBin(upperRightChartCorner.getY());
int numberOfSelectedXBins = selectedXmaxBin - selectedXminBin;
int numberOfSelectedYBins = selectedYmaxBin - selectedYminBin;
logger.fine("no x bins: "+numberOfSelectedXBins+" no y bins: "+numberOfSelectedYBins);
double[][] gradientXField = new double[numberOfSelectedYBins][numberOfSelectedXBins];
double[][] gradientYField = new double[numberOfSelectedYBins][numberOfSelectedXBins];
double maxGradientNorm = 0.0;
double binDiagonalLength = Math.sqrt(xBinWidth*xBinWidth + yBinWidth*yBinWidth);
//calculate gradient, except at the borders and beyond
for (int i = 1; i < numberOfSelectedYBins - 1; i++) {
for (int j = 1 ; j < numberOfSelectedXBins - 1; j++) {
//Remember that x Axis defines column (y Axis row)
//such that gradientX = d/d(column) and gradientY = d/ d(row)
gradientXField[i][j] = (plotData.getValue(i + selectedYminBin, j + selectedXminBin + 1) -
plotData.getValue(i + selectedYminBin, j + selectedXminBin - 1))/2*xBinWidth;
gradientYField[i][j] = (plotData.getValue(i + selectedYminBin + 1, j + selectedXminBin) -
plotData.getValue(i + selectedYminBin -1, j + selectedXminBin))/2*yBinWidth;
double gradientNorm = Math.sqrt(Math.pow(gradientXField[i][j], 2.0) + Math.pow(gradientYField[i][j], 2.0));
maxGradientNorm = Math.max(maxGradientNorm, gradientNorm);
}
}
double scaleFactor;
if (maxGradientNorm != 0.0){
scaleFactor = 1.0/maxGradientNorm;
}
else{
scaleFactor = 0.0;
}
for (int i = 0; i < numberOfSelectedYBins - 1; i++) {
for (int j = 0; j < numberOfSelectedXBins - 1; j++) {
double scaledGradientX = binDiagonalLength * scaleFactor * gradientXField[i][j];
double scaledGradientY = binDiagonalLength * scaleFactor * gradientYField[i][j];
vectorSeries.add(plotData.getXValue(i + selectedYminBin, j + selectedXminBin), plotData.getYValue(i + selectedYminBin, j + selectedXminBin), scaledGradientX, scaledGradientY);
}
}
return gradientField;
}
/**
* Show gradient field of the underlying data
*/
@Override
public void execute(final JFreeMatrixPlot jFreeMatrixPlot) {
Thread t = new Thread( new Runnable(){
public void run(){
try {
GradientPlot plot = new GradientPlot("Gradient Field",
calculateGradientField(jFreeMatrixPlot.getData(), jFreeMatrixPlot.getLowerLeftChartCorner(), jFreeMatrixPlot.getUpperRightChartCorner()),
jFreeMatrixPlot.getLowerLeftChartCorner(), jFreeMatrixPlot.getUpperRightChartCorner());
plot.pack();
plot.setVisible(true);
} catch (Exception e) {
logger.warning(e.getMessage());
}
}});
t.start();
}
@Override
public String getLabel() {
return this.getClass().getSimpleName();
}
}
@@ -1,62 +0,0 @@
package ch.psi.plot.xyz.plugable;
import java.awt.Dimension;
import javax.swing.JFrame;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.VectorRenderer;
import org.jfree.data.xy.VectorSeriesCollection;
import ch.psi.plot.util.XYPoint;
public class GradientPlot extends JFrame{
private static final long serialVersionUID = 1L;
/**
* Constructor
* Creates a ChartPanel that plots the gradientField
* @param title
* @param gradientField
* @param lowerLeft
* @param upperRight
*/
public GradientPlot(String title, VectorSeriesCollection gradientField, XYPoint lowerLeft, XYPoint upperRight) {
super(title);
JFreeChart chart = createChart(gradientField, lowerLeft, upperRight);
ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setPreferredSize(new Dimension(500, 270));
setContentPane(chartPanel);
}
/**
* Creates a chart that plots the gradientField in a specified range (lowerleft and upperright rectangle)
* @param gradientField
* @param lowerLeft
* @param upperRight
* @return
*/
private JFreeChart createChart(VectorSeriesCollection gradientField, XYPoint lowerLeft, XYPoint upperRight) {
// create the chart...
NumberAxis xAxis = new NumberAxis("X");
xAxis.setLowerBound(lowerLeft.getX());
xAxis.setUpperBound(upperRight.getX());
NumberAxis yAxis = new NumberAxis("Y");
yAxis.setLowerBound(lowerLeft.getY());
yAxis.setUpperBound(upperRight.getY());
VectorRenderer renderer = new VectorRenderer();
XYPlot vectorPlot = new XYPlot(gradientField, xAxis, yAxis, renderer);
JFreeChart chart = new JFreeChart("Gradient Field", vectorPlot);
return chart;
}
}

Some files were not shown because too many files have changed in this diff Show More