Partially fixed plot group visualization
This commit is contained in:
parent
25251e64f9
commit
dbe93f546a
@ -31,8 +31,8 @@ import hep.dataforge.exceptions.ControlException;
|
||||
import hep.dataforge.exceptions.MeasurementException;
|
||||
import hep.dataforge.exceptions.StorageException;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.storage.api.PointLoader;
|
||||
import hep.dataforge.storage.api.Storage;
|
||||
import hep.dataforge.storage.api.TableLoader;
|
||||
import hep.dataforge.storage.commons.LoaderFactory;
|
||||
import hep.dataforge.tables.TableFormat;
|
||||
import hep.dataforge.tables.TableFormatBuilder;
|
||||
@ -85,7 +85,7 @@ public class PKT8Device extends PortSensor<PKT8Result> {
|
||||
setMeta(meta);
|
||||
}
|
||||
|
||||
private PointLoader buildLoader(StorageConnection connection) {
|
||||
private TableLoader buildLoader(StorageConnection connection) {
|
||||
Storage storage = connection.getStorage();
|
||||
String suffix = DateTimeUtils.fileSuffix();
|
||||
|
||||
|
@ -36,8 +36,8 @@ import hep.dataforge.exceptions.MeasurementException;
|
||||
import hep.dataforge.exceptions.PortException;
|
||||
import hep.dataforge.exceptions.StorageException;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.storage.api.PointLoader;
|
||||
import hep.dataforge.storage.api.Storage;
|
||||
import hep.dataforge.storage.api.TableLoader;
|
||||
import hep.dataforge.storage.commons.LoaderFactory;
|
||||
import hep.dataforge.tables.TableFormat;
|
||||
import hep.dataforge.tables.TableFormatBuilder;
|
||||
@ -421,7 +421,7 @@ public class MspDevice extends Sensor<Values> implements PortHandler.PortControl
|
||||
this.meta = meta;
|
||||
}
|
||||
|
||||
private PointLoader makeLoader(StorageConnection connection) {
|
||||
private TableLoader makeLoader(StorageConnection connection) {
|
||||
|
||||
try {
|
||||
Storage storage = connection.getStorage();
|
||||
|
@ -3,7 +3,7 @@ package inr.numass.control
|
||||
import hep.dataforge.control.connections.StorageConnection
|
||||
import hep.dataforge.control.devices.AbstractDevice
|
||||
import hep.dataforge.exceptions.StorageException
|
||||
import hep.dataforge.storage.api.PointLoader
|
||||
import hep.dataforge.storage.api.TableLoader
|
||||
import hep.dataforge.values.Values
|
||||
import java.util.*
|
||||
import java.util.function.Function
|
||||
@ -12,8 +12,8 @@ import java.util.function.Function
|
||||
* A helper to store points in multiple loaders
|
||||
* Created by darksnake on 16-May-17.
|
||||
*/
|
||||
class StorageHelper(private val device: AbstractDevice, private val loaderFactory: Function<StorageConnection, PointLoader>) : AutoCloseable {
|
||||
private val loaderMap = HashMap<StorageConnection, PointLoader>()
|
||||
class StorageHelper(private val device: AbstractDevice, private val loaderFactory: Function<StorageConnection, TableLoader>) : AutoCloseable {
|
||||
private val loaderMap = HashMap<StorageConnection, TableLoader>()
|
||||
|
||||
fun push(point: Values) {
|
||||
if (!device.hasState("storing") || device.getState("storing").booleanValue()) {
|
||||
|
@ -19,7 +19,7 @@ import hep.dataforge.control.measurements.Measurement;
|
||||
import hep.dataforge.description.ValueDef;
|
||||
import hep.dataforge.exceptions.ControlException;
|
||||
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.tables.TableFormatBuilder;
|
||||
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);
|
||||
getSensors().forEach((s) -> {
|
||||
format.setType(s.getName(), ValueType.NUMBER);
|
||||
|
@ -23,8 +23,8 @@ public class NumassFileEnvelope extends FileEnvelope {
|
||||
try (SeekableByteChannel channel = Files.newByteChannel(path, READ)) {
|
||||
ByteBuffer header = ByteBuffer.allocate(2);
|
||||
channel.read(header);
|
||||
if(Arrays.equals(header.array(),LEGACY_START_SEQUENCE)){
|
||||
return new NumassFileEnvelope(path,readOnly);
|
||||
if (Arrays.equals(header.array(), LEGACY_START_SEQUENCE)) {
|
||||
return new NumassFileEnvelope(path, readOnly);
|
||||
} else {
|
||||
return FileEnvelope.open(path, readOnly);
|
||||
}
|
||||
@ -38,7 +38,7 @@ public class NumassFileEnvelope extends FileEnvelope {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EnvelopeTag buildTag(){
|
||||
protected EnvelopeTag buildTag() {
|
||||
return new NumassEnvelopeType.LegacyTag();
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ ctx.pluginManager().load(PlotManager)
|
||||
ctx.pluginManager().load(NumassPlugin.class)
|
||||
|
||||
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);
|
||||
|
||||
|
@ -11,8 +11,8 @@ import hep.dataforge.server.ServerManager;
|
||||
import hep.dataforge.server.ServletUtils;
|
||||
import hep.dataforge.server.storage.StorageRatpackHandler;
|
||||
import hep.dataforge.storage.api.ObjectLoader;
|
||||
import hep.dataforge.storage.api.PointLoader;
|
||||
import hep.dataforge.storage.api.Storage;
|
||||
import hep.dataforge.storage.api.TableLoader;
|
||||
import inr.numass.data.api.NumassSet;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import ratpack.handling.Context;
|
||||
@ -73,7 +73,7 @@ public class NumassStorageHandler extends StorageRatpackHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MetaBuilder pointLoaderPlotOptions(PointLoader loader) {
|
||||
protected MetaBuilder pointLoaderPlotOptions(TableLoader loader) {
|
||||
MetaBuilder builder = super.pointLoaderPlotOptions(loader);
|
||||
if (loader.getName().startsWith("msp")
|
||||
|| loader.getName().startsWith("vac")
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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 "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -3,16 +3,21 @@ package inr.numass.viewer
|
||||
import hep.dataforge.kodex.configure
|
||||
import hep.dataforge.kodex.fx.dfIcon
|
||||
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.plots.Plot
|
||||
import hep.dataforge.plots.PlotGroup
|
||||
import hep.dataforge.plots.data.DataPlot
|
||||
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.tables.ListTable
|
||||
import hep.dataforge.tables.Table
|
||||
import hep.dataforge.tables.XYAdapter
|
||||
import hep.dataforge.values.Values
|
||||
import javafx.collections.FXCollections
|
||||
import javafx.collections.MapChangeListener
|
||||
import javafx.collections.ObservableMap
|
||||
import javafx.scene.image.ImageView
|
||||
import tornadofx.*
|
||||
|
||||
@ -30,26 +35,39 @@ class SlowControlView : View(title = "Numass slow control view", icon = ImageVie
|
||||
center = PlotContainer(plot).root
|
||||
}
|
||||
|
||||
//TODO add multiple loaders
|
||||
fun load(loader: PointLoader) {
|
||||
runAsync {
|
||||
val data = getData(loader)
|
||||
ArrayList<Plot>().apply {
|
||||
loader.format.columns.filter { it.name != "timestamp" }.forEach {
|
||||
val adapter = XYAdapter("timestamp", it.name);
|
||||
this += DataPlot.plot(it.name, adapter, data).configure {
|
||||
val data: ObservableMap<String, TableLoader> = FXCollections.observableHashMap();
|
||||
val isEmpty = booleanBinding(data) { data.isEmpty() }
|
||||
|
||||
init {
|
||||
data.addListener { change: MapChangeListener.Change<out String, out TableLoader> ->
|
||||
if (change.wasRemoved()) {
|
||||
plot.remove(change.key)
|
||||
}
|
||||
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
|
||||
"showSymbol" to false
|
||||
"showErrors" to false
|
||||
}
|
||||
group.add(plot)
|
||||
}
|
||||
}
|
||||
group
|
||||
} 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> =
|
||||
if (query.hasValue("index")) {
|
||||
//use custom index if needed
|
||||
@ -63,7 +81,14 @@ class SlowControlView : View(title = "Numass slow control view", icon = ImageVie
|
||||
} catch (e: Exception) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
}
|
||||
|
||||
fun add(id: String, loader: TableLoader) {
|
||||
this.data.put(id, loader)
|
||||
}
|
||||
|
||||
fun remove(id: String) {
|
||||
this.data.remove(id)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,8 +7,10 @@ import hep.dataforge.fx.fragments.LogFragment
|
||||
import hep.dataforge.kodex.fx.dfIcon
|
||||
import hep.dataforge.kodex.fx.runGoal
|
||||
import hep.dataforge.kodex.fx.ui
|
||||
import hep.dataforge.meta.Metoid
|
||||
import hep.dataforge.storage.api.Loader
|
||||
import hep.dataforge.storage.api.Storage
|
||||
import hep.dataforge.storage.api.TableLoader
|
||||
import hep.dataforge.storage.filestorage.FileStorageFactory
|
||||
import inr.numass.NumassProperties
|
||||
import inr.numass.data.api.NumassPoint
|
||||
@ -71,6 +73,13 @@ class StorageView(private val context: Context = Global.instance()) : View(title
|
||||
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 ->
|
||||
val value = parent.value.content
|
||||
when (value) {
|
||||
is Storage -> (value.shelves() + value.loaders()).map { buildContainer(it, parent.value) }
|
||||
is NumassSet -> value.points.map { buildContainer(it, parent.value) }.toList()
|
||||
is Storage -> (value.shelves().sorted() + value.loaders().sorted()).map { buildContainer(it, parent.value) }
|
||||
is NumassSet -> value.points.map { buildContainer(it, parent.value) }.toList().sortedBy { it.id }
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cellFormat { value ->
|
||||
contextMenu = null
|
||||
when (value.content) {
|
||||
is Storage -> text = value.id
|
||||
is Storage -> {
|
||||
text = value.id
|
||||
graphic = null
|
||||
}
|
||||
is NumassSet -> {
|
||||
text = null
|
||||
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 {
|
||||
item("Info") {
|
||||
item("Meta") {
|
||||
action {
|
||||
openInternalBuilderWindow(title = "Info: ${value.id}", escapeClosesWindow = true) {
|
||||
scrollpane {
|
||||
@ -161,14 +187,8 @@ class StorageView(private val context: Context = Global.instance()) : View(title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is NumassPoint -> {
|
||||
text = null
|
||||
graphic = checkbox(value.id, value.checkedProperty)
|
||||
}
|
||||
else -> {
|
||||
text = (value as Loader).name
|
||||
}
|
||||
} else {
|
||||
contextMenu = null
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -189,6 +209,11 @@ class StorageView(private val context: Context = Global.instance()) : View(title
|
||||
isClosable = false
|
||||
//visibleWhen(spectrumView.isEmpty.not())
|
||||
}
|
||||
tab("Slow control") {
|
||||
content = scView.root
|
||||
isClosable = false
|
||||
//visibleWhen(scView.isEmpty.not())
|
||||
}
|
||||
}
|
||||
setDividerPosition(0, 0.3);
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user