/***************************************************************************** * Limpet - the Lightweight InforMation ProcEssing Toolkit * http://limpet.info * * (C) 2015-2016, Deep Blue C Technologies Ltd * * This library is free software; you can redistribute it and/or * modify it under the terms of the Eclipse Public License v1.0 * (http://www.eclipse.org/legal/epl-v10.html) * * This library 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. *****************************************************************************/ package info.limpet.ui.data_frequency; import info.limpet.ICollection; import info.limpet.IObjectCollection; import info.limpet.IQuantityCollection; import info.limpet.IStoreItem; import info.limpet.analysis.ObjectFrequencyBins; import info.limpet.analysis.ObjectFrequencyBins.BinnedData; import info.limpet.analysis.QuantityFrequencyBins; import info.limpet.analysis.QuantityFrequencyBins.Bin; import info.limpet.data.operations.CollectionComplianceTests; import info.limpet.ui.PlottingHelpers; import info.limpet.ui.core_view.CoreAnalysisView; import java.util.Iterator; import java.util.List; import javax.measure.quantity.Quantity; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.swtchart.Chart; import org.swtchart.IAxis; import org.swtchart.IBarSeries; import org.swtchart.ILineSeries; import org.swtchart.Range; import org.swtchart.ILineSeries.PlotSymbolType; import org.swtchart.ISeries; import org.swtchart.ISeries.SeriesType; import org.swtchart.ext.InteractiveChart; /** * display analysis overview of selection * * @author ian * */ public class DataFrequencyView extends CoreAnalysisView { private static final int MAX_SIZE = 2000; /** * The ID of the view as specified by the extension. */ public static final String ID = "info.limpet.ui.DataFrequencyView"; private Chart chart; /** * The constructor. */ public DataFrequencyView() { super(ID, "Data frequency"); } /** * This is a callback that will allow us to create the viewer and initialize it. */ public void createPartControl(Composite parent) { makeActions(); contributeToActionBars(); // create a chart chart = new InteractiveChart(parent, SWT.NONE); // set titles chart.getAxisSet().getXAxis(0).getTitle().setText("Value"); chart.getAxisSet().getYAxis(0).getTitle().setText("Frequency"); chart.getTitle().setVisible(false); // adjust the axis range chart.getAxisSet().adjustRange(); // register as selection listener setupListener(); } @Override public void display(List<IStoreItem> res) { if (res.size() == 0) { return; } // they're all the same type - check the first one Iterator<IStoreItem> iter = res.iterator(); ICollection first = (ICollection) iter.next(); // sort out what type of data this is. if (first.isQuantity()) { showQuantity(res); } else { showObject(res); } } private void showObject(List<IStoreItem> res) { Iterator<IStoreItem> iter = res.iterator(); // clear the graph ISeries[] coll = chart.getSeriesSet().getSeries(); for (int i = 0; i < coll.length; i++) { ISeries iSeries = coll[i]; chart.getSeriesSet().deleteSeries(iSeries.getId()); } while (iter.hasNext()) { ICollection iCollection = (ICollection) iter.next(); if (iCollection.getValuesCount() <= MAX_SIZE) { BinnedData bins = null; IObjectCollection<?> thisQ = (IObjectCollection<?>) iCollection; bins = ObjectFrequencyBins.doBins(thisQ); String seriesName = iCollection.getName(); IBarSeries newSeries = (IBarSeries) chart.getSeriesSet().createSeries(SeriesType.BAR, seriesName); newSeries.setBarColor(PlottingHelpers.colorFor(seriesName)); String[] xData = new String[bins.size()]; double[] yData = new double[bins.size()]; // put the data into series int ctr = 0; Iterator<ObjectFrequencyBins.Bin> iter2 = bins.iterator(); while (iter2.hasNext()) { ObjectFrequencyBins.Bin bin = (ObjectFrequencyBins.Bin) iter2.next(); xData[ctr] = (String) bin.getIndexVal(); yData[ctr++] = bin.getFreqVal(); } IAxis xAxis = chart.getAxisSet().getXAxis(0); xAxis.setCategorySeries(xData); xAxis.enableCategory(true); // newSeries.set(xData); newSeries.setYSeries(yData); // adjust the axis range chart.getAxisSet().adjustRange(); chart.redraw(); } } } @SuppressWarnings("unchecked") private void showQuantity(List<IStoreItem> res) { Iterator<IStoreItem> iter = res.iterator(); // clear the graph ISeries[] coll = chart.getSeriesSet().getSeries(); for (int i = 0; i < coll.length; i++) { ISeries iSeries = coll[i]; chart.getSeriesSet().deleteSeries(iSeries.getId()); } while (iter.hasNext()) { ICollection iCollection = (ICollection) iter.next(); QuantityFrequencyBins.BinnedData bins = null; if (iCollection.isQuantity() && iCollection.getValuesCount() > 1 && iCollection.getValuesCount() <= MAX_SIZE) { IQuantityCollection<Quantity> thisQ = (IQuantityCollection<Quantity>) iCollection; bins = QuantityFrequencyBins.doBins(thisQ); String seriesName = iCollection.getName() + " (" + thisQ.getUnits() + ")"; ILineSeries newSeries = (ILineSeries) chart.getSeriesSet().createSeries(SeriesType.LINE, seriesName); newSeries.setSymbolType(PlotSymbolType.NONE); newSeries.enableArea(true); newSeries.setLineColor(PlottingHelpers.colorFor(seriesName)); double[] xData = new double[bins.size() * 2]; double[] yData = new double[bins.size() * 2]; // put the data into series int ctr = 0; Iterator<Bin> iter2 = bins.iterator(); while (iter2.hasNext()) { Bin bin = (QuantityFrequencyBins.Bin) iter2.next(); xData[ctr] = bin.getLowerVal(); yData[ctr++] = bin.getFreqVal(); xData[ctr] = bin.getUpperVal(); yData[ctr++] = bin.getFreqVal(); } newSeries.setXSeries(xData); newSeries.setYSeries(yData); // adjust the axis range chart.getAxisSet().adjustRange(); IAxis xAxis = chart.getAxisSet().getXAxis(0); xAxis.enableCategory(false); // set the y axis min to be zero Range yRange = chart.getAxisSet().getYAxis(0).getRange(); chart.getAxisSet().getYAxis(0).setRange(new Range(0, yRange.upper)); chart.redraw(); } } } @Override public void setFocus() { chart.setFocus(); } @Override protected boolean appliesToMe(List<IStoreItem> selection, CollectionComplianceTests tests) { final boolean res; if (tests.allQuantity(selection)) { // ok, all quantities - that's easy res = true; } else if (tests.allNonQuantity(selection)) { if (tests.allNonLocation(selection)) { // none of them are locations - that's ok res = true; } else { // hmm, locations - scary. say no res = false; } } else { // mixed sorts, let's not bother res = false; } chart.setVisible(res); return res; } @Override protected String getTextForClipboard() { return "Pending"; } }