/* * 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.DataSet; import hep.dataforge.io.ColumnedDataWriter; import hep.dataforge.meta.Meta; import hep.dataforge.meta.MetaBuilder; import hep.dataforge.plots.XYPlotFrame; import hep.dataforge.plots.XYPlottable; import hep.dataforge.plots.data.PlotDataUtils; import hep.dataforge.plots.data.PlottableData; import hep.dataforge.plots.jfreechart.JFreeChartFrame; import hep.dataforge.storage.commons.JSONMetaWriter; import inr.numass.data.NMPoint; import inr.numass.data.NumassData; import static inr.numass.viewer.NumassViewerUtils.displayPlot; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.ResourceBundle; import java.util.function.Function; import javafx.beans.property.BooleanProperty; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.ChoiceBox; import javafx.scene.control.SelectionMode; import javafx.scene.control.Tab; import javafx.scene.control.TextArea; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.VBox; import javafx.stage.FileChooser; import org.controlsfx.control.CheckListView; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYErrorRenderer; import org.jfree.data.xy.XYIntervalSeries; import org.jfree.data.xy.XYIntervalSeriesCollection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * FXML Controller class * * @author darksnake */ public class NumassLoaderViewComponent extends AnchorPane implements Initializable { public static NumassLoaderViewComponent build(NumassData numassLoader) { NumassLoaderViewComponent component = new NumassLoaderViewComponent(); FXMLLoader loader = new FXMLLoader(component.getClass().getResource("/fxml/NumassLoaderView.fxml")); loader.setRoot(component); loader.setController(component); try { loader.load(); } catch (IOException ex) { throw new RuntimeException(ex); } component.setData(numassLoader); return component; } Logger logger = LoggerFactory.getLogger(NumassLoaderViewComponent.class); private NumassData data; private XYPlotFrame detectorPlotFrame; @FXML private AnchorPane detectorPlotPane; @FXML private CheckListView detectorPointListView; @FXML private Tab detectorTab; @FXML private Tab hvTab; @FXML private Tab spectrumTab; @FXML private TextArea infoTextBox; @FXML private VBox detectorOptionsPane; @FXML private AnchorPane spectrumPlotPane; @FXML private VBox spectrumOptionsPane; @FXML private ChoiceBox detectorBinningSelector; @FXML private CheckBox detectorNormalizeSwitch; @FXML private Button detectorDataExportButton; /** * Initializes the controller class. * @param url * @param rb */ @Override public void initialize(URL url, ResourceBundle rb) { // TODO detectorBinningSelector.setItems(FXCollections.observableArrayList(1, 2, 5, 10, 20)); detectorBinningSelector.getSelectionModel().selectLast(); detectorNormalizeSwitch.setSelected(true); detectorPointListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); detectorDataExportButton.setOnAction(this::onExportButtonClick); } public NumassData getData() { return data; } public void setData(NumassData data) { this.data = data; if (data != null) { List points = data.getNMPoints(); //setup detector data setupDetectorPane(points); //setup spectrum plot setupSpectrumPane(points); setupInfo(data); detectorTab.getTabPane().getSelectionModel().select(detectorTab); } else { logger.error("The data model is null"); } } /** * setup detector pane * * @param points */ private void setupDetectorPane(List points) { boolean normalize = detectorNormalizeSwitch.isSelected(); int binning = detectorBinningSelector.getValue(); updateDetectorPane(fillDetectorData(points, binning, normalize)); detectorBinningSelector.getSelectionModel().selectedItemProperty() .addListener((ObservableValue observable, Integer oldValue, Integer newValue) -> { boolean norm = detectorNormalizeSwitch.isSelected(); updateDetectorPane(fillDetectorData(points, newValue, norm)); }); detectorNormalizeSwitch.selectedProperty().addListener((ObservableValue observable, Boolean oldValue, Boolean newValue) -> { int bin = detectorBinningSelector.getValue(); updateDetectorPane(fillDetectorData(points, bin, newValue)); }); detectorDataExportButton.setDisable(false); } private void setupInfo(NumassData loader) { Meta info = loader.getInfo(); infoTextBox.setText(new JSONMetaWriter().writeString(info, null). replace("\\r", "\r").replace("\\n", "\n")); } private void setupSpectrumPane(List points) { updateSpectrumData(fillSpectrumData(points, (point) -> point.getEventsCount())); } private void updateSpectrumData(XYIntervalSeriesCollection data) { spectrumPlotPane.getChildren().clear(); NumberAxis xAxis = new NumberAxis("HV"); NumberAxis yAxis = new NumberAxis("count rate"); xAxis.setAutoRangeIncludesZero(false); yAxis.setAutoRangeIncludesZero(false); XYPlot plot = new XYPlot(data, xAxis, yAxis, new XYErrorRenderer()); JFreeChart spectrumPlot = new JFreeChart("spectrum", plot); displayPlot(spectrumPlotPane, spectrumPlot); } /** * update detector pane with new data */ private void updateDetectorPane(List detectorData) { if (detectorData == null) { throw new IllegalArgumentException("Detector data not defined"); } detectorPointListView.getItems().clear();//removing all checkboxes detectorPlotPane.getChildren().clear();//removing plot Meta frameMeta = new MetaBuilder("frame") .setValue("frameTitle", "Detector response plot") .setNode(new MetaBuilder("xAxis") .setValue("axisTitle", "ADC") .setValue("axisUnits", "channels") .build()) .setNode(new MetaBuilder("yAxis") .setValue("axisTitle", "count rate") .setValue("axisUnits", "Hz") .build()) .build(); detectorPlotFrame = new JFreeChartFrame("detectorSignal", frameMeta, detectorPlotPane); for (XYPlottable pl : detectorData) { detectorPlotFrame.add(pl); detectorPointListView.getItems().add(pl.getName()); } for (String plotName : detectorPointListView.getItems()) { BooleanProperty checked = detectorPointListView.getItemBooleanProperty(plotName); checked.set(true); checked.addListener((ObservableValue observable, Boolean oldValue, Boolean newValue) -> { detectorPlotFrame.get(plotName).getConfig().setValue("visible", newValue); }); } } private List fillDetectorData(List points, int binning, boolean normalize) { List plottables = new ArrayList<>(); Meta plottableConfig = new MetaBuilder("plot") .setValue("connectionType", "step") .setValue("thickness", 2) .setValue("showLine", true) .setValue("showSymbol", false) .build(); for (NMPoint point : points) { String seriesName = String.format("%d: %.2f (%.2f)", points.indexOf(point), point.getUset(), point.getUread()); PlottableData datum = new PlottableData(seriesName, plottableConfig, point.getData(binning, normalize), "chanel", "count"); plottables.add(datum); } return plottables; } /** * Fill spectrum with custom window calculator * * @param points * @param lowerBoundCalculator * @param upperBoundCalculator * @return */ private XYIntervalSeriesCollection fillSpectrumData(List points, Function calculator) { XYIntervalSeriesCollection collection = new XYIntervalSeriesCollection(); XYIntervalSeries ser = new XYIntervalSeries("spectrum"); for (NMPoint point : points) { double u = point.getUread(); double count = calculator.apply(point).doubleValue(); double time = point.getLength(); double err = Math.sqrt(count); ser.add(u, u, u, count / time, (count - err) / time, (count + err) / time); } collection.addSeries(ser); return collection; } @FXML private void checkAllAction(ActionEvent event) { detectorPointListView.getCheckModel().checkAll(); } @FXML private void uncheckAllAction(ActionEvent event) { detectorPointListView.getCheckModel().clearChecks(); } @FXML private void checkSelectedAction(ActionEvent event) { for (Integer i : detectorPointListView.getSelectionModel().getSelectedIndices()) { detectorPointListView.getCheckModel().check(i); } } @FXML private void uncheckSelectedAction(ActionEvent event) { for (Integer i : detectorPointListView.getSelectionModel().getSelectedIndices()) { detectorPointListView.getCheckModel().clearCheck(i); } } private void onExportButtonClick(ActionEvent event) { FileChooser fileChooser = new FileChooser(); fileChooser.setTitle("Choose text export destination"); fileChooser.setInitialFileName(data.getName() + "_detector.out"); File destination = fileChooser.showSaveDialog(detectorPlotPane.getScene().getWindow()); if (destination != null) { DataSet detectorData = PlotDataUtils.collectXYDataFromPlot(detectorPlotFrame, true); try { ColumnedDataWriter .writeDataSet(destination, detectorData, "Numass data viewer detector data export for " + data.getName(), false); } catch (IOException ex) { LoggerFactory.getLogger(getClass()).error("Destination file not found", ex); } } } }