ObservationAndMeanPlotPane.java
/**
* VStar: a statistical analysis tool for variable star data.
* Copyright (C) 2009 AAVSO (http://www.aavso.org/)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.aavso.tools.vstar.ui.pane.plot;
import java.awt.Dimension;
import java.awt.geom.Point2D;
import java.util.List;
import org.aavso.tools.vstar.data.SeriesType;
import org.aavso.tools.vstar.data.ValidObservation;
import org.aavso.tools.vstar.input.AbstractObservationRetriever;
import org.aavso.tools.vstar.ui.mediator.AnalysisType;
import org.aavso.tools.vstar.ui.mediator.DocumentManager;
import org.aavso.tools.vstar.ui.mediator.Mediator;
import org.aavso.tools.vstar.ui.mediator.NewStarType;
import org.aavso.tools.vstar.ui.mediator.ViewModeType;
import org.aavso.tools.vstar.ui.mediator.message.NewStarMessage;
import org.aavso.tools.vstar.ui.mediator.message.ObservationSelectionMessage;
import org.aavso.tools.vstar.ui.mediator.message.PanRequestMessage;
import org.aavso.tools.vstar.ui.mediator.message.ZoomRequestMessage;
import org.aavso.tools.vstar.ui.model.plot.ObservationAndMeanPlotModel;
import org.aavso.tools.vstar.util.notification.Listener;
import org.aavso.tools.vstar.util.prefs.NumericPrecisionPrefs;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.entity.ChartEntity;
import org.jfree.chart.entity.XYItemEntity;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.plot.SeriesRenderingOrder;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.title.TextTitle;
import org.jfree.chart.title.Title;
/**
* This class represents a chart pane containing a plot for a set of valid
* observations along with mean-based data.
*/
@SuppressWarnings("serial")
public class ObservationAndMeanPlotPane extends AbstractObservationPlotPane<ObservationAndMeanPlotModel> {
private DocumentManager docMgr;
private String xyMsgFormat;
/**
* Constructor
*
* @param title The title for the chart.
* @param subTitle The sub-title for the chart (may be null).
* @param domainTitle The domain title (e.g. Julian Date, phase).
* @param rangeTitle The range title (e.g. magnitude).
* @param obsModel The data model to plot.
* @param bounds The bounding box to which to set the chart's preferred
* size.
* @param retriever The observation retriever for observations in this plot.
* @param analysisType The analysis type associated with this plot.
*/
public ObservationAndMeanPlotPane(String title, String subTitle, String domainTitle, String rangeTitle,
ObservationAndMeanPlotModel obsAndMeanModel, Dimension bounds, AbstractObservationRetriever retriever,
AnalysisType analysisType) {
super(title, subTitle, domainTitle, rangeTitle, obsAndMeanModel, bounds, retriever);
docMgr = Mediator.getInstance().getDocumentManager();
// Add sub-title, if any.
if (subTitle != null && !"".equals(subTitle.trim())) {
List<Title> subTitles = chart.getSubtitles();
subTitles.add(new TextTitle(subTitle));
chart.setSubtitles(subTitles);
}
// Format for observation tool-tip.
xyMsgFormat = "%s (%s), %s";
// Set the means series color.
int meanSeriesNum = obsAndMeanModel.getMeansSeriesNum();
if (meanSeriesNum != ObservationAndMeanPlotModel.NO_SERIES) {
this.getRenderer().setSeriesPaint(meanSeriesNum, SeriesType.getColorFromSeries(SeriesType.MEANS));
}
// Update joined series to ensure that the means series is initially
// joined since the base class won't include it in its set.
setJoinedSeries();
// Update plot pane from state of user-controllable characteristics
getRenderer().setDrawYError(docMgr.shouldShowErrorBars(analysisType));
getChartPanel().getChart().getXYPlot().setDomainCrosshairVisible(docMgr.shouldShowCrossHairs(analysisType));
getChartPanel().getChart().getXYPlot().setRangeCrosshairVisible(docMgr.shouldShowCrossHairs(analysisType));
getChartPanel().getChart().getXYPlot().getRangeAxis().setInverted(docMgr.shouldInvertRange(analysisType));
getChartPanel().getChart().getXYPlot().setSeriesRenderingOrder(
docMgr.shouldInvertSeriesOrder(analysisType) ? SeriesRenderingOrder.REVERSE : SeriesRenderingOrder.FORWARD);
if (meanSeriesNum != ObservationAndMeanPlotModel.NO_SERIES) {
// This may override the action of setJoinedSeries() depending upon state of
// this user-controllable characteristic
getRenderer().setSeriesLinesVisible(obsModel.getMeansSeriesNum(), docMgr.shouldJoinMeans(analysisType));
}
}
/**
* Constructor
*
* @param title The title for the chart.
* @param subTitle The sub-title for the chart.
* @param obsModel The data model to plot.
* @param bounds The bounding box to which to set the chart's preferred
* size.
* @param retriever The observation retriever for observations in this plot.
* @param analysisType The analysis type associated with this plot.
*/
public ObservationAndMeanPlotPane(String title, String subTitle, ObservationAndMeanPlotModel obsAndMeanModel,
Dimension bounds, AbstractObservationRetriever retriever, AnalysisType analysisType) {
this(title, subTitle, getTimeAxisLabel(retriever), getBrightnessAxisLabel(retriever), obsAndMeanModel, bounds,
retriever, analysisType);
}
/**
* @return The observation model.
*/
public ObservationAndMeanPlotModel getObsModel() {
return obsModel;
}
/**
* @param meanSourceSeriesNum the meanSourceSeriesNum to set
*/
public void setMeanSourceSeriesNum(int meanSourceSeriesNum) {
obsModel.setMeanSourceSeriesNum(meanSourceSeriesNum);
}
/**
* Attempt to create a new mean series with the specified number of time
* elements per bin.
*
* @param timeElementsInBin The number of days or phase steps to be created per
* bin.
* @return Whether or not the series was changed.
*/
public boolean changeMeansSeries(double timeElementsInBin) {
return obsModel.changeMeansSeries(timeElementsInBin);
}
// @Override
// protected void setSeriesVisibility() {
//
// super.setSeriesVisibility();
//
// Map<SeriesType, Boolean> seriesVisibilityMap = obsModel
// .getSeriesVisibilityMap();
//
// boolean isModelFuncVisible = seriesVisibilityMap
// .get(SeriesType.ModelFunction);
//
// if (isModelFuncVisible && obsModel.getModelFunction() != null) {
// ContinuousModelPlotModel modelFuncModel = new ContinuousModelPlotModel(
// obsModel.getModelFunction());
//
// JFreeChart modelFuncPlot = ChartFactory.createXYLineChart("", "",
// "", modelFuncModel, PlotOrientation.VERTICAL, false, false,
// false);
//
// int modelFuncSeriesNum = obsModel.getSrcTypeToSeriesNumMap().get(
// SeriesType.ModelFunction);
//
// chart.getXYPlot().setDataset(modelFuncSeriesNum, modelFuncModel);
// chart.getXYPlot().setRenderer(modelFuncSeriesNum,
// modelFuncPlot.getXYPlot().getRenderer());
// Color color = SeriesType
// .getColorFromSeries(SeriesType.ModelFunction);
// chart.getXYPlot().getRenderer(modelFuncSeriesNum).setSeriesPaint(
// modelFuncSeriesNum, color);
// chart.getXYPlot().getRenderer(modelFuncSeriesNum).setSeriesVisible(
// modelFuncSeriesNum, true);
// }
// }
// From ChartMouseListener interface.
// If the mouse is over a data point, set its tool-tip with JD and
// magnitude.
public void chartMouseMoved(ChartMouseEvent event) {
ChartEntity entity = event.getEntity();
if (entity instanceof XYItemEntity) {
XYItemEntity item = (XYItemEntity) entity;
// Dataset may not be same as primary observation model, e.g.
// could be model function dataset (continuous model).
if (item.getDataset() == obsModel) {
ValidObservation ob = obsModel.getValidObservation(item.getSeriesIndex(), item.getItem());
String xyMsg = String.format(xyMsgFormat, NumericPrecisionPrefs.formatTime(ob.getJD()),
ob.getDateInfo().getCalendarDate(), NumericPrecisionPrefs.formatMag(ob.getMag()));
item.setToolTipText(xyMsg);
}
}
}
// Returns an observation selection listener.
protected Listener<ObservationSelectionMessage> createObservationSelectionListener() {
return new Listener<ObservationSelectionMessage>() {
public void update(ObservationSelectionMessage message) {
// Move the cross hairs if we have date information since
// this plot's domain is JD.
if (message.getSource() != this && message.getObservation().getDateInfo() != null) {
chart.getXYPlot().setDomainCrosshairValue(message.getObservation().getJD());
chart.getXYPlot().setRangeCrosshairValue(message.getObservation().getMag());
updateSelectionFromObservation(message.getObservation());
}
}
public boolean canBeRemoved() {
return true;
}
};
}
// Returns a zoom request listener.
protected Listener<ZoomRequestMessage> createZoomRequestListener() {
return new Listener<ZoomRequestMessage>() {
public void update(ZoomRequestMessage info) {
if (Mediator.getInstance().getAnalysisType() == AnalysisType.RAW_DATA
&& Mediator.getInstance().getViewMode() == ViewModeType.PLOT_OBS_MODE) {
doZoom(info.getZoomType());
}
}
public boolean canBeRemoved() {
return true;
}
};
}
// Returns a pan request listener.
protected Listener<PanRequestMessage> createPanRequestListener() {
return new Listener<PanRequestMessage>() {
@Override
public void update(PanRequestMessage msg) {
final PlotRenderingInfo plotInfo = chartPanel.getChartRenderingInfo().getPlotInfo();
final Point2D source = new Point2D.Double(0, 0);
double percentage = 0.01;
XYPlot plot = chart.getXYPlot();
NewStarMessage newStarMsg = Mediator.getInstance().getLatestNewStarMessage();
List<ValidObservation> obs = newStarMsg.getObservations();
switch (msg.getPanType()) {
case LEFT:
if (plot.getDomainAxis().getLowerBound() >= obs.get(0).getJD()) {
plot.panDomainAxes(-percentage, plotInfo, source);
} else {
if (newStarMsg.getNewStarType() == NewStarType.NEW_STAR_FROM_DATABASE) {
// TODO: ask whether to read more AID data before
// last JD
}
}
break;
case RIGHT:
if (plot.getDomainAxis().getUpperBound() <= obs.get(obs.size() - 1).getJD()) {
plot.panDomainAxes(percentage, plotInfo, source);
} else {
if (newStarMsg.getNewStarType() == NewStarType.NEW_STAR_FROM_DATABASE) {
// TODO: ask whether to read more AID data after
// last JD
}
}
break;
case UP:
if (newStarMsg.getMinMag() <= plot.getRangeAxis().getLowerBound()) {
plot.panRangeAxes(percentage, plotInfo, source);
}
break;
case DOWN:
if (newStarMsg.getMaxMag() >= plot.getRangeAxis().getUpperBound()) {
plot.panRangeAxes(-percentage, plotInfo, source);
}
break;
}
}
@Override
public boolean canBeRemoved() {
return true;
}
};
}
}