001/* 002 * Copyright (c) 2010-2012 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2012-05-09 11:05:40 -0700 (Wed, 09 May 2012) $' 007 * '$Revision: 29823 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.kepler.plotting; 031 032import java.awt.Component; 033import java.awt.GridBagConstraints; 034import java.awt.GridBagLayout; 035import java.awt.event.ActionEvent; 036import java.awt.event.WindowAdapter; 037import java.awt.event.WindowEvent; 038import java.text.DateFormat; 039import java.text.ParseException; 040import java.text.SimpleDateFormat; 041import java.util.ArrayList; 042import java.util.Date; 043import java.util.HashSet; 044import java.util.List; 045import java.util.Set; 046 047import javax.swing.JButton; 048import javax.swing.JMenu; 049import javax.swing.JMenuItem; 050import javax.swing.JPanel; 051import javax.swing.JScrollPane; 052 053import org.jfree.chart.ChartPanel; 054import org.jfree.chart.JFreeChart; 055import org.jfree.chart.axis.DateAxis; 056import org.jfree.chart.axis.NumberAxis; 057import org.jfree.chart.plot.XYPlot; 058import org.jfree.chart.renderer.xy.DefaultXYItemRenderer; 059import org.jfree.chart.renderer.xy.XYItemRenderer; 060import org.jfree.data.time.SimpleTimePeriod; 061import org.jfree.data.time.TimePeriodValues; 062import org.jfree.data.time.TimePeriodValuesCollection; 063 064import ptolemy.actor.gui.TableauFrame; 065import ptolemy.vergil.toolbox.FigureAction; 066 067/** 068 * Created by IntelliJ IDEA. 069 * User: sean 070 * Date: Jul 6, 2010 071 * Time: 12:17:07 PM 072 */ 073 074public class Plot extends JPanel { 075 public static List<Plot> getAllPlots() { 076 return _plots; 077 } 078 079 public Plot(TableauFrame frame) { 080 GridBagLayout layout = new GridBagLayout(); 081 this.setLayout(layout); 082 GridBagConstraints c = new GridBagConstraints(); 083 JPanel testGraph = getGraph(); 084 this.add(testGraph, c); 085 086 _plots.add(this); 087 088 // When the window is closed the plot needs to be 089 // removed from the static list so it can be garbage 090 // collected 091 WindowClosedAdapter adapter = new WindowClosedAdapter(); 092 frame.addWindowListener(adapter); 093 } 094 095 private JPanel getGraph() { 096 // series = new XYSeries("Line!"); 097 demoSeries = new TimePeriodValues("Demo Series"); 098 TimePeriodValuesCollection dataset = new TimePeriodValuesCollection(); 099 dataset.setDomainIsPointsInTime(false); 100 this.dataset = dataset; 101 // addDemoSeries(); 102 // dataset = new XYSeriesCollection(series); 103 104 //initializeDemoSeries(); 105 createChart(); 106 107 // don't forget this initializes the chart 108 setScrolling(false); 109 110 resetToggleMenu(); 111 112 return panel; 113 } 114 115 public ChartPanel getChartPanel() { 116 return chartPanel; 117 } 118 119 public void setScrolling(boolean scrolling) { 120 121 GridBagConstraints constraints = new GridBagConstraints(); 122 constraints.gridx = 1; 123 constraints.gridy = 1; 124 125 if (panel == null) { 126 // initialize panel 127 panel = new JPanel(new GridBagLayout()); 128 } 129 else { 130 panel.removeAll(); 131 } 132 // Now we have an empty panel 133 134 Component graphComponent; 135 chartPanel = new ChartPanel(chart); 136 // System.out.println("Chart panel has been set: " + System.identityHashCode(chartPanel)); 137 if (scrolling) { 138 JScrollPane scrollPane = new JScrollPane(chartPanel); 139 scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 140 scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); 141 graphComponent = scrollPane; 142 } 143 else { 144 graphComponent = chartPanel; 145 } 146 147 panel.add(graphComponent, constraints); 148 } 149 150 private void initializeToggleMenu() { 151 if (toggleMenu == null) { 152 toggleMenu = new JMenu("Toggle line"); 153 } 154 if (!added) { 155 chartPanel.getPopupMenu().add(toggleMenu); 156 added = true; 157 } 158 } 159 160 public void setClearButton(JButton clearButton) { 161 this.clearButton = clearButton; 162 } 163 164 public JButton getClearButton() { 165 return clearButton; 166 } 167 168 private boolean added = false; 169 170 private void clearToggleMenu() { 171 toggleMenu.removeAll(); 172 } 173 174 private void populateToggleMenu() { 175 for (int i = 0; i < dataset.getSeriesCount(); i++) { 176 TimePeriodValues series = dataset.getSeries(i); 177 addEntry(series); 178 } 179 for (TimePeriodValues series : frozenSeries) { 180 addEntry(series); 181 } 182 } 183 184 private JMenu toggleMenu = null; 185 186 private void addEntry(final TimePeriodValues series) { 187 String menuEntryName = "Toggle line '" + series.getKey() + "'"; 188 final Plot me = this; 189 toggleMenu.add(new JMenuItem(new FigureAction(menuEntryName) { 190 @Override 191 public void actionPerformed(ActionEvent e) { 192 // Get series number 193 int seriesIndex = -1; 194 for (int i = 0; i < dataset.getSeriesCount(); i++) { 195 TimePeriodValues currentSeries = dataset.getSeries(i); 196 if (series == currentSeries) { 197 seriesIndex = i; 198 break; 199 } 200 } 201 if (seriesIndex == -1) { 202 return; 203 } 204 205 XYItemRenderer renderer = me.getXYPlot().getRendererForDataset(dataset); 206 Boolean currentVisibility = renderer.getSeriesVisible(seriesIndex); 207 if (currentVisibility == null) { 208 currentVisibility = true; 209 } 210 renderer.setSeriesVisible(seriesIndex, !currentVisibility); 211 } 212 })); 213 } 214 215 public void resetToggleMenu() { 216 initializeToggleMenu(); 217 clearToggleMenu(); 218 populateToggleMenu(); 219 } 220 221 private final Set<TimePeriodValues> frozenSeries = new HashSet<TimePeriodValues>(); 222 223 public void removeDemoSeries() { 224 dataset.removeSeries(demoSeries); 225 } 226 227 public void addDemoSeries() { 228 dataset.addSeries(demoSeries); 229 } 230 231 private void createChart() { 232 boolean includeLegend = false; 233 boolean tooltips = true; 234 boolean urls = false; 235 236 // chart = ChartFactory.createXYLineChart("Chart Title", "Domain label", "Value label", dataset, PlotOrientation.VERTICAL, includeLegend, tooltips, urls); 237 plot = new XYPlot(dataset, new DateAxis("X Axis"), new NumberAxis("Y Axis"), new DefaultXYItemRenderer()); 238 chart = new JFreeChart("Chart Title", plot); 239 } 240 241 private void initializeDemoSeries() { 242 DateFormat df = new SimpleDateFormat("M/d/yyyy HH:mm:ss.SSS"); 243 Date d0 = null, d1 = null, d2 = null, d3 = null, d4 = null; 244 Date d5 = null, d6 = null, d7 = null, d8 = null, d9 = null; 245 Date d10 = null, d11 = null, d12 = null, d13 = null, d14 = null; 246 Date d15 = null; 247 try { 248 d0 = df.parse("11/5/2003 0:00:00.000"); 249 d1 = df.parse("11/5/2003 0:01:00.000"); 250 d2 = df.parse("11/5/2003 0:02:00.000"); 251 d3 = df.parse("11/5/2003 0:03:00.000"); 252 d4 = df.parse("11/5/2003 0:04:00.000"); 253 d5 = df.parse("11/5/2003 0:05:00.000"); 254 d6 = df.parse("11/5/2003 0:06:00.000"); 255 d7 = df.parse("11/5/2003 0:07:00.000"); 256 d8 = df.parse("11/5/2003 0:08:00.000"); 257 d9 = df.parse("11/5/2003 0:09:00.000"); 258 d10 = df.parse("11/5/2003 0:10:00.000"); 259 d11 = df.parse("11/5/2003 0:11:00.000"); 260 d12 = df.parse("11/5/2003 0:12:00.000"); 261 d13 = df.parse("11/5/2003 0:13:00.000"); 262 d14 = df.parse("11/5/2003 0:14:00.000"); 263 d15 = df.parse("11/5/2003 0:15:00.000"); 264 } 265 catch(ParseException ex) { 266 ex.printStackTrace(); 267 } 268 269 demoSeries.add(new SimpleTimePeriod(d0, d0), 0); 270 demoSeries.add(new SimpleTimePeriod(d1, d1), 40.674); 271 demoSeries.add(new SimpleTimePeriod(d2, d2), 74.314); 272 demoSeries.add(new SimpleTimePeriod(d3, d3), 95.106); 273 demoSeries.add(new SimpleTimePeriod(d4, d4), 99.452); 274 demoSeries.add(new SimpleTimePeriod(d5, d5), 86.603); 275 demoSeries.add(new SimpleTimePeriod(d6, d6), 58.779); 276 demoSeries.add(new SimpleTimePeriod(d7, d7), 20.791); 277 demoSeries.add(new SimpleTimePeriod(d8, d8), -20.791); 278 demoSeries.add(new SimpleTimePeriod(d9, d9), -58.779); 279 demoSeries.add(new SimpleTimePeriod(d10, d10), -86.603); 280 demoSeries.add(new SimpleTimePeriod(d11, d11), -99.452); 281 demoSeries.add(new SimpleTimePeriod(d12, d12), -95.106); 282 demoSeries.add(new SimpleTimePeriod(d13, d13), -74.314); 283 demoSeries.add(new SimpleTimePeriod(d14, d14), -40.674); 284 demoSeries.add(new SimpleTimePeriod(d15, d15), 0); 285 } 286 287 public TimePeriodValuesCollection getDataset() { 288 return dataset; 289 } 290 291 public PlotEditor getPlotEditor() { 292 return plotEditor; 293 } 294 295 public void setPlotEditor(PlotEditor plotEditor) { 296 this.plotEditor = plotEditor; 297 // Initialize a connection between the dataset and the table model, so that the table model can be accurately reflected 298 this.getPlotEditor().getTable().setDataset(dataset); 299 } 300 301 public JPanel getPanel() { 302 return panel; 303 } 304 305 public void setGraphName(String graphName) { 306 chart.setTitle(graphName); 307 } 308 309 public JFreeChart getChart() { 310 return chart; 311 } 312 313 public XYPlot getXYPlot() { 314 return plot; 315 } 316 317 public void setProperty(GraphProperty label, String value) { 318 if (label == GraphProperty.TITLE) { 319 chart.setTitle(value); 320 } 321 else if (label == GraphProperty.X_LABEL) { 322 chart.getXYPlot().getDomainAxis().setLabel(value); 323 } 324 else if (label == GraphProperty.Y_LABEL) { 325 chart.getXYPlot().getRangeAxis().setLabel(value); 326 } 327 } 328 329 public String getTitle() { 330 try { 331 return chart.getTitle().getText(); 332 } 333 catch(NullPointerException ex) { 334 return null; 335 } 336 } 337 338 /** Listener for windowClosing action. */ 339 class WindowClosedAdapter extends WindowAdapter { 340 public void windowClosed(WindowEvent e) { 341 //Window window = e.getWindow(); 342 //System.out.println("org.kepler.plotting.Plot$WindowClosedAdapter.windowClosed() : " + window.getName()); 343 344 _plots.remove(Plot.this); 345 } 346 } 347 348 private static List<Plot> _plots = new ArrayList<Plot>(); 349 private JFreeChart chart; 350 private XYPlot plot; 351 private TimePeriodValues demoSeries; 352 private TimePeriodValuesCollection dataset; 353 private JPanel panel; 354 private ChartPanel chartPanel; 355 private PlotEditor plotEditor; 356 private JButton clearButton; 357}