ucar.unidata.idv.control.McVHistogramWrapper.java Source code

Java tutorial

Introduction

Here is the source code for ucar.unidata.idv.control.McVHistogramWrapper.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;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JMenuItem;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
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.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StackedXYBarRenderer;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.Range;
import org.jfree.data.statistics.HistogramType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ucar.unidata.data.DataChoice;
import ucar.unidata.data.grid.GridUtil;
import ucar.unidata.idv.DisplayControl;
import ucar.unidata.idv.control.chart.DataChoiceWrapper;
import ucar.unidata.idv.control.chart.HistogramWrapper;
import ucar.unidata.idv.control.chart.MyHistogramDataset;
import ucar.unidata.idv.control.multi.DisplayGroup;
import ucar.unidata.ui.ImageUtils;
import ucar.unidata.util.FileManager;
import ucar.unidata.util.GuiUtils;
import ucar.unidata.util.LogUtil;

import visad.ErrorEstimate;
import visad.FlatField;
import visad.Unit;
import visad.VisADException;

/**
 * Wraps a JFreeChart histogram to ease working with VisAD data.
 */

public class McVHistogramWrapper extends HistogramWrapper {

    /** _more_ */
    private static final Logger logger = LoggerFactory.getLogger(McVHistogramWrapper.class);

    /** _more_ */
    private DisplayControl imageControl;

    /** _more_ */
    private double low;

    /** _more_ */
    private double high;

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

    /**
     * Ctor
     *
     * @param name The name.
     * @param dataChoices List of data choices.
     * @param control {@literal "Parent"} control.
     */
    public McVHistogramWrapper(String name, List dataChoices, DisplayControlImpl control) {
        super(name, dataChoices);
        imageControl = control;
    }

    /**
     * Create the histogram.
     * 
     * @return GUI contents.
     */
    public JComponent doMakeContents() {
        // made public so that things like MultispectralControl can work
        return super.doMakeContents();
    }

    /**
     * Clear the histogram.
     */
    public void clearHistogram() {
        if (chartPanel != null) {
            XYPlot tempPlot = chartPanel.getChart().getXYPlot();
            for (int i = 0; i < tempPlot.getDatasetCount(); i++) {
                MyHistogramDataset dataset = (MyHistogramDataset) tempPlot.getDataset(i);
                if (dataset != null) {
                    dataset.removeAllSeries();
                }
            }
        }
    }

    /**
     * _more_
     */
    public void saveImage() {
        JComboBox publishCbx = imageControl.getViewManager().getPublishManager().getSelector("nc.export");
        String filename = FileManager.getWriteFile(FileManager.FILTER_IMAGE, FileManager.SUFFIX_JPG,
                ((publishCbx != null) ? GuiUtils.top(publishCbx) : null));
        if (filename == null) {
            return;
        }
        try {
            ImageUtils.writeImageToFile(getContents(), filename);
            imageControl.getViewManager().getPublishManager().publishContent(filename, null, publishCbx);
        } catch (Exception exc) {
            LogUtil.logException("Capturing image", exc);
        }
    }

    /**
     * Create the histogram.
     *
     * @param data Data to use in histogram.
     *
     * @throws IllegalArgumentException if {@code data} is all NaNs.
     * @throws RemoteException On badness
     * @throws VisADException On badness
     */
    public void loadData(FlatField data) throws IllegalArgumentException, RemoteException, VisADException {
        if ((data != null) && !GridUtil.isAllMissing(data)) {
            reallyLoadData(data);
        } else {
            throw new IllegalArgumentException("Nothing to show in histogram");
        }
    }

    /**
     * Assumes that {@code data} has been validated and is okay to actually try
     * loading.
     *
     * @param data Data to use in histogram. Cannot be {@code null} or all NaNs.
     *
     * @throws VisADException
     * @throws RemoteException
     */
    private void reallyLoadData(FlatField data) throws VisADException, RemoteException {
        createChart();
        List dataChoiceWrappers = getDataChoiceWrappers();

        try {
            clearHistogram();

            ErrorEstimate[] errOut = new ErrorEstimate[1];
            for (int paramIdx = 0; paramIdx < dataChoiceWrappers.size(); paramIdx++) {
                DataChoiceWrapper wrapper = (DataChoiceWrapper) dataChoiceWrappers.get(paramIdx);

                DataChoice dataChoice = wrapper.getDataChoice();
                Unit defaultUnit = ucar.visad.Util.getDefaultRangeUnits((FlatField) data)[0];
                Unit unit = ((DisplayControlImpl) imageControl).getDisplayUnit();
                double[][] samples = data.getValues(false);
                double[] actualValues = filterData(samples[0], getTimeValues(samples, data))[0];
                if ((defaultUnit != null) && !defaultUnit.equals(unit)) {
                    actualValues = Unit.transformUnits(unit, errOut, defaultUnit, null, actualValues);
                }
                final NumberAxis domainAxis = new NumberAxis(wrapper.getLabel(unit));

                domainAxis.setAutoRangeIncludesZero(false);

                XYItemRenderer renderer;
                if (getStacked()) {
                    renderer = new StackedXYBarRenderer();
                } else {
                    renderer = new XYBarRenderer();
                }
                if ((plot == null) && (chartPanel != null)) {
                    plot = chartPanel.getChart().getXYPlot();
                }
                plot.setRenderer(paramIdx, renderer);
                Color c = wrapper.getColor(paramIdx);
                domainAxis.setLabelPaint(c);
                renderer.setSeriesPaint(0, c);

                MyHistogramDataset dataset = new MyHistogramDataset();
                dataset.setType(HistogramType.FREQUENCY);
                dataset.addSeries(dataChoice.getName() + " [" + unit + ']', actualValues, getBins());
                samples = null;
                actualValues = null;
                plot.setDomainAxis(paramIdx, domainAxis, false);
                plot.mapDatasetToDomainAxis(paramIdx, paramIdx);
                plot.setDataset(paramIdx, dataset);

                domainAxis.addChangeListener(new AxisChangeListener() {
                    public void axisChanged(AxisChangeEvent ae) {
                        if (!imageControl.isInitDone()) {
                            return;
                        }

                        Range range = domainAxis.getRange();
                        double newLow = Math.floor(range.getLowerBound() + 0.5);
                        double newHigh = Math.floor(range.getUpperBound() + 0.5);
                        double prevLow = getLow();
                        double prevHigh = getHigh();
                        try {
                            ucar.unidata.util.Range newRange;
                            if (prevLow > prevHigh) {
                                newRange = new ucar.unidata.util.Range(newHigh, newLow);
                            } else {
                                newRange = new ucar.unidata.util.Range(newLow, newHigh);
                            }
                            ((DisplayControlImpl) imageControl).setRange(newRange);
                        } catch (Exception e) {
                            logger.error("Cannot change range", e);
                        }
                    }
                });

                Range range = domainAxis.getRange();
                low = range.getLowerBound();
                high = range.getUpperBound();
            }

        } catch (Exception exc) {
            System.out.println("Exception exc=" + exc);
            LogUtil.logException("Error creating data set", exc);
        }
    }

    /**
     * Modify the low and high values of the domain axis.
     *
     * @param lowVal Low value.
     * @param hiVal High value.
     *
     * @return {@code false} if {@link #plot} is {@code null}. {@code true}
     * otherwise.
     */
    public boolean modifyRange(double lowVal, double hiVal) {
        return modifyRange(lowVal, hiVal, true);
    }

    /**
     * Modify the low and high values of the domain axis.
     *
     * @param lowVal Low value.
     * @param hiVal High value.
     * @param notify Whether or not listeners should be notified.
     *
     * @return {@code false} if {@link #plot} is {@code null}. {@code true}
     * otherwise.
     */
    public boolean modifyRange(double lowVal, double hiVal, boolean notify) {
        try {
            if (plot == null) {
                return false;
            }
            ValueAxis domainAxis = plot.getDomainAxis();
            org.jfree.data.Range newRange = new org.jfree.data.Range(lowVal, hiVal);
            domainAxis.setRange(newRange, domainAxis.isAutoRange(), notify);
            return true;
        } catch (Exception e) {
            return true;
        }
    }

    /**
     * _more_
     *
     * @return _more_
     */
    public Range getRange() {
        ValueAxis domainAxis = plot.getDomainAxis();
        return domainAxis.getRange();
    }

    /**
     * _more_
     */
    public void doReset() {
        resetPlot();
    }

    /**
     * reset the histogram to its previous range
     */
    public void resetPlot() {
        if (chart == null) {
            return;
        }
        if (!(chart.getPlot() instanceof XYPlot)) {
            return;
        }
        XYPlot plot = (XYPlot) chart.getPlot();
        int rcnt = plot.getRangeAxisCount();
        for (int i = 0; i < rcnt; i++) {
            ValueAxis axis = plot.getRangeAxis(i);
            axis.setAutoRange(true);
        }
        int dcnt = plot.getDomainAxisCount();
        for (int i = 0; i < dcnt; i++) {
            ValueAxis axis = plot.getDomainAxis(i);
            try {
                axis.setRange(low, high);
            } catch (Exception e) {
                logger.warn("jfreechart does not like ranges to be high -> low", e);
            }
        }
    }

    /**
     * _more_
     *
     * @return _more_
     */
    public double getLow() {
        return low;
    }

    /**
     * _more_
     *
     * @param val _more_
     */
    public void setLow(double val) {
        low = val;
    }

    /**
     * _more_
     *
     * @return _more_
     */
    public double getHigh() {
        return high;
    }

    /**
     * _more_
     *
     * @param val _more_
     */
    public void setHigh(double val) {
        high = val;
    }

    /**
     * SHow the popup menu
     *
     * @param where component to show near to
     * @param x x
     * @param y y
     */
    @Override
    public void showPopup(JComponent where, int x, int y) {
        List items = new ArrayList();
        items = getPopupMenuItems(items);
        if (items.isEmpty()) {
            return;
        }
        GuiUtils.makePopupMenu(items).show(where, x, y);
    }

    /**
     * Add the default menu items
     *
     * @param items List of menu items
     *
     * @return The items list
     */
    @Override
    public List getPopupMenuItems(List items) {
        items = super.getPopupMenuItems(items);
        for (Object o : items) {
            if (o instanceof JMenuItem) {
                JMenuItem menuItem = (JMenuItem) o;
                if ("Properties...".equals(menuItem.getText())) {
                    if (menuItem.getActionListeners().length == 0) {
                        menuItem.setActionCommand(ChartPanel.PROPERTIES_COMMAND);
                        menuItem.addActionListener(buildHistoPropsListener());
                    }
                }
            }
        }
        return items;
    }

    /**
     * @return {@link ActionListener} that listens for
     * {@link ChartPanel#PROPERTIES_COMMAND} events and shows the histogram
     * properties.
     */
    private ActionListener buildHistoPropsListener() {
        return new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                String command = event.getActionCommand();
                if (ChartPanel.PROPERTIES_COMMAND.equals(command)) {
                    McVHistogramWrapper.this.showProperties();
                    return;
                }
            }
        };
    }

    /**
     * Show the properties dialog
     *
     * @return Was it ok
     */
    @Override
    public boolean showProperties() {
        boolean result;
        if (!hasDisplayControl()) {
            result = showProperties(null, 0, 0);
        } else {
            result = super.showProperties();
        }
        return result;
    }

    /**
     * _more_
     *
     * @return _more_
     */
    public boolean hasDisplayControl() {
        return getDisplayControl() != null;
    }

    /**
     * Remove me
     *
     * @return was removed
     */
    public boolean removeDisplayComponent() {
        if (GuiUtils.askYesNo("Remove Display", "Are you sure you want to remove: " + toString())) {
            DisplayGroup displayGroup = getDisplayGroup();
            if (displayGroup != null) {
                displayGroup.removeDisplayComponent(this);
            }

            if (hasDisplayControl()) {
                getDisplayControl().removeDisplayComponent(this);
            }
            return true;
        } else {
            return false;
        }
    }

    /**
     * Attempt to apply property changes.
     * 
     * @return {@code true} if properties were changed, 
     *         {@code false} otherwise.
     */
    @Override
    protected boolean doApplyProperties() {
        if (!applyProperties()) {
            return false;
        }
        try {
            loadData();
        } catch (Exception exc) {
            LogUtil.logException("Error loading data", exc);
            return false;
        }
        if (getDisplayControl() != null) {
            getDisplayControl().componentChanged();
        }
        return true;
    }

    /**
     * Been removed, do any cleanup
     */
    @Override
    public void doRemove() {
        isRemoved = true;
        List displayables = getDisplayables();
        if (hasDisplayControl() && !displayables.isEmpty()) {
            getDisplayControl().removeDisplayables(displayables);
        }
        firePropertyChange(PROP_REMOVED, null, this);
    }
}