/* * Open Source Physics software is free software as described near the bottom of this code file. * * For additional information and documentation on Open Source Physics please see: * <http://www.opensourcephysics.org/> */ package org.opensourcephysics.frames; import java.awt.Color; import java.awt.Shape; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.KeyStroke; import javax.swing.WindowConstants; import org.opensourcephysics.controls.XML; import org.opensourcephysics.controls.XMLControl; import org.opensourcephysics.display.DataTable; import org.opensourcephysics.display.DataTableFrame; import org.opensourcephysics.display.Dataset; import org.opensourcephysics.display.DatasetManager; import org.opensourcephysics.display.DisplayRes; import org.opensourcephysics.display.Drawable; import org.opensourcephysics.display.DrawingFrame; import org.opensourcephysics.display.PlottingPanel; import org.opensourcephysics.display.TeXParser; import org.opensourcephysics.display.dialogs.LogAxesInspector; import org.opensourcephysics.display.dialogs.ScaleInspector; /** * PlotFrame displays a plot using a dedicated DatasetManager. * * PlotFrame is a composite object that forwards methods to other objects such as a DatasetManager * or a DataTable. * * @author W. Christian * @version 1.0 */ public class PlotFrame extends DrawingFrame { protected DatasetManager datasetManager = new DatasetManager(); protected DataTable dataTable = new DataTable(); protected DataTableFrame tableFrame; /** * Constructs the PlottingFrame with the given frame title and axes labels. * * @param xlabel String * @param ylabel String * @param frameTitle String */ public PlotFrame(String xlabel, String ylabel, String frameTitle) { super(new PlottingPanel(xlabel, ylabel, null)); setTitle(frameTitle); drawingPanel.addDrawable(datasetManager); datasetManager.setXPointsLinked(true); dataTable.add(datasetManager); setAnimated(true); setAutoclear(true); addMenuItems(); } /** * Sets the name of this component and the Dataset Manager. */ public void setName(String name) { name = TeXParser.parseTeX(name); super.setName(name); datasetManager.setName(name); } /** * Adds Views menu items on the menu bar. */ protected void addMenuItems() { JMenuBar menuBar = getJMenuBar(); if(menuBar==null) { return; } JMenu helpMenu = this.removeMenu(DisplayRes.getString("DrawingFrame.Help_menu_item")); //$NON-NLS-1$ JMenu menu = getMenu(DisplayRes.getString("DrawingFrame.Views_menu")); //$NON-NLS-1$ if(menu==null) { menu = new JMenu(DisplayRes.getString("DrawingFrame.Views_menu")); //$NON-NLS-1$ menuBar.add(menu); menuBar.validate(); } else { // add a separator if tools already exists menu.addSeparator(); } if(helpMenu!=null) { menuBar.add(helpMenu); } // add a scale option JMenuItem scaleItem = new JMenuItem(DisplayRes.getString("DrawingFrame.Scale_menu_item")); //$NON-NLS-1$ ActionListener actionListener = new ActionListener() { public void actionPerformed(ActionEvent e) { scale(); } }; scaleItem.addActionListener(actionListener); menu.add(scaleItem); // add a log scale option JMenuItem logItem = new JMenuItem(DisplayRes.getString("DrawingFrame.LogAxes_menu_item")); //$NON-NLS-1$ actionListener = new ActionListener() { public void actionPerformed(ActionEvent e) { logAxes(); } }; logItem.addActionListener(actionListener); menu.add(logItem); menu.addSeparator(); // add a data table item to show the data table JMenuItem tableItem = new JMenuItem(DisplayRes.getString("DrawingFrame.DataTable_menu_item")); //$NON-NLS-1$ tableItem.setAccelerator(KeyStroke.getKeyStroke('T', MENU_SHORTCUT_KEY_MASK)); actionListener = new ActionListener() { public void actionPerformed(ActionEvent e) { showDataTable(true); } }; tableItem.addActionListener(actionListener); menu.add(tableItem); // add data table to the popup menu if((drawingPanel!=null)&&(drawingPanel.getPopupMenu()!=null)) { JMenuItem item = new JMenuItem(DisplayRes.getString("DrawingFrame.DataTable_menu_item")); //$NON-NLS-1$ item.addActionListener(actionListener); drawingPanel.getPopupMenu().addSeparator(); drawingPanel.getPopupMenu().add(item); } } /** * Sets the log scale property for the x axis. * * @param log boolean */ public void setLogScaleX(boolean log) { if(drawingPanel instanceof PlottingPanel) { ((PlottingPanel) drawingPanel).setLogScaleX(log); } } /** * Sets the log scale property for the y axis. * * @param log boolean */ public void setLogScaleY(boolean log) { if(drawingPanel instanceof PlottingPanel) { ((PlottingPanel) drawingPanel).setLogScaleY(log); } } protected void scale() { ScaleInspector plotInspector = new ScaleInspector(drawingPanel); plotInspector.setLocationRelativeTo(drawingPanel); plotInspector.updateDisplay(); plotInspector.setVisible(true); } protected void logAxes() { if(!(drawingPanel instanceof PlottingPanel)) { return; } LogAxesInspector logAxesInspector = new LogAxesInspector((PlottingPanel) drawingPanel); logAxesInspector.setLocationRelativeTo(drawingPanel); logAxesInspector.updateDisplay(); logAxesInspector.setVisible(true); } /** * Appends an (x,y) datum to the Dataset with the given index. * * @param datasetIndex Description of Parameter * @param x * @param y */ public void append(int datasetIndex, double x, double y) { datasetManager.append(datasetIndex, x, y); // may be too slow if lots of data is being added to the table if((tableFrame!=null)&&tableFrame.isShowing()) { dataTable.refreshTable(); } } /** * Appends a data point and its uncertainty to the Dataset. * * @param datasetIndex * @param x * @param y * @param delx * @param dely * */ public void append(int datasetIndex, double x, double y, double delx, double dely) { datasetManager.append(datasetIndex, x, y, delx, dely); if((tableFrame!=null)&&tableFrame.isShowing()) { dataTable.refreshTable(); } } /** * Appends (x,y) arrays to the Dataset. * * @param datasetIndex Description of Parameter * @param xpoints * @param ypoints */ public void append(int datasetIndex, double[] xpoints, double[] ypoints) { datasetManager.append(datasetIndex, xpoints, ypoints); if((tableFrame!=null)&&tableFrame.isShowing()) { dataTable.refreshTable(); } } /** * Appends arrays of data points and uncertainties to the Dataset. * * @param datasetIndex * @param xpoints * @param ypoints * @param delx * @param dely */ public void append(int datasetIndex, double[] xpoints, double[] ypoints, double[] delx, double[] dely) { datasetManager.append(datasetIndex, xpoints, ypoints, delx, dely); if((tableFrame!=null)&&tableFrame.isShowing()) { dataTable.refreshTable(); } } /** * Sets the connected flag for all datasets. * * @param connected true if connected; false otherwise */ public void setConnected(boolean connected) { datasetManager.setConnected(connected); } /** * Sets the maximum number of allowed datapoints. * * Points will be dropped from the beginning of the dataset after the maximum number has been reached. * * @param maxPoints int */ public void setMaximumPoints(int datasetIndex, int maxPoints) { datasetManager.getDataset(datasetIndex).setMaximumPoints(maxPoints); } /** * Sets a custom marker shape. * * @param datasetIndex int * @param marker Shape */ public void setCustomMarker(int datasetIndex, Shape marker) { datasetManager.setCustomMarker(datasetIndex, marker); } /** * Sets the data point marker shape. Shapes are: NO_MARKER, CIRCLE, SQUARE, * AREA, PIXEL, BAR, POST * * @param datasetIndex The new markerShape value * @param markerShape */ public void setMarkerShape(int datasetIndex, int markerShape) { datasetManager.setMarkerShape(datasetIndex, markerShape); } /** * Sets the half-width of the data point marker. * * @param datasetIndex * @param markerSize in pixels */ public void setMarkerSize(int datasetIndex, int markerSize) { datasetManager.setMarkerSize(datasetIndex, markerSize); } /** * Sets the data marker color for the given index. * * @param datasetIndex int * @param color Color */ public void setMarkerColor(int datasetIndex, Color color) { datasetManager.setMarkerColor(datasetIndex, color); } /** * Sets the data line color for the given index. * * @param datasetIndex int * @param color Color */ public void setLineColor(int datasetIndex, Color color) { datasetManager.setLineColor(datasetIndex, color); } /** * Sets the background color of this component. */ public void setBackground(Color color) { super.setBackground(color); if(drawingPanel!=null) { drawingPanel.setBackground(color); } } /** * Sets the marker's fill and edge colors. * * The error bar color is set equal to the edge color. * * @param datasetIndex * @param fillColor * @param edgeColor */ public void setMarkerColor(int datasetIndex, Color fillColor, Color edgeColor) { datasetManager.setMarkerColor(datasetIndex, fillColor, edgeColor); } /** * Sets the data connected flag. Points are connected by straight lines. * * @param datasetIndex The new connected value * @param connected <code>true<\code> if points are connected */ public void setConnected(int datasetIndex, boolean connected) { datasetManager.setConnected(datasetIndex, connected); } /** * Sets the linked flag. X data for datasets > 0 will not be shown in a table view. * * @param linked The new value */ public void setXPointsLinked(boolean linked) { datasetManager.setXPointsLinked(linked); } /** * Sets the column names and the dataset name. * * @param datasetIndex The new xYColumnNames value * @param xColumnName * @param yColumnName * @param datasetName */ public void setXYColumnNames(int datasetIndex, String xColumnName, String yColumnName, String datasetName) { datasetManager.setXYColumnNames(datasetIndex, xColumnName, yColumnName, datasetName); } /** * Sets the column names when rendering this dataset in a JTable. * * @param datasetIndex The new xYColumnNames value * @param xColumnName * @param yColumnName */ public void setXYColumnNames(int datasetIndex, String xColumnName, String yColumnName) { datasetManager.setXYColumnNames(datasetIndex, xColumnName, yColumnName); } /** * Sets the maximum number of fraction digits to display for cells that have * type Double * * @param maximumFractionDigits - maximum number of fraction digits to display */ public void setMaximumFractionDigits(int maximumFractionDigits) { dataTable.setMaximumFractionDigits(maximumFractionDigits); } /** * Sets the maximum number of fraction digits to display in all data table columns with * cthe given columnName. * * @param maximumFractionDigits - maximum number of fraction digits to display * @param columnName The new maximumFractionDigits value */ public void setMaximumFractionDigits(String columnName, int maximumFractionDigits) { dataTable.setMaximumFractionDigits(columnName, maximumFractionDigits); } /** * Sets the display row number flag. Table displays row number. * * @param vis <code>true<\code> if table display row number */ public void setRowNumberVisible(boolean vis) { dataTable.setRowNumberVisible(vis); } /** * Clears drawable objects added by the user to this frame. */ public void clearDrawables() { drawingPanel.clear(); // removes all drawables drawingPanel.addDrawable(datasetManager); } /** * Gets a dataset with the given index. * * @param index * @return Dataset * */ public Dataset getDataset(int index) { return datasetManager.getDataset(index); } /** * Gets the dataset manager. * * @return DatasetManager * */ public DatasetManager getDatasetManager() { return datasetManager; } /** * Gets Drawable objects added by the user to this frame. * * @return the list */ public synchronized ArrayList<Drawable> getDrawables() { ArrayList<Drawable> list = super.getDrawables(); list.remove(datasetManager); return list; } /** * Gets Drawable objects added by the user of an assignable type. The list contains * objects that are assignable from the class or interface. * * @param c the type of Drawable object * * @return the cloned list * * @see #getObjectOfClass(Class c) */ public synchronized <T extends Drawable> ArrayList<T> getDrawables(Class<T> c) { ArrayList<T> list = super.getDrawables(c); list.remove(datasetManager); return list; } /** * Clears the data from all datasets. * Dataset properties are preserved because only the data is cleared. */ public void clearData() { datasetManager.clear(); dataTable.refreshTable(); if(drawingPanel!=null) { drawingPanel.invalidateImage(); } } /** * Removes all Datasets and removes all objects from the drawing panel except the dataset manager. * Datasets are removed from the manager and dataset properties are not preserved. */ /** * Removes datasets from the manager. New datasets will be created with default properties as needed. */ public void removeDatasets() { datasetManager.removeDatasets(); dataTable.refreshTable(); if(drawingPanel!=null) { drawingPanel.invalidateImage(); } } /** * Shows or hides the data table. * * @param show boolean */ public synchronized void showDataTable(boolean show) { if(show) { if((tableFrame==null)||!tableFrame.isDisplayable()) { tableFrame = new DataTableFrame(getTitle()+" "+DisplayRes.getString("TableFrame.TitleAddOn.Data"), dataTable); //$NON-NLS-1$ //$NON-NLS-2$ tableFrame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); } dataTable.refreshTable(); tableFrame.setVisible(true); } else { tableFrame.setVisible(false); tableFrame.dispose(); tableFrame = null; } } /** * Returns an XML.ObjectLoader to save and load data. * * @return the object loader */ public static XML.ObjectLoader getLoader() { return new PlotFrameLoader(); } static protected class PlotFrameLoader extends DrawingFrame.DrawingFrameLoader { /** * Creates a PlotFame. * * @param control XMLControl * @return Object */ public Object createObject(XMLControl control) { PlotFrame frame = new PlotFrame("x", "y", DisplayRes.getString("PlotFrame.Title")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ return frame; } /** * Loads the object with data from the control. * * @param control XMLControl * @param obj Object * @return Object */ public Object loadObject(XMLControl control, Object obj) { super.loadObject(control, obj); PlotFrame frame = ((PlotFrame) obj); ArrayList<?> list = frame.getObjectOfClass(DatasetManager.class); if(list.size()>0) { // assume the first DatasetManager is the manager for this frame frame.datasetManager = (DatasetManager) list.get(0); frame.dataTable.clear(); frame.dataTable.add(frame.datasetManager); } return obj; } } } /* * Open Source Physics software is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public License (GPL) as * published by the Free Software Foundation; either version 2 of the License, * or(at your option) any later version. * Code that uses any portion of the code in the org.opensourcephysics package * or any subpackage (subdirectory) of this package must must also be be released * under the GNU GPL license. * * This software 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA * or view the license online at http://www.gnu.org/copyleft/gpl.html * * Copyright (c) 2007 The Open Source Physics project * http://www.opensourcephysics.org */