/*
* Copyright (C) 2013 Serdar
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.fub.maps.project.detector.model.statistics;
import de.fub.maps.project.detector.model.TrainingsDataProvider;
import de.fub.maps.project.detector.model.gpx.TrackSegment;
import de.fub.maps.project.detector.model.inference.features.TrackLengthFeatureProcess;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import org.netbeans.api.annotations.common.StaticResource;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.netbeans.core.spi.multiview.CloseOperationState;
import org.netbeans.core.spi.multiview.MultiViewElement;
import org.netbeans.core.spi.multiview.MultiViewElementCallback;
import org.openide.awt.UndoRedo;
import org.openide.util.ImageUtilities;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
import org.openide.util.lookup.Lookups;
import org.openide.util.lookup.ProxyLookup;
import org.openide.windows.TopComponent;
/**
*
* @author Serdar
*/
@MultiViewElement.Registration(
displayName = "#LBL_Detector_TrainingData_Analyzer_VISUAL",
mimeType = "text/detector+xml",
persistenceType = TopComponent.PERSISTENCE_NEVER,
preferredID = "DetectorAnalyzerVisual",
position = 1200)
@NbBundle.Messages({
"LBL_Detector_TrainingData_Analyzer_VISUAL=Data Analyzer"
})
public class TrainingDataAnalyizerComponent extends JPanel implements MultiViewElement {
@StaticResource
private static final String REFRESH_BUTTON_ICON_PATH = "de/fub/maps/project/detector/model/statistics/refreshIcon.png";
private static final Logger LOG = Logger.getLogger(TrainingDataAnalyizerComponent.class.getName());
private static final long serialVersionUID = 1L;
private JToolBar toolbar = null;
private MultiViewElementCallback callback;
private Lookup lookup;
private final Object UPDATE_MUTEX = new Object();
private TrainingsDataProvider dataProvider;
private JButton refreshButton;
/**
* Creates new form TrainingDataAnalyizerComponent
*/
public TrainingDataAnalyizerComponent() {
initComponents();
addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
int height = 0;
for (Component component : contentPanel.getComponents()) {
height += component.getPreferredSize().height;
}
contentPanel.setPreferredSize(new Dimension(0, height));
}
});
}
public TrainingDataAnalyizerComponent(Lookup lookup) {
this();
this.lookup = new ProxyLookup(lookup, Lookups.singleton(contentPanel));
}
private TrainingsDataProvider getDataProvider() {
if (dataProvider == null) {
Collection<? extends TrainingsDataProvider> allInstances = lookup.lookupResult(TrainingsDataProvider.class).allInstances();
if (!allInstances.isEmpty()) {
dataProvider = allInstances.iterator().next();
}
}
return dataProvider;
}
@Override
public String getName() {
return "DetectorAnalyzerVisual";
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
contentPanel = new javax.swing.JPanel();
barChartContainer1 = new TransportModeDataLengthChart();
filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 8), new java.awt.Dimension(0, 8), new java.awt.Dimension(32767, 8));
barChartContainer2 = new SegmentLengthHistogramChart();
filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 8), new java.awt.Dimension(0, 8), new java.awt.Dimension(32767, 8));
barChartContainer3 = new AvgPointBarChart();
setLayout(new java.awt.BorderLayout());
contentPanel.setBackground(new java.awt.Color(255, 255, 255));
contentPanel.setPreferredSize(new java.awt.Dimension(0, 0));
contentPanel.setLayout(new javax.swing.BoxLayout(contentPanel, javax.swing.BoxLayout.PAGE_AXIS));
barChartContainer1.setMaximumSize(new java.awt.Dimension(2147483647, 300));
barChartContainer1.setMinimumSize(new java.awt.Dimension(102, 250));
barChartContainer1.setPreferredSize(new java.awt.Dimension(682, 300));
contentPanel.add(barChartContainer1);
contentPanel.add(filler1);
barChartContainer2.setMaximumSize(new java.awt.Dimension(2147483647, 300));
barChartContainer2.setMinimumSize(new java.awt.Dimension(102, 250));
barChartContainer2.setPreferredSize(new java.awt.Dimension(682, 300));
contentPanel.add(barChartContainer2);
contentPanel.add(filler2);
barChartContainer3.setMaximumSize(new java.awt.Dimension(2147483647, 300));
barChartContainer3.setMinimumSize(new java.awt.Dimension(102, 250));
contentPanel.add(barChartContainer3);
jScrollPane1.setViewportView(contentPanel);
add(jScrollPane1, java.awt.BorderLayout.CENTER);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private de.fub.maps.project.detector.model.statistics.BarChartContainer barChartContainer1;
private de.fub.maps.project.detector.model.statistics.BarChartContainer barChartContainer2;
private de.fub.maps.project.detector.model.statistics.BarChartContainer barChartContainer3;
private javax.swing.JPanel contentPanel;
private javax.swing.Box.Filler filler1;
private javax.swing.Box.Filler filler2;
private javax.swing.JScrollPane jScrollPane1;
// End of variables declaration//GEN-END:variables
@Override
public JComponent getVisualRepresentation() {
return this;
}
@Override
public JComponent getToolbarRepresentation() {
if (toolbar == null) {
toolbar = new JToolBar();
toolbar.addSeparator();
toolbar.add(getRefreshButton());
}
return toolbar;
}
private JButton getRefreshButton() {
if (refreshButton == null) {
ImageIcon imageIcon = ImageUtilities.loadImageIcon(REFRESH_BUTTON_ICON_PATH, false);
refreshButton = new JButton(imageIcon);
refreshButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateViewAsync();
}
});
}
return refreshButton;
}
@Override
public Action[] getActions() {
Action[] retValue;
// the multiviewObserver was passed to the element in setMultiViewCallback() method.
if (callback != null) {
retValue = callback.createDefaultActions();
// add you own custom actions here..
} else {
// fallback..
retValue = new Action[0];
}
return retValue;
}
@Override
public Lookup getLookup() {
return lookup;
}
@Override
public void componentOpened() {
updateViewAsync();
}
@Override
public void componentClosed() {
}
@NbBundle.Messages({
"CLT_Analyzer_DisplayName=Data Analyzer"
})
@Override
public void componentShowing() {
if (callback != null && getDataProvider() != null) {
String displayNString = MessageFormat.format("{0}[{1}]",
getDataProvider().getName(), Bundle.CLT_Analyzer_DisplayName());
TopComponent topComponent = callback.getTopComponent();
topComponent.setDisplayName(displayNString);
topComponent.setHtmlDisplayName(displayNString);
}
}
@Override
public void componentHidden() {
}
@Override
public void componentActivated() {
}
@Override
public void componentDeactivated() {
}
@Override
public UndoRedo getUndoRedo() {
return UndoRedo.NONE;
}
@Override
public void setMultiViewCallback(MultiViewElementCallback callback) {
this.callback = callback;
}
@Override
public CloseOperationState canCloseElement() {
return CloseOperationState.STATE_OK;
}
private void updateViewAsync() {
RequestProcessor.getDefault().post(new Runnable() {
@Override
public void run() {
getRefreshButton().setEnabled(false);
ProgressHandle handle = ProgressHandleFactory.createHandle("Analysing data...");
try {
handle.start();
updateView();
} finally {
handle.finish();
getRefreshButton().setEnabled(true);
}
}
});
}
private void updateView() {
synchronized (UPDATE_MUTEX) {
if (getDataProvider() != null) {
Map<String, List<TrackSegment>> data = getDataProvider().getData();
ArrayList<Double> histogramDatalist = new ArrayList<Double>();
ArrayList<String> keys = new ArrayList<String>(data.keySet());
Collections.sort(keys);
for (String key : keys) {
double pointCount = 0;
TrackLengthFeatureProcess feature = new TrackLengthFeatureProcess();
double length = 0;
for (TrackSegment trackSegment : data.get(key)) {
pointCount += trackSegment.getWayPointList().size();
feature.setInput(trackSegment);
feature.run();
double result = feature.getResult();
length += result;
histogramDatalist.add(result);
}
updateBarChart(length, key, data.values().size());
updateAvgPointBarChart(pointCount / data.get(key).size(), key);
}
updateHistogramChart(histogramDatalist);
}
}
}
private void updateHistogramChart(final ArrayList<Double> valueList) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
final String _0_TO_50_METER = "0-50";
final String _50_TO_100_METER = "50-100";
final String _100_TO_200_METER = "100-200";
final String _200_TO_300_METER = "200-300";
final String _300_TO_400_METER = "300-400";
final String _400_TO_500_METER = "400-500";
final String _500_TO_600_METER = "500-600";
final String _600_TO_700_METER = "600-700";
final String _700_TO_800_METER = "700-800";
final String _800_TO_900_METER = "800-900";
final String _900_TO_1000_METER = "900-1000";
final String _1000_METER = "> 1000";
HashMap<String, Integer> bins = new HashMap<String, Integer>();
String binKey = null;
int totalCount = 0;
for (Double value : valueList) {
if (value > 0 && value <= 50) {
binKey = _0_TO_50_METER;
} else if (value > 51 && value <= 100) {
binKey = _50_TO_100_METER;
} else if (value > 100 && value <= 200) {
binKey = _100_TO_200_METER;
} else if (value > 200 && value <= 300) {
binKey = _200_TO_300_METER;
} else if (value > 300 && value <= 400) {
binKey = _300_TO_400_METER;
} else if (value > 400 && value <= 500) {
binKey = _400_TO_500_METER;
} else if (value > 500 && value <= 600) {
binKey = _500_TO_600_METER;
} else if (value > 600 && value <= 700) {
binKey = _600_TO_700_METER;
} else if (value > 700 && value <= 800) {
binKey = _700_TO_800_METER;
} else if (value > 800 && value <= 900) {
binKey = _800_TO_900_METER;
} else if (value > 900 && value <= 1000) {
binKey = _900_TO_1000_METER;
} else if (value > 1000) {
binKey = _1000_METER;
}
if (binKey != null) {
if (!bins.containsKey(binKey)) {
bins.put(binKey, 0);
}
Integer count = bins.get(binKey);
count = count + 1;
bins.put(binKey, count);
totalCount++;
}
}
List<String> keys = Arrays.asList(_0_TO_50_METER, _50_TO_100_METER,
_100_TO_200_METER, _200_TO_300_METER,
_300_TO_400_METER, _400_TO_500_METER,
_500_TO_600_METER, _600_TO_700_METER,
_700_TO_800_METER, _800_TO_900_METER,
_900_TO_1000_METER, _1000_METER);
for (String key : keys) {
if (bins.containsKey(key)) {
barChartContainer2.getDataset().addValue(bins.get(key) / (double) totalCount * 100, "Segment length", key);
}
}
} catch (Exception ex) {
LOG.severe(MessageFormat.format("Exception at value: {0}", valueList));
}
}
});
}
private void updateBarChart(final double length, final String transportMode, final int size) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
barChartContainer1.getDataset().addValue(length / 1000, "Total Length", transportMode);
barChartContainer1.getDataset().addValue(length / 1000 / size, "Avg. Segment Length", transportMode);
}
});
}
private void updateAvgPointBarChart(double d, String transportMode) {
barChartContainer3.getDataset().addValue(d, transportMode, "Average Point per");
}
private static class TransportModeDataLengthChart extends BarChartContainer {
private static final long serialVersionUID = 1L;
public TransportModeDataLengthChart() {
super();
init();
}
private void init() {
setTitle("Training Data Set");
getPlot().getRenderer().setSeriesPaint(1, Color.red);
getRangeAxis().setLabel(NbBundle.getMessage(TrainingDataAnalyizerComponent.class, "TransportModeDataLengthChart.value.axis.name"));
getDomainAxis().setLabel(NbBundle.getMessage(TrainingDataAnalyizerComponent.class, "TransportModeDataLengthChart.domain.axis.name"));
getRangeAxis().setUpperMargin(.1);
}
}
private static class AvgPointBarChart extends BarChartContainer {
private static final long serialVersionUID = 1L;
public AvgPointBarChart() {
super();
init();
}
private void init() {
setTitle("Average Point Count per Segment");
getPlot().getRenderer().setSeriesPaint(1, Color.red);
getRangeAxis().setLabel(NbBundle.getMessage(TrainingDataAnalyizerComponent.class, "AvgPointBarChart.value.axis.name"));
getDomainAxis().setLabel(NbBundle.getMessage(TrainingDataAnalyizerComponent.class, "AvgPointBarChart.domain.axis.name"));
getRangeAxis().setUpperMargin(.1);
}
}
private static class SegmentLengthHistogramChart extends BarChartContainer {
private static final long serialVersionUID = 1L;
public SegmentLengthHistogramChart() {
super();
init();
}
private void init() {
setTitle("Segment length Histogramm");
getRangeAxis().setLabel(NbBundle.getMessage(TrainingDataAnalyizerComponent.class, "SegmentLengthHistogramChart.value.axis.name"));
getDomainAxis().setLabel(NbBundle.getMessage(TrainingDataAnalyizerComponent.class, "SegmentLengthHistogramChart.domain.axis.name"));
// getRangeAxis().setRange(0, 100);
getRangeAxis().setAutoRange(true);
getRangeAxis().setUpperMargin(.1);
getBarChart().removeLegend();
}
}
}