209 lines
7.3 KiB
Java
209 lines
7.3 KiB
Java
|
/*
|
||
|
* Copyright 2015 Alexander Nozik.
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
package inr.numass.viewer;
|
||
|
|
||
|
/*
|
||
|
* To change this license header, choose License Headers in Project Properties.
|
||
|
* To change this template file, choose Tools | Templates
|
||
|
* and open the template in the editor.
|
||
|
*/
|
||
|
import hep.dataforge.data.DataPoint;
|
||
|
import hep.dataforge.data.MapDataPoint;
|
||
|
import hep.dataforge.exceptions.StorageException;
|
||
|
import hep.dataforge.storage.api.PointLoader;
|
||
|
import hep.dataforge.storage.api.Storage;
|
||
|
import hep.dataforge.values.Value;
|
||
|
import static inr.numass.viewer.NumassViewerUtils.displayPlot;
|
||
|
import java.net.URL;
|
||
|
import java.text.DecimalFormat;
|
||
|
import java.util.ArrayList;
|
||
|
import java.util.HashMap;
|
||
|
import java.util.List;
|
||
|
import java.util.Map;
|
||
|
import java.util.ResourceBundle;
|
||
|
import javafx.application.Platform;
|
||
|
import javafx.event.ActionEvent;
|
||
|
import javafx.fxml.FXML;
|
||
|
import javafx.fxml.Initializable;
|
||
|
import javafx.scene.control.CheckBox;
|
||
|
import javafx.scene.layout.AnchorPane;
|
||
|
import javafx.scene.layout.VBox;
|
||
|
import org.jfree.chart.JFreeChart;
|
||
|
import org.jfree.chart.axis.DateAxis;
|
||
|
import org.jfree.chart.axis.LogAxis;
|
||
|
import org.jfree.chart.plot.XYPlot;
|
||
|
import org.jfree.chart.renderer.xy.XYStepRenderer;
|
||
|
import org.jfree.data.xy.XYDataset;
|
||
|
import org.jfree.data.xy.XYSeries;
|
||
|
import org.jfree.data.xy.XYSeriesCollection;
|
||
|
|
||
|
/**
|
||
|
* FXML Controller class
|
||
|
*
|
||
|
* @author darksnake
|
||
|
*/
|
||
|
public class MspViewController implements Initializable {
|
||
|
|
||
|
private ProgressUpdateCallback callback;
|
||
|
|
||
|
@FXML
|
||
|
private AnchorPane mspPlotPane;
|
||
|
@FXML
|
||
|
private VBox mspSelectorPane;
|
||
|
|
||
|
/**
|
||
|
* Initializes the controller class.
|
||
|
*
|
||
|
* @param url
|
||
|
* @param rb
|
||
|
*/
|
||
|
@Override
|
||
|
public void initialize(URL url, ResourceBundle rb) {
|
||
|
// TODO
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* update detector pane with new data
|
||
|
*/
|
||
|
private void updateMspPane(XYSeriesCollection detectorData) {
|
||
|
Platform.runLater(() -> {
|
||
|
if (detectorData == null) {
|
||
|
throw new IllegalArgumentException("Detector data not defined");
|
||
|
}
|
||
|
|
||
|
mspSelectorPane.getChildren().clear();//removing all checkboxes
|
||
|
mspPlotPane.getChildren().clear();//removing plot
|
||
|
|
||
|
DateAxis xAxis = new DateAxis("time");
|
||
|
LogAxis yAxis = new LogAxis("partial pressure (mbar)");
|
||
|
yAxis.setAutoRange(true);
|
||
|
yAxis.setAutoTickUnitSelection(false);
|
||
|
yAxis.setNumberFormatOverride(new DecimalFormat("0E0"));
|
||
|
//NumberAxis yAxis = new NumberAxis();
|
||
|
|
||
|
XYPlot plot = new XYPlot(detectorData, xAxis, yAxis, new XYStepRenderer());
|
||
|
|
||
|
JFreeChart mspPlot = new JFreeChart("Mass-spectrum peak jump plot", plot);
|
||
|
|
||
|
displayPlot(mspPlotPane, mspPlot);
|
||
|
|
||
|
for (int i = 0; i < plot.getDatasetCount(); i++) {
|
||
|
final XYDataset dataset = plot.getDataset(i);
|
||
|
for (int j = 0; j < dataset.getSeriesCount(); j++) {
|
||
|
CheckBox cb = new CheckBox(dataset.getSeriesKey(j).toString());
|
||
|
cb.setSelected(true);
|
||
|
final int seriesNumber = j;
|
||
|
cb.setOnAction((ActionEvent event) -> {
|
||
|
boolean checked = cb.isSelected();
|
||
|
plot.getRendererForDataset(dataset).setSeriesVisible(seriesNumber, checked);
|
||
|
});
|
||
|
mspSelectorPane.getChildren().add(cb);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
public void fillMspData(Storage rootStorage) {
|
||
|
if (rootStorage != null) {
|
||
|
try {
|
||
|
List<DataPoint> mspData = getMspData(rootStorage);
|
||
|
Map<String, XYSeries> series = new HashMap<>();
|
||
|
|
||
|
for (DataPoint point : mspData) {
|
||
|
for (String name : point.names()) {
|
||
|
if (!name.equals("timestamp")) {
|
||
|
if (!series.containsKey(name)) {
|
||
|
series.put(name, new XYSeries(name));
|
||
|
}
|
||
|
long time = point.getValue("timestamp").timeValue().toEpochMilli();
|
||
|
double value = point.getDouble(name);
|
||
|
if (value > 0) {
|
||
|
series.get(name).add(time, value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
XYSeriesCollection mspSeriesCollection = new XYSeriesCollection();
|
||
|
for (XYSeries ser : series.values()) {
|
||
|
mspSeriesCollection.addSeries(ser);
|
||
|
}
|
||
|
updateMspPane(mspSeriesCollection);
|
||
|
} catch (StorageException ex) {
|
||
|
throw new RuntimeException(ex);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private List<DataPoint> getMspData(Storage storage) throws StorageException {
|
||
|
List<DataPoint> mspData = new ArrayList<>();
|
||
|
DataPoint last = null;
|
||
|
for (String loaderName : storage.loaders().keySet()) {
|
||
|
if (loaderName.startsWith("msp")) {
|
||
|
PointLoader mspLoader = (PointLoader) storage.getLoader(loaderName);
|
||
|
updateProgress("Loading mass spectrometer data from " + mspLoader.getName());
|
||
|
updateProgress(-1);
|
||
|
for (DataPoint dp : mspLoader.asDataSet()) {
|
||
|
mspData.add(dp);
|
||
|
last = dp;
|
||
|
}
|
||
|
if (last != null) {
|
||
|
mspData.add(terminatorPoint(last));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
for (String shelfName : storage.shelves().keySet()) {
|
||
|
mspData.addAll(getMspData(storage.getShelf(shelfName)));
|
||
|
}
|
||
|
|
||
|
updateProgress("Loading msp data finished");
|
||
|
updateProgress(1);
|
||
|
return mspData;
|
||
|
}
|
||
|
|
||
|
private void updateProgress(String progress) {
|
||
|
if (callback != null) {
|
||
|
callback.setProgressText(progress);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void updateProgress(double progress) {
|
||
|
if (callback != null) {
|
||
|
callback.setProgress(progress);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void setCallback(ProgressUpdateCallback callback) {
|
||
|
this.callback = callback;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a NaN value point to terminate msp series
|
||
|
*
|
||
|
* @param last
|
||
|
* @return
|
||
|
*/
|
||
|
private DataPoint terminatorPoint(DataPoint last) {
|
||
|
MapDataPoint p = new MapDataPoint();
|
||
|
p.putValue("timestamp", last.getValue("timestamp").timeValue().plusMillis(10));
|
||
|
for (String name : last.namesAsArray()) {
|
||
|
if (!name.equals("timestamp")) {
|
||
|
p.putValue(name, Value.getNull());
|
||
|
}
|
||
|
}
|
||
|
return p;
|
||
|
}
|
||
|
}
|