Migrated from Mercurial to git (without history)
This commit is contained in:
10
ch.psi.plot/.classpath
Normal file
10
ch.psi.plot/.classpath
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
1
ch.psi.plot/.gitignore
vendored
Normal file
1
ch.psi.plot/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
23
ch.psi.plot/.project
Normal file
23
ch.psi.plot/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>ch.psi.plot</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
3
ch.psi.plot/.settings/org.eclipse.jdt.core.prefs
Normal file
3
ch.psi.plot/.settings/org.eclipse.jdt.core.prefs
Normal file
@@ -0,0 +1,3 @@
|
||||
#Tue Oct 18 15:36:07 CEST 2011
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
5
ch.psi.plot/.settings/org.eclipse.m2e.core.prefs
Normal file
5
ch.psi.plot/.settings/org.eclipse.m2e.core.prefs
Normal file
@@ -0,0 +1,5 @@
|
||||
#Tue Oct 18 14:55:04 CEST 2011
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
||||
BIN
ch.psi.plot/documentation/3DPlot.pdf
Normal file
BIN
ch.psi.plot/documentation/3DPlot.pdf
Normal file
Binary file not shown.
BIN
ch.psi.plot/documentation/LinePlot.pdf
Normal file
BIN
ch.psi.plot/documentation/LinePlot.pdf
Normal file
Binary file not shown.
BIN
ch.psi.plot/documentation/MatrixPlot.pdf
Normal file
BIN
ch.psi.plot/documentation/MatrixPlot.pdf
Normal file
Binary file not shown.
1
ch.psi.plot/documentation/Readme.txt
Normal file
1
ch.psi.plot/documentation/Readme.txt
Normal file
@@ -0,0 +1 @@
|
||||
JFree is not thread safe. If a manipulate the plotting data used by JFree, the rendering process is not synchronized in the sense that it does not lock the data and hence does not finish plotting the data it started with. If you e.g. define a array of hundred points to be plotted by JFree and for some reason you decide to remove (or alter) these points, then the rendering thread tries to finish rendering the 100 points it started with but allows the concurrent modification of the data. This can cause a runtime Array Index Out of Bounds Exception in the worst case or at least give a 'noisy' impression of the plotting. However, the problem occurs only for large datasets and/or high update frequencies.
|
||||
66
ch.psi.plot/pom.xml
Normal file
66
ch.psi.plot/pom.xml
Normal file
@@ -0,0 +1,66 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>ch.psi</groupId>
|
||||
<artifactId>plot</artifactId>
|
||||
<version>1.1.30</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jfree</groupId>
|
||||
<artifactId>chart</artifactId>
|
||||
<version>1.0.13</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.8.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- Generate Javadoc Jar -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.8</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- Generate Source Jar -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>2.1.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<distributionManagement>
|
||||
<snapshotRepository>
|
||||
<id>i.snapshots</id>
|
||||
<name>Artifactory Snapshots</name>
|
||||
<url>http://slsyoke1/artifactory/libs-snapshots-local</url>
|
||||
</snapshotRepository>
|
||||
<repository>
|
||||
<id>i.releases</id>
|
||||
<name>Atrifactory Releases</name>
|
||||
<url>http://slsyoke1/artifactory/libs-releases-local</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
</project>
|
||||
46
ch.psi.plot/src/main/java/ch/psi/plot/Plot.java
Normal file
46
ch.psi.plot/src/main/java/ch/psi/plot/Plot.java
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
*
|
||||
* 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;
|
||||
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public interface Plot {
|
||||
/**
|
||||
* Get the chart panel
|
||||
* @return
|
||||
*/
|
||||
public ChartPanel getChartPanel();
|
||||
|
||||
/**
|
||||
* Get chart of the plot (e.g. to be able to export the chart as an image)
|
||||
* @return
|
||||
*/
|
||||
public JFreeChart getChart();
|
||||
|
||||
/**
|
||||
* Update plot (notify all components of the plot)
|
||||
*/
|
||||
public void update();
|
||||
}
|
||||
541
ch.psi.plot/src/main/java/ch/psi/plot/xy/LinePlot.java
Normal file
541
ch.psi.plot/src/main/java/ch/psi/plot/xy/LinePlot.java
Normal file
@@ -0,0 +1,541 @@
|
||||
package ch.psi.plot.xy;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import org.jfree.chart.ChartFactory;
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.annotations.XYAnnotation;
|
||||
import org.jfree.chart.annotations.XYDrawableAnnotation;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.entity.StandardEntityCollection;
|
||||
import org.jfree.chart.labels.StandardXYToolTipGenerator;
|
||||
import org.jfree.chart.labels.XYToolTipGenerator;
|
||||
import org.jfree.chart.plot.Marker;
|
||||
import org.jfree.chart.plot.PlotOrientation;
|
||||
import org.jfree.chart.plot.ValueMarker;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
|
||||
import org.jfree.data.Range;
|
||||
import org.jfree.data.xy.XYDataItem;
|
||||
import org.jfree.ui.Layer;
|
||||
import org.jfree.ui.RectangleAnchor;
|
||||
import org.jfree.ui.RefineryUtilities;
|
||||
import org.jfree.ui.TextAnchor;
|
||||
|
||||
import ch.psi.plot.Plot;
|
||||
import ch.psi.plot.xy.tools.Average;
|
||||
import ch.psi.plot.xy.tools.CrossAnnotation;
|
||||
import ch.psi.plot.xy.tools.Derivative;
|
||||
import ch.psi.plot.xy.tools.Integral;
|
||||
import ch.psi.plot.xy.tools.Maximum;
|
||||
import ch.psi.plot.xy.tools.Minimum;
|
||||
|
||||
public class LinePlot implements Plot {
|
||||
|
||||
|
||||
// Get Logger
|
||||
private static final Logger logger = Logger.getLogger(LinePlot.class.getName());
|
||||
|
||||
private ChartPanel chartPanel;
|
||||
|
||||
private static final int chartPanelWidth = 500;
|
||||
private static final int chartPanelHeight = 270;
|
||||
|
||||
//Defining Context Menu Label
|
||||
private static final String showLegendMenuLabel = "Show Legend";
|
||||
private static final String hideLegendMenuLabel = "Hide Legend";
|
||||
private static final String showTooltipsMenuLabel = "Show Tooltips";
|
||||
private static final String hideTooltipsMenuLabel = "Hide Tooltips";
|
||||
|
||||
|
||||
private XYSeriesCollectionP data;
|
||||
|
||||
JFreeChart chart;
|
||||
|
||||
private String title;
|
||||
private String xAxisLabel = "X";
|
||||
private String yAxisLabel = "Y";
|
||||
|
||||
private boolean tooltips = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param title Title of plot
|
||||
*/
|
||||
public LinePlot(String title){
|
||||
this(title, new XYSeriesCollectionP());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param title Title of plot
|
||||
* @param data Data of plot
|
||||
*/
|
||||
public LinePlot(String title, XYSeriesCollectionP data){
|
||||
this.title = title;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the chart panel of this plot. The chart panel will be lazily created
|
||||
* the first time this function is called
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public ChartPanel getChartPanel() {
|
||||
if(chartPanel == null){
|
||||
|
||||
// Create chart
|
||||
chart = ChartFactory.createXYLineChart(this.title, xAxisLabel, yAxisLabel, data, PlotOrientation.VERTICAL, true, tooltips, false);
|
||||
|
||||
// Customize chart look and feel
|
||||
// Customize background (gray: new Color(238,238,238))
|
||||
chart.setBackgroundPaint(null);
|
||||
|
||||
// Customize legend
|
||||
chart.getLegend().setVisible(false);
|
||||
chart.getLegend().setBackgroundPaint(null);
|
||||
chart.getLegend().setBorder(0, 0, 0, 0);
|
||||
|
||||
// Customize plot area look and feel
|
||||
XYPlot plot = (XYPlot) chart.getPlot();
|
||||
plot.setBackgroundPaint(Color.white);
|
||||
plot.setDomainGridlinePaint(Color.gray);
|
||||
plot.setRangeGridlinePaint(Color.gray);
|
||||
|
||||
// Show data point
|
||||
((XYLineAndShapeRenderer)plot.getRenderer()).setBaseShapesVisible(true);
|
||||
|
||||
// Include zeros in range (x) axis
|
||||
((NumberAxis) plot.getRangeAxis()).setAutoRangeIncludesZero(false);
|
||||
|
||||
// Lazy creation of the chart panel
|
||||
chartPanel = new ChartPanel(chart);
|
||||
chartPanel.setName(title);
|
||||
|
||||
// Remove border
|
||||
chartPanel.getChart().setBorderVisible(false);
|
||||
|
||||
// Set size of chart
|
||||
chartPanel.setPreferredSize(new java.awt.Dimension(chartPanelWidth, chartPanelHeight));
|
||||
|
||||
// Add more items to the context menu
|
||||
amendContextMenu();
|
||||
|
||||
//Activate (arrow) keys
|
||||
addKeyBindings();
|
||||
}
|
||||
return chartPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change visible part of chart
|
||||
* @param translationVector
|
||||
*/
|
||||
private void moverOverPlot(XYDataItem translationVector) {
|
||||
double translatedDomainIntervalMin = chart.getXYPlot().getDomainAxis().getRange().getLowerBound() + translationVector.getX().doubleValue();
|
||||
double translatedDomainIntervalMax = chart.getXYPlot().getDomainAxis().getRange().getUpperBound() + translationVector.getX().doubleValue();
|
||||
double translatedRangeIntervalMin = chart.getXYPlot().getRangeAxis().getRange().getLowerBound() + translationVector.getY().doubleValue();
|
||||
double translatedRangeIntervalMax = chart.getXYPlot().getRangeAxis().getRange().getUpperBound() + translationVector.getY().doubleValue();
|
||||
|
||||
Range domainAxisRange = new Range(translatedDomainIntervalMin, translatedDomainIntervalMax);
|
||||
Range rangeAxisRange = new Range(translatedRangeIntervalMin, translatedRangeIntervalMax);
|
||||
//We set notify to false in the first call..
|
||||
chart.getXYPlot().getDomainAxis().setRange(domainAxisRange, true, false);
|
||||
//...and true in the last
|
||||
chart.getXYPlot().getRangeAxis().setRange(rangeAxisRange, true, true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add key bindings to chart panel
|
||||
*/
|
||||
private void addKeyBindings(){
|
||||
final String moveUpKey = "move up";
|
||||
final String moveDownKey = "move down";
|
||||
final String moveRightKey = "move right";
|
||||
final String moveLeftKey = "move left";
|
||||
|
||||
// Up arrow
|
||||
chartPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), moveUpKey);
|
||||
chartPanel.getActionMap().put(moveUpKey, new AbstractAction() {
|
||||
@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() {
|
||||
@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() {
|
||||
@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() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
moverOverPlot(new XYDataItem(- ((NumberAxis)chart.getXYPlot().getDomainAxis()).getTickUnit().getSize(), 0.0));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional items to the context menu of the frame
|
||||
*/
|
||||
public void amendContextMenu(){
|
||||
|
||||
chartPanel.getPopupMenu().addSeparator();
|
||||
|
||||
JMenu toolsMenu = new JMenu("Tools");
|
||||
chartPanel.getPopupMenu().add(toolsMenu);
|
||||
|
||||
// Manipulation function
|
||||
JMenuItem averageMenuItem = new JMenuItem("Average");
|
||||
averageMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Average average = new Average();
|
||||
for (XYSeriesP series : data.getSeries()) {
|
||||
double a = average.average(series);
|
||||
// System.out.println("Average: "+a);
|
||||
|
||||
// Remove all range markers
|
||||
Collection<?> c = chartPanel.getChart().getXYPlot().getRangeMarkers(Layer.FOREGROUND);
|
||||
if(c!=null){
|
||||
for(final Object marker: c){
|
||||
SwingUtilities.invokeLater(new Runnable() { // Avoid concurrent modification exception
|
||||
@Override
|
||||
public void run() {
|
||||
chartPanel.getChart().getXYPlot().removeRangeMarker((Marker) marker);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
final ValueMarker marker = new ValueMarker(a, Color.BLACK, new BasicStroke(1));
|
||||
marker.setLabel("Average ["+series.getKey()+"]: "+String.format("%.6f", a));
|
||||
marker.setLabelAnchor(RectangleAnchor.CENTER);
|
||||
marker.setLabelTextAnchor(TextAnchor.TOP_RIGHT);
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() { // Avoid concurrent modification exception
|
||||
@Override
|
||||
public void run() {
|
||||
chartPanel.getChart().getXYPlot().addRangeMarker(marker, Layer.FOREGROUND);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
// chartPanel.getPopupMenu().add(averageMenuItem);
|
||||
toolsMenu.add(averageMenuItem);
|
||||
|
||||
JMenuItem minimumMenuItem = new JMenuItem("Minimum");
|
||||
minimumMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Minimum minimum = new Minimum();
|
||||
for (XYSeriesP series : data.getSeries()) {
|
||||
XYDataItem m = minimum.minimum(series);
|
||||
// System.out.println("Minimum: "+m.getXValue());
|
||||
// Remove all annotation for the series
|
||||
for(Object o: chartPanel.getChart().getXYPlot().getAnnotations()){
|
||||
chartPanel.getChart().getXYPlot().removeAnnotation((XYAnnotation) o);
|
||||
}
|
||||
XYDrawableAnnotation cross = new XYDrawableAnnotation(m.getXValue(), m.getYValue(), 10.0, 10.0, new CrossAnnotation(Color.BLACK));
|
||||
cross.setToolTipText("Minimum: "+m.getXValue() +" / "+ m.getYValue());
|
||||
chartPanel.getChart().getXYPlot().addAnnotation(cross);
|
||||
}
|
||||
}
|
||||
});
|
||||
// chartPanel.getPopupMenu().add(minimumMenuItem);
|
||||
toolsMenu.add(minimumMenuItem);
|
||||
|
||||
|
||||
JMenuItem maximumMenuItem = new JMenuItem("Maximum");
|
||||
maximumMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Maximum maximum = new Maximum();
|
||||
for (XYSeriesP series : data.getSeries()) {
|
||||
XYDataItem m = maximum.maximum(series);
|
||||
// System.out.println("Maximum: "+m.getXValue());
|
||||
// Remove all annotation for the series
|
||||
for(Object o: chartPanel.getChart().getXYPlot().getAnnotations()){
|
||||
chartPanel.getChart().getXYPlot().removeAnnotation((XYAnnotation) o);
|
||||
}
|
||||
XYDrawableAnnotation cross = new XYDrawableAnnotation(m.getXValue(), m.getYValue(), 10.0, 10.0, new CrossAnnotation(Color.BLACK));
|
||||
cross.setToolTipText("Maximum: "+m.getXValue() +" / "+ m.getYValue());
|
||||
chartPanel.getChart().getXYPlot().addAnnotation(cross);
|
||||
}
|
||||
}
|
||||
});
|
||||
// chartPanel.getPopupMenu().add(maximumMenuItem);
|
||||
toolsMenu.add(maximumMenuItem);
|
||||
|
||||
JMenuItem derivativeMenuItem = new JMenuItem("Derivative");
|
||||
derivativeMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Derivative derivative = new Derivative();
|
||||
// for (XYSeriesP series : data.getSeries()) {
|
||||
// // Show derivative in same plot
|
||||
// final XYSeriesP s = derivative.derivative(series);
|
||||
// SwingUtilities.invokeLater(new Runnable() { // Avoid concurrent modification exception
|
||||
// @Override
|
||||
// public void run() {
|
||||
// data.addSeries(s); // Add Derivative
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// Show new frame
|
||||
LinePlot p = new LinePlot("Derivative - " + title, derivative.derivative(data));
|
||||
|
||||
JFrame frame = new JFrame();
|
||||
frame.setContentPane(p.getChartPanel());
|
||||
frame.pack();
|
||||
RefineryUtilities.centerFrameOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
// chartPanel.getPopupMenu().add(derivativeMenuItem);
|
||||
toolsMenu.add(derivativeMenuItem);
|
||||
|
||||
JMenuItem integralMenuItem = new JMenuItem("Integral");
|
||||
integralMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Integral integral = new Integral();
|
||||
|
||||
// Show new frame
|
||||
LinePlot p = new LinePlot("Integral - "+title, integral.integral(data));
|
||||
|
||||
JFrame frame = new JFrame();
|
||||
frame.setContentPane(p.getChartPanel());
|
||||
frame.pack();
|
||||
RefineryUtilities.centerFrameOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
// chartPanel.getPopupMenu().add(integralMenuItem);
|
||||
toolsMenu.add(integralMenuItem);
|
||||
|
||||
chartPanel.getPopupMenu().addSeparator();
|
||||
|
||||
// // Plot all series of the plot in a own plot
|
||||
// JMenuItem splitPlotMenuItem = new JMenuItem("Split");
|
||||
// splitPlotMenuItem.addActionListener(new ActionListener() {
|
||||
// @Override
|
||||
// public void actionPerformed(ActionEvent e) {
|
||||
// for (XYSeriesP serie : data.getSeries()) {
|
||||
// XYSeriesCollectionP collection = new XYSeriesCollectionP();
|
||||
// collection.addSeries(serie);
|
||||
//
|
||||
// int index = data.indexOf(serie);
|
||||
// //The right colors are not automatically assigned
|
||||
// Paint paint = chart.getXYPlot().getRenderer().getSeriesPaint(index);
|
||||
// LinePlot p = new LinePlot((String) serie.getKey(), collection);
|
||||
// // there is only one series in this plot, so we choose index 0 to assign paint
|
||||
// p.getChartPanel().getChart().getXYPlot().getRenderer().setSeriesPaint(0, paint);
|
||||
//
|
||||
// JFrame frame = new JFrame();
|
||||
// frame.setContentPane(p.getChartPanel());
|
||||
// frame.pack();
|
||||
// RefineryUtilities.centerFrameOnScreen(frame);
|
||||
// frame.setVisible(true);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// chartPanel.getPopupMenu().add(splitPlotMenuItem);
|
||||
|
||||
// Detach plot into a separate frame
|
||||
JMenuItem detachPlotMenuItem = new JMenuItem("Detach");
|
||||
detachPlotMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
LinePlot p = new LinePlot(title, data);
|
||||
|
||||
JFrame frame = new JFrame();
|
||||
frame.setContentPane(p.getChartPanel());
|
||||
frame.pack();
|
||||
RefineryUtilities.centerFrameOnScreen(frame);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
chartPanel.getPopupMenu().add(detachPlotMenuItem);
|
||||
|
||||
// Hide/Show legend
|
||||
JMenuItem hideLegendMenuItem = new JMenuItem(showLegendMenuLabel);
|
||||
hideLegendMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuItem source = (JMenuItem)(e.getSource());
|
||||
|
||||
if(source.getText() == showLegendMenuLabel){
|
||||
chart.getLegend().setVisible(true);
|
||||
source.setText(hideLegendMenuLabel);
|
||||
}
|
||||
|
||||
else if(source.getText() == hideLegendMenuLabel){
|
||||
chart.getLegend().setVisible(false);
|
||||
source.setText(showLegendMenuLabel);
|
||||
}
|
||||
}
|
||||
});
|
||||
chartPanel.getPopupMenu().add(hideLegendMenuItem);
|
||||
|
||||
// Hide/Show tooltips
|
||||
JMenuItem hideToolTipsMenuItem = new JMenuItem(hideTooltipsMenuLabel);
|
||||
if(!tooltips){
|
||||
hideToolTipsMenuItem.setText(showTooltipsMenuLabel);
|
||||
}
|
||||
hideToolTipsMenuItem.addActionListener(new ActionListener() {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuItem source = (JMenuItem)(e.getSource());
|
||||
if(source.getText() == showTooltipsMenuLabel){
|
||||
showTooltips();
|
||||
source.setText(hideTooltipsMenuLabel);
|
||||
}
|
||||
|
||||
else if(source.getText() == hideTooltipsMenuLabel){
|
||||
hideTooltips();
|
||||
source.setText(showTooltipsMenuLabel);
|
||||
}
|
||||
}
|
||||
});
|
||||
chartPanel.getPopupMenu().add(hideToolTipsMenuItem);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Show tooltips
|
||||
*/
|
||||
private void showTooltips(){
|
||||
tooltips = true;
|
||||
DecimalFormat dm = new DecimalFormat("0.##########");
|
||||
XYToolTipGenerator xYToolTipGenerator = new StandardXYToolTipGenerator( "{1}/{2}", dm, dm);
|
||||
chart.getXYPlot().getRenderer().setBaseToolTipGenerator(xYToolTipGenerator);
|
||||
chartPanel.setDisplayToolTips(true);
|
||||
chartPanel.getChartRenderingInfo().setEntityCollection(new StandardEntityCollection());
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide tooltips
|
||||
*/
|
||||
private void hideTooltips(){
|
||||
tooltips = false;
|
||||
// http://www.jfree.org/phpBB2/viewtopic.php?t=12788&highlight=redraw+speed+performance+problem
|
||||
chartPanel.getChartRenderingInfo().setEntityCollection(null);
|
||||
chart.getXYPlot().getRenderer().setBaseToolTipGenerator(null);
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.plot.Plot#update()
|
||||
*/
|
||||
@Override
|
||||
public void update() {
|
||||
// Fire chart change event
|
||||
// chart.fireChartChanged();
|
||||
if(data != null){
|
||||
SwingUtilities.invokeLater(new Runnable() { // Try to avoid concurrent modification exception
|
||||
@Override
|
||||
public void run() {
|
||||
try{
|
||||
for(XYSeriesP s:data.getSeries()){
|
||||
s.fireSeriesChanged();
|
||||
}
|
||||
}
|
||||
catch(ConcurrentModificationException e){
|
||||
logger.log(Level.WARNING, "Series got modified concurrently: "+e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see ch.psi.plot.Plot#getChart()
|
||||
*/
|
||||
@Override
|
||||
public JFreeChart getChart() {
|
||||
return chart;
|
||||
}
|
||||
|
||||
//getter and setter
|
||||
public XYSeriesCollectionP getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the xAxisLabel
|
||||
*/
|
||||
public String getxAxisLabel() {
|
||||
return xAxisLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param xAxisLabel the xAxisLabel to set
|
||||
*/
|
||||
public void setxAxisLabel(String xAxisLabel) {
|
||||
this.xAxisLabel = xAxisLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the yAxisLabel
|
||||
*/
|
||||
public String getyAxisLabel() {
|
||||
return yAxisLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param yAxisLabel the yAxisLabel to set
|
||||
*/
|
||||
public void setyAxisLabel(String yAxisLabel) {
|
||||
this.yAxisLabel = yAxisLabel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,626 @@
|
||||
/* ===========================================================
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
454
ch.psi.plot/src/main/java/ch/psi/plot/xy/XYSeriesP.java
Normal file
454
ch.psi.plot/src/main/java/ch/psi/plot/xy/XYSeriesP.java
Normal file
@@ -0,0 +1,454 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
62
ch.psi.plot/src/main/java/ch/psi/plot/xy/tools/Average.java
Normal file
62
ch.psi.plot/src/main/java/ch/psi/plot/xy/tools/Average.java
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xy.tools;
|
||||
|
||||
import org.jfree.data.xy.XYDataItem;
|
||||
|
||||
import ch.psi.plot.xy.XYSeriesCollectionP;
|
||||
import ch.psi.plot.xy.XYSeriesP;
|
||||
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class Average {
|
||||
|
||||
/**
|
||||
* Calculate average of the passed series collection
|
||||
*
|
||||
* @param collection
|
||||
* @return Average value of the collection
|
||||
*/
|
||||
public double average(XYSeriesCollectionP collection){
|
||||
double average = 0.0;
|
||||
for (XYSeriesP series : collection.getSeries()) {
|
||||
average = average + average(series);
|
||||
}
|
||||
|
||||
return average/collection.getSeriesCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate average value for a series
|
||||
* @param series
|
||||
* @return
|
||||
*/
|
||||
public double average(XYSeriesP series){
|
||||
double average = 0.0;
|
||||
for(XYDataItem item: series.getItems()){
|
||||
average = average+item.getYValue();
|
||||
}
|
||||
|
||||
return average/series.getItemCount();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package ch.psi.plot.xy.tools;
|
||||
|
||||
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 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 CrossAnnotation implements Drawable {
|
||||
|
||||
private final Color color;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
public CrossAnnotation(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(2)); // Stroke width = 2
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xy.tools;
|
||||
|
||||
import org.jfree.data.xy.XYDataItem;
|
||||
|
||||
import ch.psi.plot.xy.XYSeriesCollectionP;
|
||||
import ch.psi.plot.xy.XYSeriesP;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class Derivative {
|
||||
|
||||
/**
|
||||
* Calculate derivatives for all series in the passed collection
|
||||
* @param collection
|
||||
* @return Collection of series holding the derivatives
|
||||
*/
|
||||
public XYSeriesCollectionP derivative(XYSeriesCollectionP collection){
|
||||
XYSeriesCollectionP dcollection = new XYSeriesCollectionP();
|
||||
for (XYSeriesP series : collection.getSeries()) {
|
||||
dcollection.addSeries(derivative(series));
|
||||
}
|
||||
|
||||
return dcollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate derivative (first and/or second order) of a given function.
|
||||
* derivative is based upon 3 points.
|
||||
*
|
||||
* @param series
|
||||
* @return
|
||||
*/
|
||||
public XYSeriesP derivative(XYSeriesP series){
|
||||
|
||||
XYSeriesP derivative = new XYSeriesP(series.getKey() + "'");
|
||||
|
||||
for (int i = 1; i < series.getItemCount() - 1; i++) { // do not start at 0 but 1 - stop 1 before end
|
||||
XYDataItem m = series.getDataItem(i - 1);
|
||||
XYDataItem p = series.getDataItem(i + 1);
|
||||
|
||||
double xi = series.getDataItem(i).getXValue();
|
||||
|
||||
double ximinus1 = m.getXValue();
|
||||
double xiplus1 = p.getXValue();
|
||||
|
||||
double yiminus1 = m.getYValue();
|
||||
double yiplus1 = p.getYValue();
|
||||
|
||||
if (xiplus1-ximinus1 != 0.0) {
|
||||
double di = (yiplus1 - yiminus1) / (xiplus1-ximinus1);
|
||||
derivative.add(xi, di);
|
||||
}
|
||||
else{
|
||||
derivative.add(xi, Double.NaN);
|
||||
}
|
||||
}
|
||||
|
||||
return derivative;
|
||||
}
|
||||
}
|
||||
66
ch.psi.plot/src/main/java/ch/psi/plot/xy/tools/Integral.java
Normal file
66
ch.psi.plot/src/main/java/ch/psi/plot/xy/tools/Integral.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xy.tools;
|
||||
|
||||
import org.jfree.data.xy.XYDataItem;
|
||||
|
||||
import ch.psi.plot.xy.XYSeriesCollectionP;
|
||||
import ch.psi.plot.xy.XYSeriesP;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class Integral {
|
||||
|
||||
/**
|
||||
* Calculate integral for all series in passed collection
|
||||
* @param collection
|
||||
* @return Collection of series
|
||||
*/
|
||||
public XYSeriesCollectionP integral(XYSeriesCollectionP collection){
|
||||
XYSeriesCollectionP icollection = new XYSeriesCollectionP();
|
||||
for (XYSeriesP series : collection.getSeries()) {
|
||||
icollection.addSeries(integral(series));
|
||||
}
|
||||
|
||||
return icollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate integral of the function
|
||||
* @param series
|
||||
* @return
|
||||
*/
|
||||
public XYSeriesP integral(XYSeriesP series) {
|
||||
XYSeriesP integral = new XYSeriesP("integral-" + series.getKey());
|
||||
|
||||
double value = 0.0;
|
||||
for (int i = 1; i < series.getItemCount(); i++) { // Leave out 1. point
|
||||
XYDataItem item = series.getDataItem(i);
|
||||
XYDataItem itemM = series.getDataItem(i - 1);
|
||||
|
||||
value += (item.getXValue() - itemM.getXValue()) * (item.getYValue() + itemM.getYValue()) / 2.0;
|
||||
|
||||
integral.add(item.getXValue(), value);
|
||||
}
|
||||
return integral;
|
||||
}
|
||||
}
|
||||
52
ch.psi.plot/src/main/java/ch/psi/plot/xy/tools/Maximum.java
Normal file
52
ch.psi.plot/src/main/java/ch/psi/plot/xy/tools/Maximum.java
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xy.tools;
|
||||
|
||||
import org.jfree.data.xy.XYDataItem;
|
||||
import ch.psi.plot.xy.XYSeriesP;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class Maximum {
|
||||
|
||||
/**
|
||||
* Find maximum in series
|
||||
* @param series
|
||||
* @return maximum data point
|
||||
*/
|
||||
public XYDataItem maximum(XYSeriesP series){
|
||||
XYDataItem maximum = null;
|
||||
for(XYDataItem item: series.getItems()){
|
||||
if(maximum==null){ // set first item as maximum
|
||||
maximum = item;
|
||||
}
|
||||
else{
|
||||
if(item.getYValue()>maximum.getYValue()){
|
||||
maximum = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return maximum;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
52
ch.psi.plot/src/main/java/ch/psi/plot/xy/tools/Minimum.java
Normal file
52
ch.psi.plot/src/main/java/ch/psi/plot/xy/tools/Minimum.java
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xy.tools;
|
||||
|
||||
import org.jfree.data.xy.XYDataItem;
|
||||
import ch.psi.plot.xy.XYSeriesP;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class Minimum {
|
||||
|
||||
/**
|
||||
* Find minimum in series
|
||||
* @param series
|
||||
* @return minimum data point
|
||||
*/
|
||||
public XYDataItem minimum(XYSeriesP series){
|
||||
XYDataItem minimum = null;
|
||||
for(XYDataItem item: series.getItems()){
|
||||
if(minimum == null){
|
||||
minimum = item;
|
||||
}
|
||||
else{
|
||||
if(item.getYValue()<minimum.getYValue()){
|
||||
minimum = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return minimum;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
87
ch.psi.plot/src/main/java/ch/psi/plot/xyz/ColorManager.java
Normal file
87
ch.psi.plot/src/main/java/ch/psi/plot/xyz/ColorManager.java
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class ColorManager {
|
||||
|
||||
/**
|
||||
* Get color for a given value
|
||||
* @param v Value to get the color for
|
||||
* @param vmin Lower end value mapped to the lower end of the color map
|
||||
* @param vmax Upper end value mapped to the upper end of the color map
|
||||
* @return Mapped color for the specified value
|
||||
*/
|
||||
public static Color getColourForValue(double v, double vmin, double vmax)
|
||||
{
|
||||
// Standard algorithm for hot-cold color gradient (copied from
|
||||
// http://local.wasp.uwa.edu.au/~pbourke/texture_colour/colourramp/)
|
||||
|
||||
//Init color to white
|
||||
double r = 1.0;
|
||||
double g = 1.0;
|
||||
double b = 1.0;
|
||||
|
||||
double dv;
|
||||
|
||||
if (v < vmin)
|
||||
v = vmin;
|
||||
if (v > vmax)
|
||||
v = vmax;
|
||||
dv = vmax - vmin;
|
||||
|
||||
if (v < (vmin + 0.25 * dv)) {
|
||||
r = 0.0;
|
||||
g = 4 * (v - vmin) / dv;
|
||||
} else if (v < (vmin + 0.5 * dv)) {
|
||||
r = 0.0;
|
||||
b = 1 + 4 * (vmin + 0.25 * dv - v) / dv;
|
||||
} else if (v < (vmin + 0.75 * dv)) {
|
||||
r = 4 * (v - vmin - 0.5 * dv) / dv;
|
||||
b = 0.0;
|
||||
} else {
|
||||
g = 1 + 4 * (vmin + 0.75 * dv - v) / dv;
|
||||
b = 0.0;
|
||||
}
|
||||
|
||||
return new Color( new Double(255.0*r).intValue(), new Double(255.0*g).intValue(), new Double(255.0*b).intValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a gray value for a given value
|
||||
* @param value the value (must be within the range specified by the
|
||||
* lower and upper bounds for the scale).
|
||||
*
|
||||
* @return a gray scale color.
|
||||
*/
|
||||
public static Color getGrayForValue(double value, double vmin, double vmax) {
|
||||
double v = Math.max(value, vmin);
|
||||
v = Math.min(v, vmax);
|
||||
int g = (int) ((v - vmin) / (vmax- vmin) * 255.0);
|
||||
// FIXME: it probably makes sense to allocate an array of 256 Colors
|
||||
// and lazily populate this array...
|
||||
return new Color(g, g, g);
|
||||
}
|
||||
}
|
||||
183
ch.psi.plot/src/main/java/ch/psi/plot/xyz/ManualScaleDialog.java
Normal file
183
ch.psi.plot/src/main/java/ch/psi/plot/xyz/ManualScaleDialog.java
Normal file
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
*
|
||||
* 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 {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
379
ch.psi.plot/src/main/java/ch/psi/plot/xyz/MatrixPlot.java
Normal file
379
ch.psi.plot/src/main/java/ch/psi/plot/xyz/MatrixPlot.java
Normal file
@@ -0,0 +1,379 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
194
ch.psi.plot/src/main/java/ch/psi/plot/xyz/MatrixPlotData.java
Normal file
194
ch.psi.plot/src/main/java/ch/psi/plot/xyz/MatrixPlotData.java
Normal file
@@ -0,0 +1,194 @@
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
//import java.util.Arrays;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jfree.data.xy.DefaultXYZDataset;
|
||||
import org.jfree.data.xy.XYZDataset;
|
||||
|
||||
/**
|
||||
* PlotData implementation optimized for matrix data.
|
||||
* ...
|
||||
*/
|
||||
public class MatrixPlotData {
|
||||
|
||||
// Get Logger
|
||||
private static final Logger logger = Logger.getLogger(MatrixPlotData.class.getName());
|
||||
|
||||
private final double minX;
|
||||
private final double maxX;
|
||||
private final int numberOfBinsX;
|
||||
private final double binWidthX;
|
||||
|
||||
private final double minY;
|
||||
private final double maxY;
|
||||
private final int numberOfBinsY;
|
||||
private final double binWidthY;
|
||||
|
||||
private final double axisMinX;
|
||||
private final double axisMaxX;
|
||||
private final double axisMinY;
|
||||
private final double axisMaxY;
|
||||
|
||||
|
||||
double[] xvalues;
|
||||
double[] yvalues;
|
||||
double[] zvalues;
|
||||
|
||||
private XYZDataset data;
|
||||
|
||||
public MatrixPlotData(double minX, double maxX, int nX, double minY, double maxY, int nY){
|
||||
|
||||
this.minX = minX;
|
||||
this.maxX = maxX;
|
||||
this.numberOfBinsX = nX;
|
||||
|
||||
this.minY = minY;
|
||||
this.maxY = maxY;
|
||||
this.numberOfBinsY = nY;
|
||||
|
||||
this.binWidthX = (maxX - minX)/(double) (numberOfBinsX - 1);
|
||||
this.binWidthY = (maxY - minY)/(double) (numberOfBinsY - 1);
|
||||
|
||||
// The axis min and max values need to be half a bin larger. Otherwise the outer pixels
|
||||
// will not be plotted correctly (half of the pixel is missing)
|
||||
this.axisMinX = minX - 0.5*binWidthX;
|
||||
this.axisMaxX = maxX + 0.5*binWidthX;
|
||||
|
||||
this.axisMinY = minY - 0.5*binWidthY;
|
||||
this.axisMaxY = maxY + 0.5*binWidthY;
|
||||
|
||||
int arraylength = numberOfBinsX*numberOfBinsY;
|
||||
xvalues = new double[arraylength];
|
||||
yvalues = new double[arraylength];
|
||||
zvalues = new double[arraylength];
|
||||
|
||||
Arrays.fill(xvalues, Double.NEGATIVE_INFINITY);
|
||||
Arrays.fill(yvalues, Double.NEGATIVE_INFINITY);
|
||||
Arrays.fill(zvalues, Double.NEGATIVE_INFINITY);
|
||||
|
||||
double[][] dataArray = new double[][] {xvalues, yvalues, zvalues};
|
||||
|
||||
|
||||
//Create the XYDataset (org.jfree), not to be confused with the ch.psi dataSet)
|
||||
data = new DefaultXYZDataset();
|
||||
((DefaultXYZDataset)data).addSeries("Data" , dataArray);
|
||||
}
|
||||
|
||||
public XYZDataset getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void addData(final double x, final double y, final double z) {
|
||||
final int xBin = ((int) ((x - axisMinX)/binWidthX));
|
||||
final int yBin = ((int) ((y - axisMinY)/binWidthY));
|
||||
final int index = yBin * numberOfBinsX + xBin;
|
||||
|
||||
try{
|
||||
//x Value is column, y value is row
|
||||
xvalues[index] = x;
|
||||
yvalues[index] = y;
|
||||
zvalues[index] = z;
|
||||
}
|
||||
catch(ArrayIndexOutOfBoundsException e){
|
||||
logger.log(Level.WARNING, "Unable to add data point at index "+index+" [x: "+x+" y: "+y+"]", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
Arrays.fill(xvalues, Double.NEGATIVE_INFINITY);
|
||||
Arrays.fill(yvalues, Double.NEGATIVE_INFINITY);
|
||||
Arrays.fill(zvalues, Double.NEGATIVE_INFINITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the axisMinX
|
||||
*/
|
||||
public double getAxisMinX() {
|
||||
return axisMinX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the axisMinY
|
||||
*/
|
||||
public double getAxisMinY() {
|
||||
return axisMinY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the binWidthX
|
||||
*/
|
||||
public double getBinWidthX() {
|
||||
return binWidthX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the binWidthY
|
||||
*/
|
||||
public double getBinWidthY() {
|
||||
return binWidthY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the minX
|
||||
*/
|
||||
public double getMinX() {
|
||||
return minX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the maxX
|
||||
*/
|
||||
public double getMaxX() {
|
||||
return maxX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the minY
|
||||
*/
|
||||
public double getMinY() {
|
||||
return minY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the maxY
|
||||
*/
|
||||
public double getMaxY() {
|
||||
return maxY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the axisMaxX
|
||||
*/
|
||||
public double getAxisMaxX() {
|
||||
return axisMaxX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the axisMaxY
|
||||
*/
|
||||
public double getAxisMaxY() {
|
||||
return axisMaxY;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the numberOfBinsX
|
||||
*/
|
||||
public int getNumberOfBinsX() {
|
||||
return numberOfBinsX;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the numberOfBinsY
|
||||
*/
|
||||
public int getNumberOfBinsY() {
|
||||
return numberOfBinsY;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
*
|
||||
* Copyright 2010 Paul Scherrer Institute. All rights reserved.
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful,
|
||||
* but without any warranty; without even the implied warranty of
|
||||
* merchantability or fitness for a particular purpose. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this code. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.psi.plot.xyz;
|
||||
|
||||
import org.jfree.data.xy.XYZDataset;
|
||||
|
||||
/**
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class XYZDatasetUtil {
|
||||
|
||||
/**
|
||||
* Find the minimum and maximum value of the dataset
|
||||
* @param dataset Dataset to find the min and max value
|
||||
* @return Double array with min in element 0 and max in element 1
|
||||
*/
|
||||
public static double[] minMaxZValue(XYZDataset dataset){
|
||||
|
||||
double min = Double.NaN;
|
||||
double max = Double.NaN;
|
||||
|
||||
if(dataset != null){
|
||||
int seriesCount = dataset.getSeriesCount();
|
||||
for(int s=0;s<seriesCount;s++){
|
||||
int itemCount = dataset.getItemCount(s);
|
||||
boolean first = true;
|
||||
for(int i=0;i<itemCount;i++){
|
||||
|
||||
double v = dataset.getZValue(s, i);
|
||||
if(v!=Double.NEGATIVE_INFINITY){
|
||||
if(first){
|
||||
min=v;
|
||||
max=v;
|
||||
first=false;
|
||||
}
|
||||
else{
|
||||
if(v>max){
|
||||
max=v;
|
||||
}
|
||||
if(v<min){
|
||||
min=v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double[] value = new double[2];
|
||||
value[0]=min;
|
||||
value[1]=max;
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
0
ch.psi.plot/src/main/resources/.gitignore
vendored
Normal file
0
ch.psi.plot/src/main/resources/.gitignore
vendored
Normal file
149
ch.psi.plot/src/test/java/DualAxisChart.java
Normal file
149
ch.psi.plot/src/test/java/DualAxisChart.java
Normal file
@@ -0,0 +1,149 @@
|
||||
import java.awt.Color;
|
||||
|
||||
import java.awt.Font;
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.axis.CategoryAxis;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.axis.ValueAxis;
|
||||
import org.jfree.chart.labels.StandardCategoryToolTipGenerator;
|
||||
import org.jfree.chart.plot.CategoryPlot;
|
||||
import org.jfree.chart.plot.CombinedDomainCategoryPlot;
|
||||
import org.jfree.chart.renderer.category.BarRenderer;
|
||||
import org.jfree.chart.renderer.category.CategoryItemRenderer;
|
||||
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
|
||||
import org.jfree.data.category.CategoryDataset;
|
||||
import org.jfree.data.category.DefaultCategoryDataset;
|
||||
import org.jfree.ui.ApplicationFrame;
|
||||
import org.jfree.ui.RefineryUtilities;
|
||||
|
||||
public class DualAxisChart extends ApplicationFrame {
|
||||
|
||||
final String team1 = "1st Team";
|
||||
final String team2 = "2nd Team";
|
||||
|
||||
public DualAxisChart(String titel) {
|
||||
super(titel);
|
||||
|
||||
final JFreeChart chart = createChart();
|
||||
final ChartPanel chartPanel = new ChartPanel(chart);
|
||||
chartPanel.setPreferredSize(new java.awt.Dimension(600, 450));
|
||||
setContentPane(chartPanel);
|
||||
}
|
||||
|
||||
public double[][] run() {
|
||||
double[][] run = new double[][] { { 10, 6, 2, 4, 7, 2, 8, 12, 9, 4 }, { 2, 6, 3, 8, 1, 6, 4, 9, 2, 10 } };
|
||||
return run;
|
||||
}
|
||||
|
||||
private CategoryDataset createRunDataset1() {
|
||||
final DefaultCategoryDataset dataset = new DefaultCategoryDataset();
|
||||
|
||||
double[] run = run()[0];
|
||||
|
||||
for (int i = 0; i < run.length; i++) {
|
||||
dataset.addValue(run[i], team1 + " Run", "" + (i + 1));
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
|
||||
private CategoryDataset createRunDataset2() {
|
||||
final DefaultCategoryDataset dataset = new DefaultCategoryDataset();
|
||||
|
||||
double[] run = run()[1];
|
||||
|
||||
for (int i = 0; i < run.length; i++) {
|
||||
dataset.addValue(run[i], team2 + " Run", "" + (i + 1));
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
|
||||
private CategoryDataset createRunRateDataset1() {
|
||||
final DefaultCategoryDataset dataset = new DefaultCategoryDataset();
|
||||
|
||||
double[] run = run()[0];
|
||||
float num = 0;
|
||||
|
||||
for (int i = 0; i < run.length; i++) {
|
||||
num += run[i];
|
||||
dataset.addValue(num / (i + 1), team1 + " Runrate", "" + (i + 1));
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
|
||||
private CategoryDataset createRunRateDataset2() {
|
||||
final DefaultCategoryDataset dataset = new DefaultCategoryDataset();
|
||||
|
||||
double[] run = run()[1];
|
||||
float num = 0;
|
||||
|
||||
for (int i = 0; i < run.length; i++) {
|
||||
num += run[i];
|
||||
dataset.addValue(num / (i + 1), team2 + " Runrate", "" + (i + 1));
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
|
||||
private JFreeChart createChart() {
|
||||
|
||||
final CategoryDataset dataset1 = createRunDataset1();
|
||||
final NumberAxis rangeAxis1 = new NumberAxis("Run");
|
||||
rangeAxis1.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
|
||||
final BarRenderer renderer1 = new BarRenderer();
|
||||
renderer1.setSeriesPaint(0, Color.red);
|
||||
renderer1.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator());
|
||||
final CategoryPlot subplot1 = new CategoryPlot(dataset1, null, rangeAxis1, renderer1);
|
||||
subplot1.setDomainGridlinesVisible(true);
|
||||
|
||||
final CategoryDataset runrateDataset1 = createRunRateDataset1();
|
||||
final ValueAxis axis2 = new NumberAxis("Run Rate");
|
||||
subplot1.setRangeAxis(1, axis2);
|
||||
subplot1.setDataset(1, runrateDataset1);
|
||||
subplot1.mapDatasetToRangeAxis(1, 1);
|
||||
final CategoryItemRenderer runrateRenderer1 = new LineAndShapeRenderer();
|
||||
runrateRenderer1.setSeriesPaint(0, Color.red);
|
||||
|
||||
subplot1.setForegroundAlpha(0.7f);
|
||||
subplot1.setRenderer(0, renderer1);
|
||||
subplot1.setRenderer(1, runrateRenderer1);
|
||||
|
||||
final CategoryDataset dataset2 = createRunDataset2();
|
||||
final NumberAxis rangeAxis2 = new NumberAxis("Run");
|
||||
rangeAxis2.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
|
||||
final BarRenderer renderer2 = new BarRenderer();
|
||||
renderer2.setSeriesPaint(0, Color.blue);
|
||||
renderer2.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator());
|
||||
final CategoryPlot subplot2 = new CategoryPlot(dataset2, null, rangeAxis2, renderer2);
|
||||
subplot2.setDomainGridlinesVisible(true);
|
||||
|
||||
final CategoryDataset runrateDataset2 = createRunRateDataset2();
|
||||
final ValueAxis axis3 = new NumberAxis("Run Rate");
|
||||
subplot2.setRangeAxis(1, axis3);
|
||||
subplot2.setDataset(1, runrateDataset2);
|
||||
subplot2.mapDatasetToRangeAxis(1, 1);
|
||||
final CategoryItemRenderer runrateRenderer2 = new LineAndShapeRenderer();
|
||||
runrateRenderer2.setSeriesPaint(0, Color.blue);
|
||||
|
||||
subplot2.setForegroundAlpha(0.7f);
|
||||
subplot2.setRenderer(0, renderer2);
|
||||
subplot2.setRenderer(1, runrateRenderer2);
|
||||
|
||||
final CategoryAxis domainAxis = new CategoryAxis("Over");
|
||||
final CombinedDomainCategoryPlot plot = new CombinedDomainCategoryPlot(domainAxis);
|
||||
|
||||
plot.add(subplot1, 1);
|
||||
plot.add(subplot2, 1);
|
||||
|
||||
final JFreeChart chart = new JFreeChart("Score Bord", new Font("SansSerif", Font.BOLD, 12), plot, true);
|
||||
return chart;
|
||||
}
|
||||
|
||||
public static void main(final String[] args) {
|
||||
|
||||
final String title = "Score Bord";
|
||||
final DualAxisChart chart = new DualAxisChart(title);
|
||||
chart.pack();
|
||||
RefineryUtilities.centerFrameOnScreen(chart);
|
||||
chart.setVisible(true);
|
||||
}
|
||||
}
|
||||
148
ch.psi.plot/src/test/java/DualAxisChart2.java
Normal file
148
ch.psi.plot/src/test/java/DualAxisChart2.java
Normal file
@@ -0,0 +1,148 @@
|
||||
import java.awt.Color;
|
||||
|
||||
import java.awt.Font;
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.axis.CategoryAxis;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.axis.ValueAxis;
|
||||
import org.jfree.chart.labels.StandardCategoryToolTipGenerator;
|
||||
import org.jfree.chart.plot.CategoryPlot;
|
||||
import org.jfree.chart.plot.CombinedDomainCategoryPlot;
|
||||
import org.jfree.chart.renderer.category.CategoryItemRenderer;
|
||||
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
|
||||
import org.jfree.data.category.CategoryDataset;
|
||||
import org.jfree.data.category.DefaultCategoryDataset;
|
||||
import org.jfree.ui.ApplicationFrame;
|
||||
import org.jfree.ui.RefineryUtilities;
|
||||
|
||||
public class DualAxisChart2 extends ApplicationFrame {
|
||||
|
||||
final String team1 = "1st Team";
|
||||
final String team2 = "2nd Team";
|
||||
|
||||
public DualAxisChart2(String titel) {
|
||||
super(titel);
|
||||
|
||||
final JFreeChart chart = createChart();
|
||||
final ChartPanel chartPanel = new ChartPanel(chart);
|
||||
chartPanel.setPreferredSize(new java.awt.Dimension(600, 450));
|
||||
setContentPane(chartPanel);
|
||||
}
|
||||
|
||||
public double[][] run() {
|
||||
double[][] run = new double[][] { { 10, 6, 2, 4, 7, 2, 8, 12, 9, 4 }, { 2, 6, 3, 8, 1, 6, 4, 9, 2, 10 } };
|
||||
return run;
|
||||
}
|
||||
|
||||
private CategoryDataset createRunDataset1() {
|
||||
final DefaultCategoryDataset dataset = new DefaultCategoryDataset();
|
||||
|
||||
double[] run = run()[0];
|
||||
|
||||
for (int i = 0; i < run.length; i++) {
|
||||
dataset.addValue(run[i], team1 + " Run", "" + (i + 1));
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
|
||||
private CategoryDataset createRunDataset2() {
|
||||
final DefaultCategoryDataset dataset = new DefaultCategoryDataset();
|
||||
|
||||
double[] run = run()[1];
|
||||
|
||||
for (int i = 0; i < run.length; i++) {
|
||||
dataset.addValue(run[i], team2 + " Run", "" + (i + 1));
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
|
||||
private CategoryDataset createRunRateDataset1() {
|
||||
final DefaultCategoryDataset dataset = new DefaultCategoryDataset();
|
||||
|
||||
double[] run = run()[0];
|
||||
float num = 0;
|
||||
|
||||
for (int i = 0; i < run.length; i++) {
|
||||
num += run[i];
|
||||
dataset.addValue(num / (i + 1), team1 + " Runrate", "" + (i + 1));
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
|
||||
private CategoryDataset createRunRateDataset2() {
|
||||
final DefaultCategoryDataset dataset = new DefaultCategoryDataset();
|
||||
|
||||
double[] run = run()[1];
|
||||
float num = 0;
|
||||
|
||||
for (int i = 0; i < run.length; i++) {
|
||||
num += run[i];
|
||||
dataset.addValue(num / (i + 1), team2 + " Runrate", "" + (i + 1));
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
|
||||
private JFreeChart createChart() {
|
||||
|
||||
final CategoryDataset dataset1 = createRunDataset1();
|
||||
final NumberAxis rangeAxis1 = new NumberAxis("Run");
|
||||
rangeAxis1.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
|
||||
final LineAndShapeRenderer renderer1 = new LineAndShapeRenderer();
|
||||
renderer1.setSeriesPaint(0, Color.red);
|
||||
renderer1.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator());
|
||||
final CategoryPlot subplot1 = new CategoryPlot(dataset1, null, rangeAxis1, renderer1);
|
||||
subplot1.setDomainGridlinesVisible(true);
|
||||
|
||||
final CategoryDataset runrateDataset1 = createRunRateDataset1();
|
||||
final ValueAxis axis2 = new NumberAxis("Run Rate");
|
||||
subplot1.setRangeAxis(1, axis2);
|
||||
subplot1.setDataset(1, runrateDataset1);
|
||||
subplot1.mapDatasetToRangeAxis(1, 1);
|
||||
final CategoryItemRenderer runrateRenderer1 = new LineAndShapeRenderer();
|
||||
runrateRenderer1.setSeriesPaint(0, Color.red);
|
||||
|
||||
subplot1.setForegroundAlpha(0.7f);
|
||||
subplot1.setRenderer(0, renderer1);
|
||||
subplot1.setRenderer(1, runrateRenderer1);
|
||||
|
||||
final CategoryDataset dataset2 = createRunDataset2();
|
||||
final NumberAxis rangeAxis2 = new NumberAxis("Run");
|
||||
rangeAxis2.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
|
||||
final LineAndShapeRenderer renderer2 = new LineAndShapeRenderer();
|
||||
renderer2.setSeriesPaint(0, Color.blue);
|
||||
renderer2.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator());
|
||||
final CategoryPlot subplot2 = new CategoryPlot(dataset2, null, rangeAxis2, renderer2);
|
||||
subplot2.setDomainGridlinesVisible(true);
|
||||
|
||||
final CategoryDataset runrateDataset2 = createRunRateDataset2();
|
||||
final ValueAxis axis3 = new NumberAxis("Run Rate");
|
||||
subplot2.setRangeAxis(1, axis3);
|
||||
subplot2.setDataset(1, runrateDataset2);
|
||||
subplot2.mapDatasetToRangeAxis(1, 1);
|
||||
final CategoryItemRenderer runrateRenderer2 = new LineAndShapeRenderer();
|
||||
runrateRenderer2.setSeriesPaint(0, Color.blue);
|
||||
|
||||
subplot2.setForegroundAlpha(0.7f);
|
||||
subplot2.setRenderer(0, renderer2);
|
||||
subplot2.setRenderer(1, runrateRenderer2);
|
||||
|
||||
final CategoryAxis domainAxis = new CategoryAxis("Over");
|
||||
final CombinedDomainCategoryPlot plot = new CombinedDomainCategoryPlot(domainAxis);
|
||||
|
||||
plot.add(subplot1, 1);
|
||||
plot.add(subplot2, 1);
|
||||
|
||||
final JFreeChart chart = new JFreeChart("Score Bord", new Font("SansSerif", Font.BOLD, 12), plot, true);
|
||||
return chart;
|
||||
}
|
||||
|
||||
public static void main(final String[] args) {
|
||||
|
||||
final String title = "Score Bord";
|
||||
final DualAxisChart2 chart = new DualAxisChart2(title);
|
||||
chart.pack();
|
||||
RefineryUtilities.centerFrameOnScreen(chart);
|
||||
chart.setVisible(true);
|
||||
}
|
||||
}
|
||||
316
ch.psi.plot/src/test/java/ch/psi/plot/xy/LinePlotTest.java
Normal file
316
ch.psi.plot/src/test/java/ch/psi/plot/xy/LinePlotTest.java
Normal file
@@ -0,0 +1,316 @@
|
||||
/**
|
||||
*
|
||||
* 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;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.LineNumberReader;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.ui.RefineryUtilities;
|
||||
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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
|
||||
XYSeriesCollectionP data = new XYSeriesCollectionP();
|
||||
XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 1000, false);
|
||||
|
||||
generator.reset();
|
||||
|
||||
String seriesName = "test";
|
||||
XYSeriesP serie = new XYSeriesP(seriesName);
|
||||
data.addSeries(serie);
|
||||
|
||||
double[] xy;
|
||||
while ((xy = generator.getNewPoint()) != null) {
|
||||
serie.add(xy[0], xy[1]); // Add t to the y value to see the plotted line
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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)) ;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
for (int t = 0; t < 1000; t++) {
|
||||
// Reset generator
|
||||
generator.reset();
|
||||
|
||||
String seriesName = seriesBaseName + " - " + t;
|
||||
final XYSeriesP f = new XYSeriesP(seriesName);
|
||||
data.addSeries(f);
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("DONE");
|
||||
|
||||
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) {
|
||||
f.add(xy[0], xy[1]+count, false); // No notification send - use this if all data is available before plotting
|
||||
}
|
||||
|
||||
System.out.println("DONE");
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
*
|
||||
* 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.generator;
|
||||
|
||||
/**
|
||||
* Generator to generate absorption data
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class Absorption implements XYGeneratorFunction{
|
||||
|
||||
@Override
|
||||
public double generate(double x) {
|
||||
|
||||
final double startedge =10.0;
|
||||
final double frequency = 10.0;
|
||||
final double slope = 0.05;
|
||||
final double offset = 1.0;
|
||||
|
||||
double y= offset - slope*x;
|
||||
if (x < startedge){
|
||||
return y;
|
||||
}
|
||||
else{
|
||||
return y + offset + 0.5*Math.exp(-(x-startedge))*Math.sin(frequency*(x-startedge));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
*
|
||||
* 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.generator;
|
||||
|
||||
/**
|
||||
* Generator to generate affine data
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class Affine implements XYGeneratorFunction{
|
||||
|
||||
@Override
|
||||
public double generate(double x) {
|
||||
final double slope = 0.4;
|
||||
final double offset = 0.0;
|
||||
return offset + slope*x;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
*
|
||||
* 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.generator;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Generator to generate noise data
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class Noise implements XYGeneratorFunction{
|
||||
|
||||
private Random random;
|
||||
private double range;
|
||||
|
||||
/**
|
||||
* Constructor - Noise generation function
|
||||
* @param range Size of the maximum noise range (e.g step size of x)
|
||||
*/
|
||||
public Noise(double range){
|
||||
this.range = range;
|
||||
random = new Random();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double generate(double x) {
|
||||
return(x + range*(random.nextDouble() - 0.5));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
*
|
||||
* 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.generator;
|
||||
|
||||
/**
|
||||
* Generator to generate sinus wave
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class Sinus implements XYGeneratorFunction{
|
||||
|
||||
private final double frequency;
|
||||
|
||||
/**
|
||||
* Constructor - Sinus generator
|
||||
* @param frequency Frequency of Sinus wave
|
||||
*/
|
||||
public Sinus(double frequency){
|
||||
this.frequency = frequency;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double generate(double x) {
|
||||
return Math.sin(frequency*x);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
*
|
||||
* 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.generator;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Generator to generate random numbers
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class UniformRandom implements XYGeneratorFunction{
|
||||
|
||||
private final Random random;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public UniformRandom(){
|
||||
random = new Random();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double generate(double x) {
|
||||
return(random.nextGaussian());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package ch.psi.plot.xy.generator;
|
||||
|
||||
|
||||
/**
|
||||
* Converter to convert a simple text file to a xy series
|
||||
*/
|
||||
public class XYGenerator {
|
||||
|
||||
private final double start;
|
||||
private final double stepSize;
|
||||
private final int steps;
|
||||
|
||||
/**
|
||||
* Current position
|
||||
*/
|
||||
private double currentStep;
|
||||
|
||||
|
||||
/**
|
||||
* Function to use by the generator
|
||||
*/
|
||||
private final XYGeneratorFunction function;
|
||||
/**
|
||||
* Noise generator
|
||||
*/
|
||||
private final Noise noiseGenerator;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param function Function to use for generating data
|
||||
* @param noise Add some noise to the generated x value
|
||||
*/
|
||||
public XYGenerator(XYGeneratorFunction function, double start, double stepSize, int steps, boolean noise){
|
||||
this.function = function;
|
||||
this.start = start;
|
||||
this.steps = steps;
|
||||
this.currentStep=0;
|
||||
this.stepSize = stepSize;
|
||||
|
||||
if(noise){
|
||||
this.noiseGenerator = new Noise(stepSize);
|
||||
}
|
||||
else{
|
||||
this.noiseGenerator = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get new data point
|
||||
* @return Returns null if there is no new point. Otherwise array of double (of size 2) where array[0] == x
|
||||
* and array[1] == y
|
||||
*/
|
||||
public double[] getNewPoint(){
|
||||
|
||||
if(currentStep>steps){
|
||||
return null;
|
||||
}
|
||||
|
||||
double x = start+(stepSize*currentStep);
|
||||
if(noiseGenerator != null){
|
||||
x = noiseGenerator.generate(x);
|
||||
}
|
||||
currentStep++;
|
||||
|
||||
// Get y value for x
|
||||
double y = function.generate(x);
|
||||
|
||||
return(new double[] {x, y});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset generator to start settings
|
||||
*/
|
||||
public void reset(){
|
||||
this.currentStep = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
*
|
||||
* 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.generator;
|
||||
|
||||
/**
|
||||
* XY Generator Interface
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public interface XYGeneratorFunction {
|
||||
/**
|
||||
* Calculate y value for given x value
|
||||
* @param x
|
||||
* @return
|
||||
*/
|
||||
public double generate(double x);
|
||||
}
|
||||
211
ch.psi.plot/src/test/java/ch/psi/plot/xyz/MatrixPlotTest.java
Normal file
211
ch.psi.plot/src/test/java/ch/psi/plot/xyz/MatrixPlotTest.java
Normal file
@@ -0,0 +1,211 @@
|
||||
/**
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package ch.psi.plot.xyz.generator;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import ch.psi.plot.xy.generator.Noise;
|
||||
import ch.psi.plot.xyz.MatrixPlotData;
|
||||
|
||||
/**
|
||||
* Converter object converting a file into PixelPlot data
|
||||
*/
|
||||
public class DataGenerator implements Runnable {
|
||||
|
||||
private static Logger logger = Logger.getLogger(DataGenerator.class.getName());
|
||||
|
||||
private final MatrixPlotData data;
|
||||
private XYZGeneratorFunction function;
|
||||
|
||||
double xMin = 0;
|
||||
double xMax = 1200;//120
|
||||
int xNStep = 1200;//120
|
||||
|
||||
double yMin = 0;
|
||||
double yMax = 1200;//120
|
||||
int yNStep = 1200;//120
|
||||
|
||||
private Noise noiseFunctionX = null;
|
||||
private Noise noiseFunctionY = null;
|
||||
|
||||
public DataGenerator(XYZGeneratorFunction function){
|
||||
this(function, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param function Function generator to use to generate value
|
||||
* @param type Type of plot (Pixel or Matrix)
|
||||
*/
|
||||
public DataGenerator(XYZGeneratorFunction function, boolean noise, boolean metaDataAvailable){
|
||||
this.function = function;
|
||||
|
||||
data = new MatrixPlotData(xMin,xMax,xNStep,yMin,yMax,yNStep);
|
||||
|
||||
if(noise){
|
||||
noiseFunctionX = new Noise(data.getBinWidthX());
|
||||
noiseFunctionY = new Noise(data.getBinWidthY());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update data
|
||||
* @throws NumberFormatException
|
||||
* @throws Exception
|
||||
*/
|
||||
public void generateData() {
|
||||
|
||||
double x;
|
||||
double y;
|
||||
//Y Axis
|
||||
for(int i=0; i < yNStep; i++){
|
||||
y = yMin + (i*data.getBinWidthY());
|
||||
if(noiseFunctionY!=null){
|
||||
y=noiseFunctionY.generate(y);
|
||||
}
|
||||
|
||||
// X Axis
|
||||
for(int t=0;t<xNStep; t++){
|
||||
x = xMin + (t*data.getBinWidthX());
|
||||
if(noiseFunctionX!=null){
|
||||
x=noiseFunctionX.generate(x);
|
||||
}
|
||||
|
||||
logger.fine("x: "+x+" y: "+y+" z: "+function.generate(x, y));
|
||||
data.addData(x, y, function.generate(x, y));
|
||||
// try {
|
||||
// Thread.sleep(1);
|
||||
// } catch (InterruptedException e1) {
|
||||
// e1.printStackTrace();
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public MatrixPlotData getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
generateData();
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
*
|
||||
* 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.generator;
|
||||
|
||||
/**
|
||||
* Generator function that generates a gauss distribution
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class Gauss2D implements XYZGeneratorFunction{
|
||||
|
||||
private double centerX;
|
||||
private double centerY;
|
||||
private double sigmaX;
|
||||
private double sigmaY;
|
||||
private double amplitude;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param centerX
|
||||
* @param centerY
|
||||
* @param sigmaX
|
||||
* @param sigmaY
|
||||
* @param amplitude
|
||||
*/
|
||||
public Gauss2D(double centerX, double centerY, double sigmaX, double sigmaY, double amplitude){
|
||||
this.centerX = centerX;
|
||||
this.centerY = centerY;
|
||||
this.sigmaX = sigmaX;
|
||||
this.sigmaY = sigmaY;
|
||||
this.amplitude = amplitude;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public double generate(double x, double y) {
|
||||
return amplitude*Math.exp(-Math.pow(x - centerX, 2.0)/sigmaX)* Math.exp(-Math.pow(y - centerY, 2.0)/sigmaY);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
*
|
||||
* 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.generator;
|
||||
|
||||
/**
|
||||
* Generator function that generates a 2D Sinus
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class Sinus2D implements XYZGeneratorFunction{
|
||||
|
||||
private double frequencyX;
|
||||
private double frequencyY;
|
||||
|
||||
/**
|
||||
* Constructor - Sinus generator
|
||||
* @param frequencyX Frequency of Sinus wave along x axis
|
||||
* @param frequencyY Frequency of Sinus wave along y axis
|
||||
*/
|
||||
public Sinus2D(double frequencyX, double frequencyY) {
|
||||
super();
|
||||
this.frequencyX = frequencyX;
|
||||
this.frequencyY = frequencyY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double generate(double x, double y) {
|
||||
return Math.sin(frequencyX * x) * Math.sin(frequencyY * y);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
*
|
||||
* 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.generator;
|
||||
|
||||
/**
|
||||
* Generator function that generates a slope
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class Slope2D implements XYZGeneratorFunction{
|
||||
|
||||
@Override
|
||||
public double generate(double x, double y) {
|
||||
return x + y;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
*
|
||||
* 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.generator;
|
||||
|
||||
/**
|
||||
* Generator function that is generating a spherical wave
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public class SphericalWave implements XYZGeneratorFunction {
|
||||
|
||||
private double centerX;
|
||||
private double centerY;
|
||||
private double kx;
|
||||
private double ky;
|
||||
private double amplitude;
|
||||
|
||||
/**
|
||||
* Constructor - Default constructor using default values for the wave
|
||||
*/
|
||||
public SphericalWave(){
|
||||
this(5.0, 5.0, 1.0, 1.0, 1.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param centerX
|
||||
* @param centerY
|
||||
* @param kx
|
||||
* @param ky
|
||||
* @param amplitude
|
||||
*/
|
||||
public SphericalWave(double centerX, double centerY, double kx, double ky,double amplitude){
|
||||
this.centerX = centerX;
|
||||
this.centerX = centerX;
|
||||
this.kx = centerX;
|
||||
this.ky = centerY;
|
||||
this.amplitude = amplitude;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public double generate(double x, double y) {
|
||||
return amplitude*Math.pow(Math.sin( Math.pow(kx*(x-centerX),2.0) + Math.pow(ky*(y-centerY), 2.0)) ,2.0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package ch.psi.plot.xyz.generator;
|
||||
|
||||
import ch.psi.plot.xy.generator.Noise;
|
||||
|
||||
|
||||
/**
|
||||
* Converter to convert a simple text file to a xy series
|
||||
*/
|
||||
public class XYZGenerator {
|
||||
|
||||
// X Settings
|
||||
private final double startX;
|
||||
private final double stepSizeX;
|
||||
private final int stepsX;
|
||||
private double currentStepX;
|
||||
|
||||
// Y Settings
|
||||
private final double startY;
|
||||
private final double stepSizeY;
|
||||
private final int stepsY;
|
||||
private double currentStepY;
|
||||
|
||||
|
||||
/**
|
||||
* Function to use by the generator
|
||||
*/
|
||||
private final XYZGeneratorFunction function;
|
||||
/**
|
||||
* Noise generator
|
||||
*/
|
||||
private final Noise noiseGeneratorX;
|
||||
private final Noise noiseGeneratorY;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param function Function to use for generating data
|
||||
* @param noise Add some noise to the generated x value
|
||||
*/
|
||||
public XYZGenerator(XYZGeneratorFunction function, double startX, double stepSizeX, int stepsX, double startY, double stepSizeY, int stepsY, boolean noise){
|
||||
this.function = function;
|
||||
|
||||
this.startX = startX;
|
||||
this.stepSizeX = stepSizeX;
|
||||
this.stepsX = stepsX;
|
||||
this.currentStepX = startX;
|
||||
|
||||
this.startY = startY;
|
||||
this.stepSizeY = stepSizeY;
|
||||
this.stepsY = stepsY;
|
||||
this.currentStepY = startY;
|
||||
|
||||
if(noise){
|
||||
this.noiseGeneratorX = new Noise(stepSizeX);
|
||||
this.noiseGeneratorY = new Noise(stepSizeY);
|
||||
}
|
||||
else{
|
||||
this.noiseGeneratorX = null;
|
||||
this.noiseGeneratorY = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get new data point
|
||||
* @return Returns null if there is no new point. Otherwise array of double (of size 3) where array[0] == x,
|
||||
* array[1] == y, array[2]==z
|
||||
*/
|
||||
public double[] getNewPoint(){
|
||||
|
||||
// Check whether X axis is at the end
|
||||
if(currentStepX>stepsX){
|
||||
currentStepX = 0;
|
||||
currentStepY++;
|
||||
}
|
||||
|
||||
// Check whether Y axis is at the end
|
||||
if(currentStepY>stepsY){
|
||||
return(null);
|
||||
}
|
||||
|
||||
double x = startX+(stepSizeX*currentStepX);
|
||||
if(noiseGeneratorX != null){
|
||||
x = noiseGeneratorX.generate(x);
|
||||
}
|
||||
currentStepX++;
|
||||
|
||||
double y = startY+(stepSizeY*currentStepY);
|
||||
if(noiseGeneratorY != null){
|
||||
y = noiseGeneratorY.generate(y);
|
||||
}
|
||||
|
||||
|
||||
// Get y value for x
|
||||
double z = function.generate(x,y);
|
||||
|
||||
return(new double[] {x, y, z});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset generator to start settings
|
||||
*/
|
||||
public void reset(){
|
||||
this.currentStepX = this.startX;
|
||||
this.currentStepY = this.startY;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
*
|
||||
* 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.generator;
|
||||
|
||||
/**
|
||||
* Interface defining the generator function signature for generating data
|
||||
* @author ebner
|
||||
*
|
||||
*/
|
||||
public interface XYZGeneratorFunction {
|
||||
|
||||
/**
|
||||
* Generate z value
|
||||
* @param x
|
||||
* @param y
|
||||
* @return Z Value for the given X and Y
|
||||
*/
|
||||
public double generate(double x, double y);
|
||||
}
|
||||
17
ch.psi.plot/src/test/resources/logging.properties
Normal file
17
ch.psi.plot/src/test/resources/logging.properties
Normal file
@@ -0,0 +1,17 @@
|
||||
# Specify the handlers to create in the root logger
|
||||
# (all loggers are children of the root logger)
|
||||
# The following creates two handlers
|
||||
#handlers = java.util.logging.ConsoleHandler, java.util.logging.FileHandler
|
||||
handlers = java.util.logging.ConsoleHandler
|
||||
|
||||
# Set the default logging level for the root logger
|
||||
.level = INFO
|
||||
|
||||
# Set the default logging level for new ConsoleHandler instances
|
||||
java.util.logging.ConsoleHandler.level = ALL
|
||||
|
||||
# Set the default formatter for new ConsoleHandler instances
|
||||
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
|
||||
|
||||
# Set the default logging level for the logger named com.mycompany
|
||||
ch.psi.level = ALL
|
||||
1058
ch.psi.plot/src/test/resources/testfiles/CamshaftExample.txt
Normal file
1058
ch.psi.plot/src/test/resources/testfiles/CamshaftExample.txt
Normal file
File diff suppressed because one or more lines are too long
1043
ch.psi.plot/src/test/resources/testfiles/StreakcameraExample.txt
Executable file
1043
ch.psi.plot/src/test/resources/testfiles/StreakcameraExample.txt
Executable file
File diff suppressed because it is too large
Load Diff
76
ch.psi.plot/tmp/done/Average.java
Normal file
76
ch.psi.plot/tmp/done/Average.java
Normal file
@@ -0,0 +1,76 @@
|
||||
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
ch.psi.plot/tmp/done/CrossDrawer.java
Normal file
44
ch.psi.plot/tmp/done/CrossDrawer.java
Normal file
@@ -0,0 +1,44 @@
|
||||
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
ch.psi.plot/tmp/done/Derivatives.java
Normal file
82
ch.psi.plot/tmp/done/Derivatives.java
Normal file
@@ -0,0 +1,82 @@
|
||||
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
ch.psi.plot/tmp/done/Extrema.java
Normal file
56
ch.psi.plot/tmp/done/Extrema.java
Normal file
@@ -0,0 +1,56 @@
|
||||
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
ch.psi.plot/tmp/done/GraphChooserFrame.form
Normal file
150
ch.psi.plot/tmp/done/GraphChooserFrame.form
Normal file
@@ -0,0 +1,150 @@
|
||||
<?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>
|
||||
112
ch.psi.plot/tmp/done/GraphPropertiesPanel.form
Normal file
112
ch.psi.plot/tmp/done/GraphPropertiesPanel.form
Normal file
@@ -0,0 +1,112 @@
|
||||
<?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
ch.psi.plot/tmp/done/ImagePanel.java
Normal file
29
ch.psi.plot/tmp/done/ImagePanel.java
Normal file
@@ -0,0 +1,29 @@
|
||||
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
ch.psi.plot/tmp/done/Integral.java
Normal file
60
ch.psi.plot/tmp/done/Integral.java
Normal file
@@ -0,0 +1,60 @@
|
||||
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
ch.psi.plot/tmp/done/LinePlot.java
Normal file
985
ch.psi.plot/tmp/done/LinePlot.java
Normal file
@@ -0,0 +1,985 @@
|
||||
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
ch.psi.plot/tmp/done/LinePlotData.java
Normal file
46
ch.psi.plot/tmp/done/LinePlotData.java
Normal file
@@ -0,0 +1,46 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
48
ch.psi.plot/tmp/done/LinePlotMetadata.java
Normal file
48
ch.psi.plot/tmp/done/LinePlotMetadata.java
Normal file
@@ -0,0 +1,48 @@
|
||||
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
ch.psi.plot/tmp/done/Maxs.java
Normal file
28
ch.psi.plot/tmp/done/Maxs.java
Normal file
@@ -0,0 +1,28 @@
|
||||
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
ch.psi.plot/tmp/done/MenuLoader.java
Normal file
148
ch.psi.plot/tmp/done/MenuLoader.java
Normal file
@@ -0,0 +1,148 @@
|
||||
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
ch.psi.plot/tmp/done/MenuNodeType.java
Normal file
131
ch.psi.plot/tmp/done/MenuNodeType.java
Normal file
@@ -0,0 +1,131 @@
|
||||
//
|
||||
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6
|
||||
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
|
||||
// Any modifications to this file will be lost upon recompilation of the source schema.
|
||||
// Generated on: 2009.12.07 at 03:37:39 PM CET
|
||||
//
|
||||
|
||||
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Java class for menuNodeType complex type.
|
||||
*
|
||||
* <p>The following schema fragment specifies the expected content contained within this class.
|
||||
*
|
||||
* <pre>
|
||||
* <complexType name="menuNodeType">
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <choice>
|
||||
* <sequence>
|
||||
* <element name="submenu" type="{}menuNodeType" maxOccurs="unbounded" minOccurs="0"/>
|
||||
* </sequence>
|
||||
* <element name="utilityClass" type="{}utilityClassType"/>
|
||||
* </choice>
|
||||
* <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "menuNodeType", propOrder = {
|
||||
"submenu",
|
||||
"utilityClass"
|
||||
})
|
||||
public class MenuNodeType {
|
||||
|
||||
protected List<MenuNodeType> submenu;
|
||||
protected UtilityClassType utilityClass;
|
||||
@XmlAttribute
|
||||
protected String name;
|
||||
|
||||
/**
|
||||
* Gets the value of the submenu property.
|
||||
*
|
||||
* <p>
|
||||
* This accessor method returns a reference to the live list,
|
||||
* not a snapshot. Therefore any modification you make to the
|
||||
* returned list will be present inside the JAXB object.
|
||||
* This is why there is not a <CODE>set</CODE> method for the submenu property.
|
||||
*
|
||||
* <p>
|
||||
* For example, to add a new item, do as follows:
|
||||
* <pre>
|
||||
* getSubmenu().add(newItem);
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Objects of the following type(s) are allowed in the list
|
||||
* {@link MenuNodeType }
|
||||
*
|
||||
*
|
||||
*/
|
||||
public List<MenuNodeType> getSubmenu() {
|
||||
if (submenu == null) {
|
||||
submenu = new ArrayList<MenuNodeType>();
|
||||
}
|
||||
return this.submenu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the utilityClass property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link UtilityClassType }
|
||||
*
|
||||
*/
|
||||
public UtilityClassType getUtilityClass() {
|
||||
return utilityClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the utilityClass property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link UtilityClassType }
|
||||
*
|
||||
*/
|
||||
public void setUtilityClass(UtilityClassType value) {
|
||||
this.utilityClass = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the name property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the name property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public void setName(String value) {
|
||||
this.name = value;
|
||||
}
|
||||
|
||||
}
|
||||
74
ch.psi.plot/tmp/done/MenuTreeType.java
Normal file
74
ch.psi.plot/tmp/done/MenuTreeType.java
Normal file
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6
|
||||
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
|
||||
// Any modifications to this file will be lost upon recompilation of the source schema.
|
||||
// Generated on: 2009.12.07 at 03:37:39 PM CET
|
||||
//
|
||||
|
||||
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Java class for menuTreeType complex type.
|
||||
*
|
||||
* <p>The following schema fragment specifies the expected content contained within this class.
|
||||
*
|
||||
* <pre>
|
||||
* <complexType name="menuTreeType">
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <sequence>
|
||||
* <element name="menuNode" type="{}menuNodeType" maxOccurs="unbounded" minOccurs="0"/>
|
||||
* </sequence>
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "menuTreeType", propOrder = {
|
||||
"menuNode"
|
||||
})
|
||||
public class MenuTreeType {
|
||||
|
||||
protected List<MenuNodeType> menuNode;
|
||||
|
||||
/**
|
||||
* Gets the value of the menuNode property.
|
||||
*
|
||||
* <p>
|
||||
* This accessor method returns a reference to the live list,
|
||||
* not a snapshot. Therefore any modification you make to the
|
||||
* returned list will be present inside the JAXB object.
|
||||
* This is why there is not a <CODE>set</CODE> method for the menuNode property.
|
||||
*
|
||||
* <p>
|
||||
* For example, to add a new item, do as follows:
|
||||
* <pre>
|
||||
* getMenuNode().add(newItem);
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Objects of the following type(s) are allowed in the list
|
||||
* {@link MenuNodeType }
|
||||
*
|
||||
*
|
||||
*/
|
||||
public List<MenuNodeType> getMenuNode() {
|
||||
if (menuNode == null) {
|
||||
menuNode = new ArrayList<MenuNodeType>();
|
||||
}
|
||||
return this.menuNode;
|
||||
}
|
||||
|
||||
}
|
||||
28
ch.psi.plot/tmp/done/Mins.java
Normal file
28
ch.psi.plot/tmp/done/Mins.java
Normal file
@@ -0,0 +1,28 @@
|
||||
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
ch.psi.plot/tmp/done/ObjectFactory.java
Normal file
96
ch.psi.plot/tmp/done/ObjectFactory.java
Normal file
@@ -0,0 +1,96 @@
|
||||
//
|
||||
// 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
ch.psi.plot/tmp/done/PlugableUtil.java
Normal file
6
ch.psi.plot/tmp/done/PlugableUtil.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
public interface PlugableUtil {
|
||||
public enum PlotType {oneDim, twoDim};
|
||||
public String getLabel();
|
||||
}
|
||||
8
ch.psi.plot/tmp/done/PlugableUtilXY.java
Normal file
8
ch.psi.plot/tmp/done/PlugableUtilXY.java
Normal file
@@ -0,0 +1,8 @@
|
||||
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;
|
||||
}
|
||||
16
ch.psi.plot/tmp/done/PluginExecutionException.java
Normal file
16
ch.psi.plot/tmp/done/PluginExecutionException.java
Normal file
@@ -0,0 +1,16 @@
|
||||
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;
|
||||
|
||||
}
|
||||
65
ch.psi.plot/tmp/done/UtilityClassType.java
Normal file
65
ch.psi.plot/tmp/done/UtilityClassType.java
Normal file
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6
|
||||
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
|
||||
// Any modifications to this file will be lost upon recompilation of the source schema.
|
||||
// Generated on: 2009.12.07 at 03:37:39 PM CET
|
||||
//
|
||||
|
||||
|
||||
package ch.psi.plot.plot.done;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
|
||||
/**
|
||||
* <p>Java class for utilityClassType complex type.
|
||||
*
|
||||
* <p>The following schema fragment specifies the expected content contained within this class.
|
||||
*
|
||||
* <pre>
|
||||
* <complexType name="utilityClassType">
|
||||
* <complexContent>
|
||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
||||
* <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
|
||||
* </restriction>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlType(name = "utilityClassType")
|
||||
public class UtilityClassType {
|
||||
|
||||
@XmlAttribute
|
||||
protected String name;
|
||||
|
||||
/**
|
||||
* Gets the value of the name property.
|
||||
*
|
||||
* @return
|
||||
* possible object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the name property.
|
||||
*
|
||||
* @param value
|
||||
* allowed object is
|
||||
* {@link String }
|
||||
*
|
||||
*/
|
||||
public void setName(String value) {
|
||||
this.name = value;
|
||||
}
|
||||
|
||||
}
|
||||
70
ch.psi.plot/tmp/done/XYPoint.java
Normal file
70
ch.psi.plot/tmp/done/XYPoint.java
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
*
|
||||
* 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
ch.psi.plot/tmp/done/menuconfig.xsd
Normal file
28
ch.psi.plot/tmp/done/menuconfig.xsd
Normal file
@@ -0,0 +1,28 @@
|
||||
<?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
ch.psi.plot/tmp/done/menuconfigxy.xml
Normal file
36
ch.psi.plot/tmp/done/menuconfigxy.xml
Normal file
@@ -0,0 +1,36 @@
|
||||
<?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
ch.psi.plot/tmp/done/menuconfigxyz.xml
Normal file
33
ch.psi.plot/tmp/done/menuconfigxyz.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?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>
|
||||
56
ch.psi.plot/tmp/util/CoordinateTransformer.java
Normal file
56
ch.psi.plot/tmp/util/CoordinateTransformer.java
Normal file
@@ -0,0 +1,56 @@
|
||||
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
ch.psi.plot/tmp/xy/GraphChooserFrame.java
Normal file
193
ch.psi.plot/tmp/xy/GraphChooserFrame.java
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
}
|
||||
358
ch.psi.plot/tmp/xy/GraphPropertiesPanel.java
Normal file
358
ch.psi.plot/tmp/xy/GraphPropertiesPanel.java
Normal file
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* 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
ch.psi.plot/tmp/xy/Interval.java
Normal file
70
ch.psi.plot/tmp/xy/Interval.java
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
*
|
||||
* 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
ch.psi.plot/tmp/xy/Marker.java
Normal file
97
ch.psi.plot/tmp/xy/Marker.java
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
*
|
||||
* 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
ch.psi.plot/tmp/xyz/ExtremaFinder.java
Normal file
140
ch.psi.plot/tmp/xyz/ExtremaFinder.java
Normal file
@@ -0,0 +1,140 @@
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
10
ch.psi.plot/tmp/xyz/IndexOutOfBoundListener.java
Normal file
10
ch.psi.plot/tmp/xyz/IndexOutOfBoundListener.java
Normal file
@@ -0,0 +1,10 @@
|
||||
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();
|
||||
}
|
||||
1354
ch.psi.plot/tmp/xyz/JFreeMatrixPlot.java
Normal file
1354
ch.psi.plot/tmp/xyz/JFreeMatrixPlot.java
Normal file
File diff suppressed because it is too large
Load Diff
130
ch.psi.plot/tmp/xyz/JFreeMatrixPlotData.java
Normal file
130
ch.psi.plot/tmp/xyz/JFreeMatrixPlotData.java
Normal file
@@ -0,0 +1,130 @@
|
||||
|
||||
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();
|
||||
}
|
||||
198
ch.psi.plot/tmp/xyz/JFreeMatrixPlotMetadata.java
Normal file
198
ch.psi.plot/tmp/xyz/JFreeMatrixPlotMetadata.java
Normal file
@@ -0,0 +1,198 @@
|
||||
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
ch.psi.plot/tmp/xyz/MatrixPlotData.java
Normal file
230
ch.psi.plot/tmp/xyz/MatrixPlotData.java
Normal file
@@ -0,0 +1,230 @@
|
||||
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
ch.psi.plot/tmp/xyz/PixelPlotData.java
Normal file
216
ch.psi.plot/tmp/xyz/PixelPlotData.java
Normal file
@@ -0,0 +1,216 @@
|
||||
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
ch.psi.plot/tmp/xyz/Region.java
Normal file
109
ch.psi.plot/tmp/xyz/Region.java
Normal file
@@ -0,0 +1,109 @@
|
||||
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
ch.psi.plot/tmp/xyz/SectionPlotData.java
Normal file
75
ch.psi.plot/tmp/xyz/SectionPlotData.java
Normal file
@@ -0,0 +1,75 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
55
ch.psi.plot/tmp/xyz/StaticMatrixPlotter.java
Normal file
55
ch.psi.plot/tmp/xyz/StaticMatrixPlotter.java
Normal file
@@ -0,0 +1,55 @@
|
||||
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 );
|
||||
}
|
||||
|
||||
}
|
||||
39
ch.psi.plot/tmp/xyz/StaticMatrixPlotterTest.java
Normal file
39
ch.psi.plot/tmp/xyz/StaticMatrixPlotterTest.java
Normal file
@@ -0,0 +1,39 @@
|
||||
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
ch.psi.plot/tmp/xyz/SurfacePlot.java
Normal file
122
ch.psi.plot/tmp/xyz/SurfacePlot.java
Normal file
@@ -0,0 +1,122 @@
|
||||
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
ch.psi.plot/tmp/xyz/SurfacePlotData.java
Normal file
87
ch.psi.plot/tmp/xyz/SurfacePlotData.java
Normal file
@@ -0,0 +1,87 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
176
ch.psi.plot/tmp/xyz/SurfacePlotMetadata.java
Normal file
176
ch.psi.plot/tmp/xyz/SurfacePlotMetadata.java
Normal file
@@ -0,0 +1,176 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
103
ch.psi.plot/tmp/xyz/plugable/BaryCenter.java
Normal file
103
ch.psi.plot/tmp/xyz/plugable/BaryCenter.java
Normal file
@@ -0,0 +1,103 @@
|
||||
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
ch.psi.plot/tmp/xyz/plugable/Filter.java
Normal file
41
ch.psi.plot/tmp/xyz/plugable/Filter.java
Normal file
@@ -0,0 +1,41 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
79
ch.psi.plot/tmp/xyz/plugable/FilterTransformation.java
Normal file
79
ch.psi.plot/tmp/xyz/plugable/FilterTransformation.java
Normal file
@@ -0,0 +1,79 @@
|
||||
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]);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
106
ch.psi.plot/tmp/xyz/plugable/FourierTransformation.java
Normal file
106
ch.psi.plot/tmp/xyz/plugable/FourierTransformation.java
Normal file
@@ -0,0 +1,106 @@
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
71
ch.psi.plot/tmp/xyz/plugable/GaussFilter.java
Normal file
71
ch.psi.plot/tmp/xyz/plugable/GaussFilter.java
Normal file
@@ -0,0 +1,71 @@
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
61
ch.psi.plot/tmp/xyz/plugable/GaussFilterMatrix.java
Normal file
61
ch.psi.plot/tmp/xyz/plugable/GaussFilterMatrix.java
Normal file
@@ -0,0 +1,61 @@
|
||||
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
ch.psi.plot/tmp/xyz/plugable/Gradient.java
Normal file
113
ch.psi.plot/tmp/xyz/plugable/Gradient.java
Normal file
@@ -0,0 +1,113 @@
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
62
ch.psi.plot/tmp/xyz/plugable/GradientPlot.java
Normal file
62
ch.psi.plot/tmp/xyz/plugable/GradientPlot.java
Normal file
@@ -0,0 +1,62 @@
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
133
ch.psi.plot/tmp/xyz/plugable/IntegratedXValues.java
Normal file
133
ch.psi.plot/tmp/xyz/plugable/IntegratedXValues.java
Normal file
@@ -0,0 +1,133 @@
|
||||
package ch.psi.plot.xyz.plugable;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.jfree.data.xy.XYSeries;
|
||||
|
||||
import ch.psi.plot.util.XYPoint;
|
||||
import ch.psi.plot.xy.LinePlot;
|
||||
import ch.psi.plot.xy.LinePlotData;
|
||||
import ch.psi.plot.xyz.JFreeMatrixPlot;
|
||||
import ch.psi.plot.xyz.JFreeMatrixPlotData;
|
||||
|
||||
public class IntegratedXValues implements PlugableUtilXYZ{
|
||||
|
||||
private static Logger logger = Logger.getLogger(IntegratedXValues.class.getName());
|
||||
|
||||
|
||||
/**
|
||||
* Creates line plot data for the integrated X axis of the passed matrix plot data
|
||||
* @param plotData
|
||||
* @param lowerLeft
|
||||
* @param upperRight
|
||||
* @return
|
||||
*/
|
||||
private LinePlotData integrateAlongXAxis(JFreeMatrixPlotData plotData, XYPoint lowerLeft, XYPoint upperRight, boolean binned){
|
||||
|
||||
LinePlotData data = new LinePlotData();
|
||||
XYSeries integratedValues = new XYSeries("Integrated X Values");
|
||||
data.getData().addSeries(integratedValues);
|
||||
|
||||
|
||||
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 sumXDirection = 0.0;
|
||||
double area = plotData.getMetadata().getBinWidthX()*plotData.getMetadata().getBinWidthY();
|
||||
|
||||
while(y < upperRight.getY()){
|
||||
while(x < upperRight.getX()){
|
||||
try{
|
||||
z = plotData.getValue(x, y);
|
||||
sumXDirection += z*area;
|
||||
}
|
||||
catch(Exception e){
|
||||
logger.severe(e.getMessage());
|
||||
}
|
||||
x = x + plotData.getMetadata().getBinWidthX();
|
||||
}
|
||||
|
||||
//if binned, then write the y value according to the stored value in MatrixPlotData
|
||||
if(binned){
|
||||
try{
|
||||
integratedValues.add(plotData.getYValueBinned(y), sumXDirection);
|
||||
}
|
||||
catch(Exception e){
|
||||
logger.fine(e.getMessage() + " Integration couldn't be binned");
|
||||
//We use unbinned version if binned failed
|
||||
integratedValues.add(y, sumXDirection);
|
||||
}
|
||||
}
|
||||
else{//just use the calculated y value
|
||||
integratedValues.add(y, sumXDirection);
|
||||
}
|
||||
|
||||
sumXDirection = 0.0;
|
||||
x = lowerLeft.getX();
|
||||
y = y + plotData.getMetadata().getBinWidthY();
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate integral of visible plot (by first integrating along X-Axis)
|
||||
* @param plotData
|
||||
* @param lowerLeft
|
||||
* @param upperRight
|
||||
* @return
|
||||
*/
|
||||
public double integrate(JFreeMatrixPlotData plotData, XYPoint lowerLeft, XYPoint upperRight){
|
||||
LinePlotData integratedValues = integrateAlongXAxis(plotData, lowerLeft,upperRight, true);
|
||||
|
||||
double integratedValue = 0.0;
|
||||
for (int i = 1; i < integratedValues.getData().getSeries(0).getItemCount() - 1; i++) {
|
||||
integratedValue += integratedValues.getData().getSeries(0).getDataItem(i).getYValue();
|
||||
}
|
||||
return integratedValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show the integrated X Axis value of the current view in a line plot
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void execute(final JFreeMatrixPlot jFreeMatrixPlot) {
|
||||
Thread t = new Thread( new Runnable(){
|
||||
public void run(){
|
||||
|
||||
try {
|
||||
LinePlotData lpData = integrateAlongXAxis(jFreeMatrixPlot.getData(), jFreeMatrixPlot.getLowerLeftChartCorner(), jFreeMatrixPlot.getUpperRightChartCorner(), true);
|
||||
LinePlot p = new LinePlot("Integrated Data" , lpData);
|
||||
p.plot(false);
|
||||
//logger.debug("total = " + JFreeMatrixPlotUtil.integrate(data, lowerLeftChartCorner, upperRightChartCorner));
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.warning(e.getMessage());
|
||||
}
|
||||
|
||||
}});
|
||||
t.start();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user