Migrated from Mercurial to git (without history)

This commit is contained in:
ebner
2011-10-21 08:53:20 +02:00
commit 8eaf020a95
106 changed files with 14090 additions and 0 deletions

10
ch.psi.plot/.classpath Normal file
View 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
View File

@@ -0,0 +1 @@
/target

23
ch.psi.plot/.project Normal file
View 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>

View 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

View File

@@ -0,0 +1,5 @@
#Tue Oct 18 14:55:04 CEST 2011
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

Binary file not shown.

Binary file not shown.

Binary file not shown.

View 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
View 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>

View 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();
}

View 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;
}
}

View File

@@ -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;
}
}

View 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);
}
}
}
}

View 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();
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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);
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View File

@@ -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;
}
}

View File

View 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);
}
}

View 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);
}
}

View 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;
}
}

View File

@@ -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));
}
}
}

View File

@@ -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;
}
}

View 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.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));
}
}

View File

@@ -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);
}
}

View File

@@ -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());
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View 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);
}
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View 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

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View 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;
}
}

View 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);
}
}

View 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();
}
}

View 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;
}
}
}

View 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>

View 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>

View 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 );
}
}

View 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;
}
}

View 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);
}
}

View 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;
}
}

View 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;
}
}

View 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();
}
}

View 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;
}
}

View 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>
* &lt;complexType name="menuNodeType">
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;choice>
* &lt;sequence>
* &lt;element name="submenu" type="{}menuNodeType" maxOccurs="unbounded" minOccurs="0"/>
* &lt;/sequence>
* &lt;element name="utilityClass" type="{}utilityClassType"/>
* &lt;/choice>
* &lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "menuNodeType", propOrder = {
"submenu",
"utilityClass"
})
public class MenuNodeType {
protected List<MenuNodeType> submenu;
protected UtilityClassType utilityClass;
@XmlAttribute
protected String name;
/**
* Gets the value of the submenu property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the submenu property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getSubmenu().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link MenuNodeType }
*
*
*/
public List<MenuNodeType> getSubmenu() {
if (submenu == null) {
submenu = new ArrayList<MenuNodeType>();
}
return this.submenu;
}
/**
* Gets the value of the utilityClass property.
*
* @return
* possible object is
* {@link UtilityClassType }
*
*/
public UtilityClassType getUtilityClass() {
return utilityClass;
}
/**
* Sets the value of the utilityClass property.
*
* @param value
* allowed object is
* {@link UtilityClassType }
*
*/
public void setUtilityClass(UtilityClassType value) {
this.utilityClass = value;
}
/**
* Gets the value of the name property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setName(String value) {
this.name = value;
}
}

View 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>
* &lt;complexType name="menuTreeType">
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;sequence>
* &lt;element name="menuNode" type="{}menuNodeType" maxOccurs="unbounded" minOccurs="0"/>
* &lt;/sequence>
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "menuTreeType", propOrder = {
"menuNode"
})
public class MenuTreeType {
protected List<MenuNodeType> menuNode;
/**
* Gets the value of the menuNode property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the menuNode property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getMenuNode().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link MenuNodeType }
*
*
*/
public List<MenuNodeType> getMenuNode() {
if (menuNode == null) {
menuNode = new ArrayList<MenuNodeType>();
}
return this.menuNode;
}
}

View 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();
}
}

View 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);
}
}

View File

@@ -0,0 +1,6 @@
package ch.psi.plot.plot.done;
public interface PlugableUtil {
public enum PlotType {oneDim, twoDim};
public String getLabel();
}

View 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;
}

View 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;
}

View 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>
* &lt;complexType name="utilityClassType">
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "utilityClassType")
public class UtilityClassType {
@XmlAttribute
protected String name;
/**
* Gets the value of the name property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setName(String value) {
this.name = value;
}
}

View 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;
}
}

View 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>

View 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>

View 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>

View 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;
}
}
}

View 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
}

View 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
}

View 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;
}
}

View 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;
}
}

View 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);
}
}

View 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();
}

File diff suppressed because it is too large Load Diff

View 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();
}

View 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;
}
}

View 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);
}
}

View 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;
}
}

View 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();
}
}
}

View 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;
}
}
}
}

View 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 );
}
}

View 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();
}
}
}

View 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
}
}

View 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;
}
}

View 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;
}
}

View 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();
}
}

View 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;
}
}
}

View 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]);
}
}
}
}

View 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();
}
}

View 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();
}
}

View 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;
}
}

View 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();
}
}

View 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;
}
}

View 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