Partially fixed plot group visualization

This commit is contained in:
Alexander Nozik 2017-10-31 17:02:28 +03:00
parent 25251e64f9
commit dbe93f546a
13 changed files with 102 additions and 829 deletions

View File

@ -31,8 +31,8 @@ import hep.dataforge.exceptions.ControlException;
import hep.dataforge.exceptions.MeasurementException; import hep.dataforge.exceptions.MeasurementException;
import hep.dataforge.exceptions.StorageException; import hep.dataforge.exceptions.StorageException;
import hep.dataforge.meta.Meta; import hep.dataforge.meta.Meta;
import hep.dataforge.storage.api.PointLoader;
import hep.dataforge.storage.api.Storage; import hep.dataforge.storage.api.Storage;
import hep.dataforge.storage.api.TableLoader;
import hep.dataforge.storage.commons.LoaderFactory; import hep.dataforge.storage.commons.LoaderFactory;
import hep.dataforge.tables.TableFormat; import hep.dataforge.tables.TableFormat;
import hep.dataforge.tables.TableFormatBuilder; import hep.dataforge.tables.TableFormatBuilder;
@ -85,7 +85,7 @@ public class PKT8Device extends PortSensor<PKT8Result> {
setMeta(meta); setMeta(meta);
} }
private PointLoader buildLoader(StorageConnection connection) { private TableLoader buildLoader(StorageConnection connection) {
Storage storage = connection.getStorage(); Storage storage = connection.getStorage();
String suffix = DateTimeUtils.fileSuffix(); String suffix = DateTimeUtils.fileSuffix();

View File

@ -36,8 +36,8 @@ import hep.dataforge.exceptions.MeasurementException;
import hep.dataforge.exceptions.PortException; import hep.dataforge.exceptions.PortException;
import hep.dataforge.exceptions.StorageException; import hep.dataforge.exceptions.StorageException;
import hep.dataforge.meta.Meta; import hep.dataforge.meta.Meta;
import hep.dataforge.storage.api.PointLoader;
import hep.dataforge.storage.api.Storage; import hep.dataforge.storage.api.Storage;
import hep.dataforge.storage.api.TableLoader;
import hep.dataforge.storage.commons.LoaderFactory; import hep.dataforge.storage.commons.LoaderFactory;
import hep.dataforge.tables.TableFormat; import hep.dataforge.tables.TableFormat;
import hep.dataforge.tables.TableFormatBuilder; import hep.dataforge.tables.TableFormatBuilder;
@ -421,7 +421,7 @@ public class MspDevice extends Sensor<Values> implements PortHandler.PortControl
this.meta = meta; this.meta = meta;
} }
private PointLoader makeLoader(StorageConnection connection) { private TableLoader makeLoader(StorageConnection connection) {
try { try {
Storage storage = connection.getStorage(); Storage storage = connection.getStorage();

View File

@ -3,7 +3,7 @@ package inr.numass.control
import hep.dataforge.control.connections.StorageConnection import hep.dataforge.control.connections.StorageConnection
import hep.dataforge.control.devices.AbstractDevice import hep.dataforge.control.devices.AbstractDevice
import hep.dataforge.exceptions.StorageException import hep.dataforge.exceptions.StorageException
import hep.dataforge.storage.api.PointLoader import hep.dataforge.storage.api.TableLoader
import hep.dataforge.values.Values import hep.dataforge.values.Values
import java.util.* import java.util.*
import java.util.function.Function import java.util.function.Function
@ -12,8 +12,8 @@ import java.util.function.Function
* A helper to store points in multiple loaders * A helper to store points in multiple loaders
* Created by darksnake on 16-May-17. * Created by darksnake on 16-May-17.
*/ */
class StorageHelper(private val device: AbstractDevice, private val loaderFactory: Function<StorageConnection, PointLoader>) : AutoCloseable { class StorageHelper(private val device: AbstractDevice, private val loaderFactory: Function<StorageConnection, TableLoader>) : AutoCloseable {
private val loaderMap = HashMap<StorageConnection, PointLoader>() private val loaderMap = HashMap<StorageConnection, TableLoader>()
fun push(point: Values) { fun push(point: Values) {
if (!device.hasState("storing") || device.getState("storing").booleanValue()) { if (!device.hasState("storing") || device.getState("storing").booleanValue()) {

View File

@ -19,7 +19,7 @@ import hep.dataforge.control.measurements.Measurement;
import hep.dataforge.description.ValueDef; import hep.dataforge.description.ValueDef;
import hep.dataforge.exceptions.ControlException; import hep.dataforge.exceptions.ControlException;
import hep.dataforge.meta.Meta; import hep.dataforge.meta.Meta;
import hep.dataforge.storage.api.PointLoader; import hep.dataforge.storage.api.TableLoader;
import hep.dataforge.storage.commons.LoaderFactory; import hep.dataforge.storage.commons.LoaderFactory;
import hep.dataforge.tables.TableFormatBuilder; import hep.dataforge.tables.TableFormatBuilder;
import hep.dataforge.tables.ValueMap; import hep.dataforge.tables.ValueMap;
@ -113,7 +113,7 @@ public class VacCollectorDevice extends Sensor<Values> {
} }
} }
private PointLoader buildLoader(StorageConnection connection) { private TableLoader buildLoader(StorageConnection connection) {
TableFormatBuilder format = new TableFormatBuilder().setType("timestamp", ValueType.TIME); TableFormatBuilder format = new TableFormatBuilder().setType("timestamp", ValueType.TIME);
getSensors().forEach((s) -> { getSensors().forEach((s) -> {
format.setType(s.getName(), ValueType.NUMBER); format.setType(s.getName(), ValueType.NUMBER);

View File

@ -26,7 +26,7 @@ ctx.pluginManager().load(PlotManager)
ctx.pluginManager().load(NumassPlugin.class) ctx.pluginManager().load(NumassPlugin.class)
new GrindShell(ctx).eval { new GrindShell(ctx).eval {
File rootDir = new File("D:\\Work\\Numass\\data\\2017_05\\Fill_2") File rootDir = new File("D:\\Work\\Numass\\data\\2017_05\\Fill_3")
NumassStorage storage = NumassStorageFactory.buildLocal(rootDir); NumassStorage storage = NumassStorageFactory.buildLocal(rootDir);

View File

@ -11,8 +11,8 @@ import hep.dataforge.server.ServerManager;
import hep.dataforge.server.ServletUtils; import hep.dataforge.server.ServletUtils;
import hep.dataforge.server.storage.StorageRatpackHandler; import hep.dataforge.server.storage.StorageRatpackHandler;
import hep.dataforge.storage.api.ObjectLoader; import hep.dataforge.storage.api.ObjectLoader;
import hep.dataforge.storage.api.PointLoader;
import hep.dataforge.storage.api.Storage; import hep.dataforge.storage.api.Storage;
import hep.dataforge.storage.api.TableLoader;
import inr.numass.data.api.NumassSet; import inr.numass.data.api.NumassSet;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import ratpack.handling.Context; import ratpack.handling.Context;
@ -73,7 +73,7 @@ public class NumassStorageHandler extends StorageRatpackHandler {
} }
@Override @Override
protected MetaBuilder pointLoaderPlotOptions(PointLoader loader) { protected MetaBuilder pointLoaderPlotOptions(TableLoader loader) {
MetaBuilder builder = super.pointLoaderPlotOptions(loader); MetaBuilder builder = super.pointLoaderPlotOptions(loader);
if (loader.getName().startsWith("msp") if (loader.getName().startsWith("msp")
|| loader.getName().startsWith("vac") || loader.getName().startsWith("vac")

View File

@ -1,67 +0,0 @@
/*
* 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;
import hep.dataforge.storage.commons.StorageManager;
import inr.numass.data.storage.NumassDataLoader;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
import java.nio.file.Paths;
/**
* @author darksnake
*/
public class TestDirectoryViewer extends Application {
@Override
public void start(Stage stage) throws IOException {
new StorageManager().startGlobal();
NumassDataLoader reader = NumassDataLoader.fromDir(null, Paths.get("C:\\Users\\darksnake\\Dropbox\\PlayGround\\data-test\\20150703143643_1\\"), null);
// NumassLoader reader = NumassLoader.fromZip(null, new File("C:\\Users\\darksnake\\Dropbox\\PlayGround\\data-test\\20150703143643_1.zip"));
NumassLoaderView comp = new NumassLoaderView();
comp.loadData(reader);
// FXMLLoader fxml = new FXMLLoader(getClass().getResource("/fxml/DirectoryViewer.fxml"));
//
// Parent parent = fxml.load();
//
// NumassLoaderViewController controller = fxml.getController();
//
// controller.setModel(reader);
Scene scene = new Scene(comp.getRoot(), 800, 600);
stage.setTitle("Detector Visualisation test");
stage.setScene(scene);
stage.setMinHeight(600);
stage.setMinWidth(800);
// primaryStage.setResizable(false);
stage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}

View File

@ -1,262 +0,0 @@
package inr.numass.viewer
import hep.dataforge.context.Context
import hep.dataforge.context.Global
import hep.dataforge.exceptions.StorageException
import hep.dataforge.fx.fragments.FragmentWindow
import hep.dataforge.fx.fragments.LogFragment
import hep.dataforge.meta.Metoid
import hep.dataforge.names.AlphanumComparator
import hep.dataforge.names.Named
import hep.dataforge.storage.api.PointLoader
import hep.dataforge.storage.api.Storage
import hep.dataforge.storage.filestorage.FileStorageFactory
import inr.numass.NumassProperties
import inr.numass.data.api.NumassSet
import inr.numass.data.storage.NumassStorage
import javafx.application.Platform
import javafx.beans.property.SimpleObjectProperty
import javafx.geometry.Insets
import javafx.scene.control.*
import javafx.scene.control.TreeTableView.CONSTRAINED_RESIZE_POLICY
import javafx.scene.input.MouseEvent
import javafx.scene.layout.AnchorPane
import javafx.scene.layout.BorderPane
import javafx.scene.layout.GridPane
import javafx.stage.DirectoryChooser
import javafx.util.Pair
import org.controlsfx.control.StatusBar
import tornadofx.*
import java.io.File
import java.net.URI
import java.util.logging.Level
/**
* Created by darksnake on 14-Apr-17.
*/
@Deprecated("obsolete")
class MainView : View("Numass data viewer") {
override val root: AnchorPane by fxml("/fxml/MainView.fxml");
private val numassLoaderView: NumassLoaderView by inject()
private val slowControlView: SlowControlView by inject()
private val consoleButton: ToggleButton by fxid()
// private val processManagerButton: ToggleButton by fxid()
private val loadDirectoryButton: Button by fxid()
private val loadRemoteButton: Button by fxid()
private val storagePathLabel: Label by fxid()
private val loaderPane: BorderPane by fxid()
private val treePane: BorderPane by fxid()
private val statusBar: StatusBar by fxid()
private val logFragment = FragmentWindow.build(consoleButton) {
LogFragment().apply {
addRootLogHandler()
}
}
// private val processFragment = FragmentWindow.builder(processManagerButton) {
// WorkManagerFragment(getWorkManager())
// }
private val storageProperty = SimpleObjectProperty<Storage?>();
init {
loadDirectoryButton.action {
val chooser = DirectoryChooser()
chooser.title = "Select numass storage root"
val storageRoot = NumassProperties.getNumassProperty("numass.storage.root")
try {
if (storageRoot == null) {
chooser.initialDirectory = File(".").absoluteFile
} else {
chooser.initialDirectory = File(storageRoot)
}
} catch (ex: Exception) {
NumassProperties.setNumassProperty("numass.storage.root", null)
}
val rootDir = chooser.showDialog(primaryStage.scene.window)
if (rootDir != null) {
NumassProperties.setNumassProperty("numass.storage.root", rootDir.absolutePath)
loadDirectory(rootDir.toURI())
}
}
loadRemoteButton.action { onLoadRemote() }
treePane.center {
treetableview<Item> {
val nameColumnt = column("name", Item::getName).apply {
sortType = TreeTableColumn.SortType.ASCENDING
}
val timeColumn = column("time", Item::getTime).apply {
isVisible = false
}
sortOrder.add(nameColumnt)
addEventHandler(MouseEvent.MOUSE_CLICKED) { e: MouseEvent ->
if (e.clickCount == 2) {
val value = focusModel.focusedCell.treeItem.value
when (value.content) {
is NumassSet -> {
numassLoaderView.loadData(value.content)
loaderPane.center = numassLoaderView.root
}
is PointLoader -> {
val loader: PointLoader = value.content;
slowControlView.load(loader);
loaderPane.center = slowControlView.root
}
}
}
}
isTableMenuButtonVisible = true
columnResizePolicy = CONSTRAINED_RESIZE_POLICY
storageProperty.addListener { _, _, value ->
if (value != null) {
Platform.runLater {
root = TreeItem(Item(value));
root.isExpanded = true
populate { parent ->
val storage = parent.value.content;
if (storage is Storage) {
//TODO add legacy loaders here?
storage.shelves().map(::Item).sorted() + storage.loaders().map(::Item).sorted()
} else {
null
}
}
}
} else {
// TODO clear
}
}
}
}
primaryStage.setOnCloseRequest {
log.info("Closing storage")
storageProperty.get()?.close()
}
}
private fun loadDirectory(path: URI) {
runAsync {
updateTitle("Load storage ($path)")
updateProgress(-1.0, -1.0);
updateMessage("Building numass storage tree...")
val root = NumassStorage(context, FileStorageFactory.buildStorageMeta(path, true, true));
setRootStorage(root)
Platform.runLater { storagePathLabel.text = "Storage: " + path }
updateProgress(1.0, 1.0)
}
}
private val context: Context
get() = Global.instance()
fun setRootStorage(root: NumassStorage) {
runAsync {
updateTitle("Fill data to UI (" + root.name + ")")
updateProgress(-1.0, 1.0)
Platform.runLater { statusBar.progress = -1.0 }
updateMessage("Loading numass storage tree...")
try {
storageProperty.set(root)
} catch (ex: StorageException) {
log.log(Level.SEVERE, null, ex)
}
// callback.setProgress(1, 1);
Platform.runLater { statusBar.progress = 0.0 }
updateMessage("Numass storage tree loaded.")
updateProgress(1.0, 1.0)
}
}
private fun onLoadRemote() {
// Create the custom dialog.
val dialog = Dialog<Pair<String, String>>()
dialog.title = "Remote storage selection"
dialog.headerText = "Select remote storage login options and run"
val loginButtonType = ButtonType("Load", ButtonBar.ButtonData.OK_DONE)
dialog.dialogPane.buttonTypes.addAll(loginButtonType, ButtonType.CANCEL)
// Create the username and password labels and fields.
val grid = GridPane()
grid.hgap = 10.0
grid.vgap = 10.0
grid.padding = Insets(20.0, 150.0, 10.0, 10.0)
val storageText = TextField()
storageText.prefWidth = 350.0
storageText.text = "sftp://trdat:Anomaly@192.168.111.1"
val runText = TextField()
runText.promptText = "Run name"
grid.add(Label("Storage path:"), 0, 0)
grid.add(storageText, 1, 0)
grid.add(Label("Run name:"), 0, 1)
grid.add(runText, 1, 1)
dialog.dialogPane.content = grid
// Request focus on the username field by default.
storageText.requestFocus()
// Convert the result to a username-password-pair when the login button is clicked.
dialog.setResultConverter { dialogButton ->
if (dialogButton == loginButtonType) {
Pair(storageText.text, runText.text)
} else {
null;
}
}
val result = dialog.showAndWait()
if (result.isPresent) {
val path = URI.create(result.get().key + "/data/" + result.get().value)
loadDirectory(path)
}
}
class Item(val content: Named) : Comparable<Item> {
override fun compareTo(other: Item): Int {
return AlphanumComparator.INSTANCE.compare(this.getName(), other.getName())
}
fun getName(): String {
return content.name;
}
fun getTime(): String {
if (content is NumassSet) {
if (content.startTime == null) {
return ""
} else {
return content.startTime.toString()
}
} else if (content is Metoid) {
return content.meta().getString("file.timeModified", "")
} else {
return "";
}
}
}
}

View File

@ -1,421 +0,0 @@
package inr.numass.viewer
import hep.dataforge.context.Context
import hep.dataforge.context.Global
import hep.dataforge.io.ColumnedDataWriter
import hep.dataforge.kodex.buildMeta
import hep.dataforge.kodex.fx.plots.PlotContainer
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaBuilder
import hep.dataforge.plots.PlotGroup
import hep.dataforge.plots.XYPlotFrame
import hep.dataforge.plots.data.DataPlot
import hep.dataforge.plots.data.DataPlotUtils
import hep.dataforge.plots.data.TimePlot
import hep.dataforge.plots.jfreechart.JFreeChartFrame
import hep.dataforge.storage.commons.JSONMetaWriter
import hep.dataforge.tables.Table
import hep.dataforge.tables.ValueMap
import hep.dataforge.tables.XYAdapter
import inr.numass.data.NumassDataUtils
import inr.numass.data.analyzers.SimpleAnalyzer
import inr.numass.data.api.NumassAnalyzer
import inr.numass.data.api.NumassPoint
import inr.numass.data.api.NumassSet
import javafx.application.Platform
import javafx.beans.property.SimpleObjectProperty
import javafx.beans.value.ObservableValue
import javafx.collections.FXCollections
import javafx.event.ActionEvent
import javafx.event.EventHandler
import javafx.geometry.Insets
import javafx.geometry.Orientation
import javafx.scene.control.*
import javafx.scene.layout.AnchorPane
import javafx.scene.layout.BorderPane
import javafx.stage.FileChooser
import javafx.util.converter.NumberStringConverter
import org.controlsfx.control.RangeSlider
import org.controlsfx.validation.ValidationSupport
import org.controlsfx.validation.Validator
import org.slf4j.LoggerFactory
import tornadofx.*
import java.io.IOException
import java.util.concurrent.atomic.AtomicInteger
import java.util.logging.Level
import java.util.stream.Collectors
/**
* Numass loader view
*
* Created by darksnake on 14-Apr-17.
*/
@Deprecated("obsolete")
class NumassLoaderView : View() {
override val root: AnchorPane by fxml("/fxml/NumassLoaderView.fxml")
// lateinit var main: MainView
private val detectorPlotPane: BorderPane by fxid();
// private val tabPane: TabPane by fxid();
private val infoTextBox: TextArea by fxid();
private val spectrumPlotPane: BorderPane by fxid();
private val lowChannelField: TextField by fxid();
private val upChannelField: TextField by fxid();
private val channelSlider: RangeSlider by fxid();
private val dTimeField: TextField by fxid();
private val hvPane: BorderPane by fxid();
private val spectrumExportButton: Button by fxid();
// private val detectorPlot: PlotContainer = PlotContainer.centerIn(detectorPlotPane)
// private val spectrumPlot: PlotContainer = PlotContainer.centerIn(spectrumPlotPane)
// private val hvPlot: PlotContainer = PlotContainer.centerIn(hvPane)
private val detectorBinningSelector: ChoiceBox<Int> = ChoiceBox(FXCollections.observableArrayList(1, 2, 5, 10, 20, 50))
private val detectorNormalizeSwitch: CheckBox = CheckBox("Normalize")
private val detectorDataExportButton: Button = Button("Export")
val dataProperty = SimpleObjectProperty<NumassSet>()
var data: NumassSet? by dataProperty
val analyzerProperty = SimpleObjectProperty<NumassAnalyzer>(SimpleAnalyzer())
var analyzer: NumassAnalyzer by analyzerProperty
private val spectra = HashMap<Double, Table>();//spectra cache
val spectrumData = DataPlot("spectrum")
val hvPlotData = PlotGroup("hv")
//private var points = FXCollections.observableArrayList<NumassPoint>()
val detectorPlotFrame = JFreeChartFrame(
MetaBuilder("frame")
.setValue("title", "Detector response plot")
.setNode(MetaBuilder("xAxis")
.setValue("axisTitle", "ADC")
.setValue("axisUnits", "channels")
.build())
.setNode(MetaBuilder("yAxis")
.setValue("axisTitle", "count rate")
.setValue("axisUnits", "Hz")
.build())
.setNode(MetaBuilder("legend")
.setValue("show", false))
.build()
)
val plottableConfig = MetaBuilder("plot")
.setValue("connectionType", "step")
.setValue("thickness", 2)
.setValue("showLine", true)
.setValue("showSymbol", false)
.setValue("showErrors", false)
.setValue("JFreeChart.cache", true)
.build()
private val detectorPlot: PlotContainer = PlotContainer(detectorPlotFrame);
private val spectrumPlot: PlotContainer;
private val hvPlot: PlotContainer;
init {
//setup detector pane frame and sidebar
val l = Label("Bin size:")
l.padding = Insets(5.0)
detectorBinningSelector.maxWidth = java.lang.Double.MAX_VALUE
detectorBinningSelector.selectionModel.clearAndSelect(4)
detectorNormalizeSwitch.isSelected = true
detectorNormalizeSwitch.padding = Insets(5.0)
detectorPlotPane.center = detectorPlot.root
detectorPlot.addToSideBar(0, l, detectorBinningSelector, detectorNormalizeSwitch, Separator(Orientation.HORIZONTAL))
detectorDataExportButton.maxWidth = java.lang.Double.MAX_VALUE
detectorDataExportButton.onAction = EventHandler { this.onExportButtonClick(it) }
detectorPlot.addToSideBar(detectorDataExportButton)
detectorPlot.sideBarPoistion = 0.7
//setup spectrum pane
spectrumExportButton.onAction = EventHandler { this.onSpectrumExportClick(it) }
val spectrumPlotMeta = MetaBuilder("plot")
.setValue("xAxis.axisTitle", "U")
.setValue("xAxis.axisUnits", "V")
.setValue("yAxis.axisTitle", "count rate")
.setValue("yAxis.axisUnits", "Hz")
.setValue("legend.show", false)
spectrumPlot = PlotContainer(JFreeChartFrame(spectrumPlotMeta).apply { add(spectrumData) })
spectrumPlotPane.center = spectrumPlot.root
lowChannelField.textProperty().bindBidirectional(channelSlider.lowValueProperty(), NumberStringConverter())
upChannelField.textProperty().bindBidirectional(channelSlider.highValueProperty(), NumberStringConverter())
channelSlider.highValue = 1900.0
channelSlider.lowValue = 300.0
detectorBinningSelector.selectionModel.selectedItemProperty().addListener { observable, oldValue, newValue ->
if (data != null) {
updateDetectorPane(data!!)
}
}
detectorNormalizeSwitch.selectedProperty().addListener { observable, oldValue, newValue ->
if (data != null) {
updateDetectorPane(data!!)
}
}
dTimeField.textProperty().addListener { _: ObservableValue<out String>, _: String, _: String ->
if (data != null) {
updateSpectrum(data!!)
}
}
val rangeChangeListener = { _: ObservableValue<out Number>, _: Number, _: Number ->
if (data != null) {
updateSpectrum(data!!)
}
}
channelSlider.lowValueProperty().addListener(rangeChangeListener)
channelSlider.highValueProperty().addListener(rangeChangeListener)
val validationSupport = ValidationSupport()
val isNumber = { t: String ->
try {
java.lang.Double.parseDouble(t)
true
} catch (ex: Exception) {
false
}
}
validationSupport.registerValidator(dTimeField, Validator.createPredicateValidator(isNumber, "Must be number"))
//setup HV frame
val hvPlotMeta = MetaBuilder("plot")
.setValue("xAxis.axisTitle", "time")
.setValue("xAxis.type", "time")
.setValue("yAxis.axisTitle", "HV")
hvPlot = PlotContainer(JFreeChartFrame(hvPlotMeta))
hvPane.center = hvPlot.root
dataProperty.addListener { observable, oldValue, newData ->
//clearing spectra cache
if (oldValue != newData) {
spectra.clear()
}
if (newData != null) {
runAsync {
updateTitle("Load numass data (" + newData.name + ")")
//setup info
updateInfo(newData)
//setup hv frame
updateHV(newData)
//setup spectrum frame
updateSpectrum(newData)
//setup detector data
updateDetectorPane(newData)
}
} else {
spectrumData.clear()
hvPlotData.clear()
}
}
}
fun getContext(): Context {
return Global.getDefaultContext();
}
fun loadData(data: NumassSet?) {
this.data = data;
// this.data = if (data == null) {
// data
// } else {
// NumassDataCache(data)
// }
}
private fun updateHV(data: NumassSet) {
hvPlotData.clear()
runAsync {
data.hvData
} ui { hvData ->
hvData.ifPresent {
for (dp in it) {
val block = dp.getString("block", "default").replace(".","_")
if (!hvPlotData.has(block)) {
hvPlotData.add(TimePlot(block))
}
(hvPlotData.opt(block).orElseThrow{RuntimeException()} as TimePlot)
.put(dp.getValue("timestamp").timeValue(), dp.getValue("value"))
}
hvPlot.frame.add(hvPlotData)
}
}
}
private fun updateInfo(data: NumassSet) {
val info = data.meta()
infoTextBox.text = JSONMetaWriter().writeString(info).replace("\\r", "\r\t").replace("\\n", "\n\t")
}
/**
* Get energy spectrum for a specific point
*/
private fun getSpectrum(point: NumassPoint): Table {
synchronized(this) {
return spectra.computeIfAbsent(point.voltage) { analyzer.getSpectrum(point, Meta.empty()) }
}
}
private fun updateSpectrum(data: NumassSet) {
runAsync {
val loChannel = channelSlider.lowValue.toShort()
val upChannel = channelSlider.highValue.toShort()
data.points.map { point ->
val count = NumassAnalyzer.countInWindow(getSpectrum(point), loChannel, upChannel);
val seconds = point.length.toMillis() / 1000.0;
runLater { spectrumPlot.progress = -1.0 }
ValueMap.ofMap(
mapOf(
XYAdapter.X_AXIS to point.voltage,
XYAdapter.Y_AXIS to (count / seconds),
XYAdapter.Y_ERROR_KEY to Math.sqrt(count.toDouble()) / seconds
)
)
}.collect(Collectors.toList())
} ui { points ->
spectrumData.fillData(points)
spectrumPlot.progress = 1.0
spectrumExportButton.isDisable = false
}
}
private val dTime: Double
get() {
try {
return java.lang.Double.parseDouble(dTimeField.text) * 1e-6
} catch (ex: NumberFormatException) {
return 0.0
}
}
/**
* update detector pane with new data
*/
private fun updateDetectorPane(data: NumassSet) {
Platform.runLater { detectorPlotFrame.clear() }
val binning = detectorBinningSelector.value
val valueAxis = if (detectorNormalizeSwitch.isSelected) {
NumassAnalyzer.COUNT_RATE_KEY
} else {
NumassAnalyzer.COUNT_KEY
}
runAsync {
Platform.runLater { detectorPlot.progressProperty.bind(progressProperty()) }
val totalCount = data.points.count();
val index = AtomicInteger(0);
data.points.map { point ->
val seriesName = String.format("%d: %.2f", index.incrementAndGet(), point.voltage)
DataPlot.plot(
seriesName,
XYAdapter(NumassAnalyzer.CHANNEL_KEY, valueAxis),
NumassDataUtils.spectrumWithBinning(getSpectrum(point), binning)
).apply {
configure(plottableConfig)
}.also {
updateProgress(index.get().toLong(), totalCount);
}
}.collect(Collectors.toList())
} ui { plots ->
detectorPlotFrame.setAll(plots)
detectorDataExportButton.isDisable = false
}
}
private fun onSpectrumExportClick(event: ActionEvent) {
if (data != null) {
val fileChooser = FileChooser()
fileChooser.title = "Choose text export destination"
fileChooser.initialFileName = data!!.name + "_spectrum.onComplete"
val destination = fileChooser.showSaveDialog(spectrumPlotPane.scene.window)
if (destination != null) {
val names = arrayOf("Uset", "Uread", "Length", "Total", "Window", "CR", "CRerr", "Timestamp")
val loChannel = channelSlider.lowValue.toInt()
val upChannel = channelSlider.highValue.toInt()
val dTime = dTime
// val spectrumDataSet = ListTable.Builder(*names)
//
// for (point in points) {
// spectrumDataSet.row(
// point.voltage,
// point.voltage,
// point.length,
// point.totalCount,
// point.getCountInWindow(loChannel, upChannel),
// NumassDataUtils.countRateWithDeadTime(point, loChannel, upChannel, dTime),
// NumassDataUtils.countRateWithDeadTimeErr(point, loChannel, upChannel, dTime),
// point.startTime
// )
// }
val spectrumDataSet = analyzer.analyzeSet(data, buildMeta {
"window.lo" to loChannel
"window.up" to upChannel
})
try {
val comment = String.format("Numass data viewer spectrum data export for %s%n"
+ "Window: (%d, %d)%n"
+ "Dead time per event: %g%n",
data!!.name, loChannel, upChannel, dTime)
ColumnedDataWriter
.writeTable(destination, spectrumDataSet, comment, false)
} catch (ex: IOException) {
log.log(Level.SEVERE, "Destination file not found", ex)
}
}
}
}
private fun onExportButtonClick(event: ActionEvent) {
val fileChooser = FileChooser()
fileChooser.title = "Choose text export destination"
fileChooser.initialFileName = data!!.name + "_detector.out"
val destination = fileChooser.showSaveDialog(detectorPlotPane.scene.window)
if (destination != null) {
val detectorData = DataPlotUtils.collectXYDataFromPlot(detectorPlot.frame as XYPlotFrame, true)
try {
ColumnedDataWriter.writeTable(
destination,
detectorData,
"Numass data viewer detector data export for " + data!!.name,
false
)
} catch (ex: IOException) {
LoggerFactory.getLogger(javaClass).error("Destination file not found", ex)
}
}
}
}

View File

@ -3,16 +3,21 @@ package inr.numass.viewer
import hep.dataforge.kodex.configure import hep.dataforge.kodex.configure
import hep.dataforge.kodex.fx.dfIcon import hep.dataforge.kodex.fx.dfIcon
import hep.dataforge.kodex.fx.plots.PlotContainer import hep.dataforge.kodex.fx.plots.PlotContainer
import hep.dataforge.kodex.fx.runGoal
import hep.dataforge.kodex.fx.ui
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.plots.Plot import hep.dataforge.plots.PlotGroup
import hep.dataforge.plots.data.DataPlot import hep.dataforge.plots.data.DataPlot
import hep.dataforge.plots.jfreechart.JFreeChartFrame import hep.dataforge.plots.jfreechart.JFreeChartFrame
import hep.dataforge.storage.api.PointLoader import hep.dataforge.storage.api.TableLoader
import hep.dataforge.storage.api.ValueIndex import hep.dataforge.storage.api.ValueIndex
import hep.dataforge.tables.ListTable import hep.dataforge.tables.ListTable
import hep.dataforge.tables.Table import hep.dataforge.tables.Table
import hep.dataforge.tables.XYAdapter import hep.dataforge.tables.XYAdapter
import hep.dataforge.values.Values import hep.dataforge.values.Values
import javafx.collections.FXCollections
import javafx.collections.MapChangeListener
import javafx.collections.ObservableMap
import javafx.scene.image.ImageView import javafx.scene.image.ImageView
import tornadofx.* import tornadofx.*
@ -30,26 +35,39 @@ class SlowControlView : View(title = "Numass slow control view", icon = ImageVie
center = PlotContainer(plot).root center = PlotContainer(plot).root
} }
//TODO add multiple loaders val data: ObservableMap<String, TableLoader> = FXCollections.observableHashMap();
fun load(loader: PointLoader) { val isEmpty = booleanBinding(data) { data.isEmpty() }
runAsync {
val data = getData(loader) init {
ArrayList<Plot>().apply { data.addListener { change: MapChangeListener.Change<out String, out TableLoader> ->
loader.format.columns.filter { it.name != "timestamp" }.forEach { if (change.wasRemoved()) {
val adapter = XYAdapter("timestamp", it.name); plot.remove(change.key)
this += DataPlot.plot(it.name, adapter, data).configure { }
if (change.wasAdded()) {
runGoal("loadTable[${change.key}]") {
val plotData = getData(change.valueAdded)
val names = plotData.format.namesAsArray().filter { it != "timestamp" }
val group = PlotGroup(change.key)
names.forEach {
val adapter = XYAdapter("timestamp", it);
val plot = DataPlot.plot(it, adapter, plotData).configure {
"showLine" to true "showLine" to true
"showSymbol" to false "showSymbol" to false
"showErrors" to false "showErrors" to false
} }
group.add(plot)
} }
} group
} ui { } ui {
plot.setAll(it) plot.add(it);
}
}
} }
} }
private fun getData(loader: PointLoader, query: Meta = Meta.empty()): Table { private fun getData(loader: TableLoader, query: Meta = Meta.empty()): Table {
val index: ValueIndex<Values> = val index: ValueIndex<Values> =
if (query.hasValue("index")) { if (query.hasValue("index")) {
//use custom index if needed //use custom index if needed
@ -63,7 +81,14 @@ class SlowControlView : View(title = "Numass slow control view", icon = ImageVie
} catch (e: Exception) { } catch (e: Exception) {
throw RuntimeException(e) throw RuntimeException(e)
} }
}
fun add(id: String, loader: TableLoader) {
this.data.put(id, loader)
}
fun remove(id: String) {
this.data.remove(id)
} }
} }

View File

@ -7,8 +7,10 @@ import hep.dataforge.fx.fragments.LogFragment
import hep.dataforge.kodex.fx.dfIcon import hep.dataforge.kodex.fx.dfIcon
import hep.dataforge.kodex.fx.runGoal import hep.dataforge.kodex.fx.runGoal
import hep.dataforge.kodex.fx.ui import hep.dataforge.kodex.fx.ui
import hep.dataforge.meta.Metoid
import hep.dataforge.storage.api.Loader import hep.dataforge.storage.api.Loader
import hep.dataforge.storage.api.Storage import hep.dataforge.storage.api.Storage
import hep.dataforge.storage.api.TableLoader
import hep.dataforge.storage.filestorage.FileStorageFactory import hep.dataforge.storage.filestorage.FileStorageFactory
import inr.numass.NumassProperties import inr.numass.NumassProperties
import inr.numass.data.api.NumassPoint import inr.numass.data.api.NumassPoint
@ -71,6 +73,13 @@ class StorageView(private val context: Context = Global.instance()) : View(title
hvView.remove(id) hvView.remove(id)
} }
} }
is TableLoader -> {
if (selected) {
scView.add(id, content)
} else {
scView.remove(id)
}
}
} }
} }
} }
@ -132,22 +141,39 @@ class StorageView(private val context: Context = Global.instance()) : View(title
populate { parent -> populate { parent ->
val value = parent.value.content val value = parent.value.content
when (value) { when (value) {
is Storage -> (value.shelves() + value.loaders()).map { buildContainer(it, parent.value) } is Storage -> (value.shelves().sorted() + value.loaders().sorted()).map { buildContainer(it, parent.value) }
is NumassSet -> value.points.map { buildContainer(it, parent.value) }.toList() is NumassSet -> value.points.map { buildContainer(it, parent.value) }.toList().sortedBy { it.id }
else -> null else -> null
} }
} }
} }
} }
cellFormat { value -> cellFormat { value ->
contextMenu = null
when (value.content) { when (value.content) {
is Storage -> text = value.id is Storage -> {
text = value.id
graphic = null
}
is NumassSet -> { is NumassSet -> {
text = null text = null
graphic = checkbox(value.id, value.checkedProperty) graphic = checkbox(value.id, value.checkedProperty)
}
is NumassPoint -> {
text = null
graphic = checkbox(value.id, value.checkedProperty)
}
is TableLoader -> {
text = null
graphic = checkbox(value.id, value.checkedProperty)
}
else -> {
text = value.id
graphic = null
}
}
if (value.content is Metoid) {
contextMenu = ContextMenu().apply { contextMenu = ContextMenu().apply {
item("Info") { item("Meta") {
action { action {
openInternalBuilderWindow(title = "Info: ${value.id}", escapeClosesWindow = true) { openInternalBuilderWindow(title = "Info: ${value.id}", escapeClosesWindow = true) {
scrollpane { scrollpane {
@ -161,14 +187,8 @@ class StorageView(private val context: Context = Global.instance()) : View(title
} }
} }
} }
} } else {
is NumassPoint -> { contextMenu = null
text = null
graphic = checkbox(value.id, value.checkedProperty)
}
else -> {
text = (value as Loader).name
}
} }
} }
} }
@ -189,6 +209,11 @@ class StorageView(private val context: Context = Global.instance()) : View(title
isClosable = false isClosable = false
//visibleWhen(spectrumView.isEmpty.not()) //visibleWhen(spectrumView.isEmpty.not())
} }
tab("Slow control") {
content = scView.root
isClosable = false
//visibleWhen(scView.isEmpty.not())
}
} }
setDividerPosition(0, 0.3); setDividerPosition(0, 0.3);
} }

View File

@ -1,27 +0,0 @@
package inr.numass.viewer.test
import hep.dataforge.context.Global
import inr.numass.data.api.NumassSet
import inr.numass.data.storage.NumassStorageFactory
import inr.numass.viewer.NumassLoaderView
import javafx.application.Application
import javafx.stage.Stage
import tornadofx.*
import java.io.File
/**
* Created by darksnake on 17-Jul-17.
*/
class NumassTest : App(NumassLoaderView::class) {
override fun start(stage: Stage) {
super.start(stage)
val storage = NumassStorageFactory.buildLocal(File("D:\\Work\\Numass\\data\\2017_05\\"))
Global.setDefaultContext(Global.instance())
val view = find<NumassLoaderView>();
view.data = storage.provide("Fill_1/set_4", NumassSet::class.java).get();
}
}
fun main(args: Array<String>) {
Application.launch(NumassTest::class.java)
}