ucar.unidata.idv.control.chart.ScatterPlotChartWrapper.java Source code

Java tutorial

Introduction

Here is the source code for ucar.unidata.idv.control.chart.ScatterPlotChartWrapper.java

Source

/*
 * This file is part of McIDAS-V
 *
 * Copyright 2007-2019
 * Space Science and Engineering Center (SSEC)
 * University of Wisconsin - Madison
 * 1225 W. Dayton Street, Madison, WI 53706, USA
 * http://www.ssec.wisc.edu/mcidas
 * 
 * All Rights Reserved
 * 
 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
 * some McIDAS-V source code is based on IDV and VisAD source code.  
 * 
 * McIDAS-V is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 * 
 * McIDAS-V 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 Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 */

package ucar.unidata.idv.control.chart;

import org.jfree.chart.*;
import org.jfree.chart.axis.*;
import org.jfree.chart.labels.*;
import org.jfree.chart.plot.*;
import org.jfree.chart.renderer.*;
import org.jfree.chart.renderer.xy.*;
import org.jfree.data.*;
import org.jfree.data.time.*;
import org.jfree.data.xy.*;
import org.jfree.ui.*;

import ucar.unidata.data.DataCategory;
import ucar.unidata.data.DataChoice;

import ucar.unidata.data.sounding.TrackDataSource;
import ucar.unidata.util.GuiUtils;

import ucar.unidata.util.LogUtil;
import ucar.unidata.util.Misc;
import ucar.unidata.util.ObjectListener;
import ucar.unidata.util.TwoFacedObject;

import ucar.unidata.xml.XmlObjectStore;
import visad.*;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;

import java.rmi.RemoteException;

import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;

/**
 * Provides a scatter plot
 *
 *
 * @author IDV Development Team
 * @version $Revision: 1.41 $
 */
public class ScatterPlotChartWrapper extends PlotWrapper {

    /** The plot */
    private MyScatterPlot plot;

    /** The dataset */
    private XYSeriesCollection dataset;

    /** times */
    double[] timeValues1;

    /** times */
    double[] timeValues2;

    /**
     * Default ctor
     */
    public ScatterPlotChartWrapper() {
    }

    /**
     * Ctor
     *
     * @param name The name
     * @param dataChoices List of data choices
     */
    public ScatterPlotChartWrapper(String name, List dataChoices) {
        super(name, dataChoices);
    }

    /**
     * Return the human readable name of this chart
     *
     * @return Chart type name
     */
    public String getTypeName() {
        return "Scatter Plot";
    }

    /**
     * Handle the event
     *
     * @param event the event
     *
     * @return Should we pass on this event
     */
    public boolean chartPanelMouseClicked(MouseEvent event) {
        if (SwingUtilities.isRightMouseButton(event) || (event.getClickCount() < 2)) {
            return super.chartPanelMousePressed(event);
        }
        List series = ((MyScatterPlot) plot).getSeries();
        //TODO: Check if click is inside data area
        double minDistance = 100;
        int minIdx = -1;
        double minTime = -1;
        for (int seriesIdx = 0; seriesIdx < series.size(); seriesIdx++) {
            NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis(seriesIdx);
            NumberAxis domainAxis = (NumberAxis) plot.getDomainAxis(seriesIdx);
            double[][] data = (double[][]) series.get(seriesIdx);
            for (int i = 0; i < data[0].length; i++) {
                double x = domainAxis.valueToJava2D(data[0][i], getChartPanel().getScreenDataArea(),
                        plot.getDomainAxisEdge());
                double y = rangeAxis.valueToJava2D(data[1][i], getChartPanel().getScreenDataArea(),
                        plot.getRangeAxisEdge());

                double distance = Math
                        .sqrt((x - event.getX()) * (x - event.getX()) + (y - event.getY()) * (y - event.getY()));
                if (distance < minDistance) {
                    minDistance = distance;
                    minIdx = i;
                }
            }
            if (minIdx >= 0) {
                minTime = timeValues1[minIdx];
            }
        }
        if (minIdx < 0) {
            return EVENT_PASSON;
        }
        firePropertyChange(PROP_SELECTEDTIME, null, new Double(minTime));
        return EVENT_PASSON;
    }

    /**
     * Get the data categories for choosing new data
     *
     * @return data categories
     */
    public List getCategories() {
        //Return a list of data categories for each parameter we are selecting
        List cats = DataCategory.parseCategories("trace;IMAGE-2D-*", false);
        return Misc.newList(cats, cats);
    }

    /**
     * Create the chart
     */
    private void createChart() {
        if (chartPanel != null) {
            return;
        }
        // create a dataset...
        XYSeries series1 = new XYSeries("Series 1");
        dataset = new XYSeriesCollection(series1);

        String name = getName();
        if (name == null) {
            name = "Scatter Plot";
        }
        // create the chart...
        chart = createScatterPlot(name, "Domain", "Range", PlotOrientation.VERTICAL, true, false, false);

        initXYPlot(plot);
        plot.setRenderer(new MyRenderer(LineState.SHAPE_POINT));
        doMakeChartPanel(chart);
    }

    /**
     * Create the gui
     *
     * @return The  gui
     */
    protected JComponent doMakeContents() {
        createChart();
        return chartPanel;
    }

    /**
     * Just a hook to turn off the series display in the legend and to
     * hold the shape to draw.
     *
     *
     * @author IDV Development Team
     * @version $Revision: 1.41 $
     */
    public static class MyRenderer extends XYLineAndShapeRenderer {

        /** The shape */
        int shape;

        /**
         * ctor
         *
         * @param shape The shape
         */
        public MyRenderer(int shape) {
            super(false, true);
            this.shape = shape;
        }

        /**
         * draw series in legend
         *
         * @param i which series
         *
         * @return draw series in legend
         */
        public boolean isSeriesVisibleInLegend(int i) {
            return false;
        }
    }

    /**
     * Hook to intercept these calls on the chart
     *
     * @param event The event
     *
     * @return  Was this event handled by the ChartWrapper
     */
    public String chartPanelGetToolTipText(MouseEvent event) {
        return "Right click to show menu; Double click to set time in other charts";
    }

    /**
     * Create the scatter plit
     *
     * @param title  title
     * @param xAxisLabel  xAxisLabel
     * @param yAxisLabel  yAxisLabel
     * @param orientation  orientation
     * @param legend  legend
     * @param tooltips  tooltips
     * @param urls  urls
     *
     * @return The chart
     */
    private JFreeChart createScatterPlot(String title, String xAxisLabel, String yAxisLabel,
            PlotOrientation orientation, boolean legend, boolean tooltips, boolean urls) {

        if (orientation == null) {
            throw new IllegalArgumentException("Null 'orientation' argument.");
        }
        NumberAxis xAxis = new NumberAxis(xAxisLabel);
        xAxis.setAutoRangeIncludesZero(false);
        NumberAxis yAxis = new NumberAxis(yAxisLabel);
        yAxis.setAutoRangeIncludesZero(false);

        plot = new MyScatterPlot(dataset, null, xAxis, yAxis);
        JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot, legend);

        return chart;
    }

    /**
     * Apply properties
     *
     *
     * @return Successful
     */
    protected boolean applyProperties() {
        if (!super.applyProperties()) {
            return false;
        }
        return true;
    }

    /**
     * Create the charts
     *
     * @throws RemoteException On badness
     * @throws VisADException On badness
     */
    public void loadData() throws VisADException, RemoteException {

        try {
            createChart();
            for (int dataSetIdx = 0; dataSetIdx < plot.getDatasetCount(); dataSetIdx++) {
                XYSeriesCollection dataset = (XYSeriesCollection) plot.getDataset(dataSetIdx);
                dataset.removeAllSeries();
            }
            ((MyScatterPlot) plot).removeAllSeries();
            Hashtable props = new Hashtable();
            props.put(TrackDataSource.PROP_TRACKTYPE, TrackDataSource.ID_TIMETRACE);

            List dataChoiceWrappers = getDataChoiceWrappers();
            int dataSetCnt = 0;
            for (int paramIdx = 0; paramIdx < dataChoiceWrappers.size(); paramIdx += 2) {
                if (paramIdx + 1 >= dataChoiceWrappers.size()) {
                    break;
                }
                DataChoiceWrapper wrapper1 = (DataChoiceWrapper) dataChoiceWrappers.get(paramIdx);
                DataChoiceWrapper wrapper2 = (DataChoiceWrapper) dataChoiceWrappers.get(paramIdx + 1);

                DataChoice dataChoice1 = wrapper1.getDataChoice();
                DataChoice dataChoice2 = wrapper2.getDataChoice();

                FlatField data1 = getFlatField((FieldImpl) dataChoice1.getData(null, props));
                FlatField data2 = getFlatField((FieldImpl) dataChoice2.getData(null, props));
                Unit unit1 = ucar.visad.Util.getDefaultRangeUnits((FlatField) data1)[0];
                Unit unit2 = ucar.visad.Util.getDefaultRangeUnits((FlatField) data2)[0];

                NumberAxis rangeAxis = new NumberAxis(wrapper2.getLabel(unit2));
                NumberAxis domainAxis = new NumberAxis(wrapper1.getLabel(unit1));

                domainAxis.setAutoRange(getAutoRange());

                Color c = wrapper1.getColor(paramIdx);
                MyRenderer renderer = new MyRenderer(wrapper1.getLineState().getShape());
                domainAxis.setLabelPaint(c);
                rangeAxis.setLabelPaint(c);
                renderer.setSeriesPaint(0, c);

                double[][] samples1 = data1.getValues(false);
                double[][] samples2 = data2.getValues(false);
                double[] timeValues1 = getTimeValues(samples1, data1);
                double[] timeValues2 = getTimeValues(samples2, data2);
                double[][] values1 = filterData(samples1[0], timeValues1);
                double[][] values2 = filterData(samples2[0], timeValues2);
                if (values1.length > 1) {
                    this.timeValues1 = values1[1];
                    this.timeValues2 = values2[1];
                }
                double[][] values = { values1[0], values2[0] };
                ((MyScatterPlot) plot).addSeries(values);

                //Add in a dummy dataset
                XYSeriesCollection dataset = new XYSeriesCollection(new XYSeries(""));

                if (!getAutoRange()) {
                    NumberAxis oldRangeAxis = (NumberAxis) plot.getRangeAxis(dataSetCnt);
                    NumberAxis oldDomainAxis = (NumberAxis) plot.getDomainAxis(dataSetCnt);
                    if ((oldRangeAxis != null) && (oldDomainAxis != null)) {
                        rangeAxis.setRange(oldRangeAxis.getRange());
                        domainAxis.setRange(oldDomainAxis.getRange());
                    }
                }

                plot.setDataset(dataSetCnt, dataset);
                plot.setRenderer(dataSetCnt, renderer);
                plot.setRangeAxis(dataSetCnt, rangeAxis, false);
                plot.setDomainAxis(dataSetCnt, domainAxis, false);
                plot.mapDatasetToRangeAxis(dataSetCnt, dataSetCnt);
                plot.mapDatasetToDomainAxis(dataSetCnt, dataSetCnt);

                if (!getAutoRange()) {
                    rangeAxis.setAutoRange(false);
                    domainAxis.setAutoRange(false);
                }

                dataSetCnt++;
            }
        } catch (Exception exc) {
            LogUtil.logException("Error creating data set", exc);
        }

    }

    /**
     * Utility to make the gui widget for the wrapper in the properties list
     *
     * @param idx Which one
     * @param fieldProperty Holder of stuff
     *
     * @return The gui
     */
    protected JComponent doMakeWrapperDisplayComponent(int idx, FieldProperties fieldProperty) {
        if (idx % 2 != 0) {
            return new JLabel(" ");
        }
        LineState ls = fieldProperty.wrapper.getLineState();
        XmlObjectStore store = getDisplayControl().getControlContext().getIdv().getStore();
        ls.getPropertyContents(store);
        List comps = new ArrayList();
        comps.add(GuiUtils.inset(ls.colorSwatch, 4));
        comps.add(ls.shapeBox);
        return GuiUtils.left(GuiUtils.hbox(comps, 4));
    }

    /**
     * Returns the list of labels used for selecting data choices.
     *
     * @return List of field labels
     */
    public List getFieldSelectionLabels() {
        return Misc.newList("X Axis Field", "Y Axis Field");
    }

    /**
     * When selecting data does the data tree support multiple selections
     *
     * @return Do multiples
     */
    public boolean doMultipleAddFields() {
        return false;
    }

    /**
     * Don't add parameters
     *
     * @return Don't add parameters
     */
    public boolean canDoParameters() {
        return true;
    }

    /**
     * canBeASourceForTimeSelectionEvents
     *
     * @return true
     */
    protected boolean canBeASourceForTimeSelectionEvents() {
        return true;
    }

    /**
     * Can we do chart colors
     *
     * @return can do colors
     */
    protected boolean canDoColors() {
        return true;
    }

    /**
     * Can we have colors on the data chocie wrappers in the properties dialog
     *
     * @return can do wrapper color
     */
    public boolean canDoWrapperColor() {
        return true;
    }

    /**
     * to string
     *
     * @return string
     */
    public String toString() {
        return "Scatter Plot: " + getName();
    }

}