Viewer update
This commit is contained in:
parent
1a9309fd21
commit
6cd618e5a3
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package inr.numass.data.storage
|
package inr.numass.data.storage
|
||||||
|
|
||||||
|
import hep.dataforge.context.Context
|
||||||
import hep.dataforge.exceptions.StorageException
|
import hep.dataforge.exceptions.StorageException
|
||||||
import hep.dataforge.io.ColumnedDataReader
|
import hep.dataforge.io.ColumnedDataReader
|
||||||
import hep.dataforge.io.envelopes.Envelope
|
import hep.dataforge.io.envelopes.Envelope
|
||||||
@ -23,6 +24,7 @@ import hep.dataforge.meta.MetaBuilder
|
|||||||
import hep.dataforge.providers.Provider
|
import hep.dataforge.providers.Provider
|
||||||
import hep.dataforge.storage.api.ObjectLoader
|
import hep.dataforge.storage.api.ObjectLoader
|
||||||
import hep.dataforge.storage.api.Storage
|
import hep.dataforge.storage.api.Storage
|
||||||
|
import hep.dataforge.storage.commons.DummyStorage
|
||||||
import hep.dataforge.storage.filestorage.FileStorage
|
import hep.dataforge.storage.filestorage.FileStorage
|
||||||
import hep.dataforge.storage.loaders.AbstractLoader
|
import hep.dataforge.storage.loaders.AbstractLoader
|
||||||
import hep.dataforge.tables.Table
|
import hep.dataforge.tables.Table
|
||||||
@ -30,7 +32,6 @@ import inr.numass.data.api.NumassPoint
|
|||||||
import inr.numass.data.api.NumassSet
|
import inr.numass.data.api.NumassSet
|
||||||
import inr.numass.data.legacy.NumassFileEnvelope
|
import inr.numass.data.legacy.NumassFileEnvelope
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
@ -170,6 +171,10 @@ class NumassDataLoader(
|
|||||||
return NumassDataLoader(storage, name, annotation, items)
|
return NumassDataLoader(storage, name, annotation, items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun fromDir(context: Context, directory: Path, name: String = FileStorage.entryName(directory)): NumassDataLoader {
|
||||||
|
return fromDir(DummyStorage(context), directory, name)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* "start_time": "2016-04-20T04:08:50",
|
* "start_time": "2016-04-20T04:08:50",
|
||||||
*
|
*
|
||||||
|
@ -7,16 +7,13 @@ import hep.dataforge.fx.ui
|
|||||||
import hep.dataforge.goals.Goal
|
import hep.dataforge.goals.Goal
|
||||||
import hep.dataforge.kodex.configure
|
import hep.dataforge.kodex.configure
|
||||||
import hep.dataforge.kodex.toList
|
import hep.dataforge.kodex.toList
|
||||||
import hep.dataforge.meta.Meta
|
|
||||||
import hep.dataforge.plots.PlotFrame
|
import hep.dataforge.plots.PlotFrame
|
||||||
import hep.dataforge.plots.PlotGroup
|
import hep.dataforge.plots.PlotGroup
|
||||||
import hep.dataforge.plots.Plottable
|
import hep.dataforge.plots.Plottable
|
||||||
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.tables.Adapters
|
import hep.dataforge.tables.Adapters
|
||||||
import hep.dataforge.tables.Table
|
|
||||||
import inr.numass.data.analyzers.NumassAnalyzer
|
import inr.numass.data.analyzers.NumassAnalyzer
|
||||||
import inr.numass.data.analyzers.SimpleAnalyzer
|
|
||||||
import inr.numass.data.analyzers.withBinning
|
import inr.numass.data.analyzers.withBinning
|
||||||
import inr.numass.data.api.MetaBlock
|
import inr.numass.data.api.MetaBlock
|
||||||
import inr.numass.data.api.NumassBlock
|
import inr.numass.data.api.NumassBlock
|
||||||
@ -32,12 +29,8 @@ import javafx.scene.control.CheckBox
|
|||||||
import javafx.scene.control.ChoiceBox
|
import javafx.scene.control.ChoiceBox
|
||||||
import javafx.scene.image.ImageView
|
import javafx.scene.image.ImageView
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
|
|
||||||
class AmplitudeView(
|
class AmplitudeView : View(title = "Numass amplitude spectrum plot", icon = ImageView(dfIcon)) {
|
||||||
private val analyzer: NumassAnalyzer = SimpleAnalyzer(),
|
|
||||||
private val cache: MutableMap<NumassBlock, Table> = ConcurrentHashMap()
|
|
||||||
) : View(title = "Numass amplitude spectrum plot", icon = ImageView(dfIcon)) {
|
|
||||||
|
|
||||||
private val frame: PlotFrame = JFreeChartFrame().configure {
|
private val frame: PlotFrame = JFreeChartFrame().configure {
|
||||||
"title" to "Detector response plot"
|
"title" to "Detector response plot"
|
||||||
@ -116,13 +109,6 @@ class AmplitudeView(
|
|||||||
center = container.root
|
center = container.root
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate or get spectrum from the immutable
|
|
||||||
*/
|
|
||||||
private fun getSpectrum(point: NumassBlock): Table {
|
|
||||||
return cache.computeIfAbsent(point) { analyzer.getAmplitudeSpectrum(point, Meta.empty()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Put or replace current plot with name `key`
|
* Put or replace current plot with name `key`
|
||||||
*/
|
*/
|
||||||
@ -138,7 +124,7 @@ class AmplitudeView(
|
|||||||
* Distinct map of channel number to corresponding grouping block
|
* Distinct map of channel number to corresponding grouping block
|
||||||
*/
|
*/
|
||||||
private fun NumassPoint.getChannels(): Map<Int, NumassBlock> {
|
private fun NumassPoint.getChannels(): Map<Int, NumassBlock> {
|
||||||
return blocks.toList().groupBy { it.channel ?: 0 }.mapValues { entry ->
|
return blocks.toList().groupBy { it.channel }.mapValues { entry ->
|
||||||
if (entry.value.size == 1) {
|
if (entry.value.size == 1) {
|
||||||
entry.value.first()
|
entry.value.first()
|
||||||
} else {
|
} else {
|
||||||
@ -164,7 +150,7 @@ class AmplitudeView(
|
|||||||
DataPlot.plot(
|
DataPlot.plot(
|
||||||
key,
|
key,
|
||||||
adapter,
|
adapter,
|
||||||
getSpectrum(point).withBinning(binning)
|
PointCache[point].withBinning(binning)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
val group = PlotGroup.typed<DataPlot>(key)
|
val group = PlotGroup.typed<DataPlot>(key)
|
||||||
@ -172,7 +158,7 @@ class AmplitudeView(
|
|||||||
val plot = DataPlot.plot(
|
val plot = DataPlot.plot(
|
||||||
key.toString(),
|
key.toString(),
|
||||||
adapter,
|
adapter,
|
||||||
getSpectrum(block).withBinning(binning)
|
PointCache[point].withBinning(binning)
|
||||||
)
|
)
|
||||||
group.add(plot)
|
group.add(plot)
|
||||||
}
|
}
|
||||||
|
200
numass-viewer/src/main/kotlin/inr/numass/viewer/MainView.kt
Normal file
200
numass-viewer/src/main/kotlin/inr/numass/viewer/MainView.kt
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
package inr.numass.viewer
|
||||||
|
|
||||||
|
import hep.dataforge.context.Context
|
||||||
|
import hep.dataforge.context.Global
|
||||||
|
import hep.dataforge.fx.*
|
||||||
|
import hep.dataforge.fx.fragments.LogFragment
|
||||||
|
import hep.dataforge.storage.commons.StorageManager
|
||||||
|
import inr.numass.NumassProperties
|
||||||
|
import inr.numass.data.api.NumassPoint
|
||||||
|
import inr.numass.data.legacy.NumassFileEnvelope
|
||||||
|
import inr.numass.data.storage.NumassDataLoader
|
||||||
|
import inr.numass.data.storage.NumassStorageFactory
|
||||||
|
import javafx.beans.property.SimpleObjectProperty
|
||||||
|
import javafx.geometry.Insets
|
||||||
|
import javafx.scene.control.Alert
|
||||||
|
import javafx.scene.layout.Priority
|
||||||
|
import javafx.scene.text.Font
|
||||||
|
import javafx.stage.DirectoryChooser
|
||||||
|
import javafx.stage.FileChooser
|
||||||
|
import kotlinx.coroutines.experimental.async
|
||||||
|
import org.controlsfx.control.StatusBar
|
||||||
|
import tornadofx.*
|
||||||
|
import java.io.File
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
class MainView(val context: Context = Global.getContext("viewer")) : View(title = "Numass viewer", icon = dfIconView) {
|
||||||
|
|
||||||
|
private val statusBar = StatusBar();
|
||||||
|
private val logFragment = LogFragment().apply {
|
||||||
|
addLogHandler(context.logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val pathProperty = SimpleObjectProperty<Path>()
|
||||||
|
private var path: Path by pathProperty
|
||||||
|
|
||||||
|
val contentViewProperty = SimpleObjectProperty<UIComponent>()
|
||||||
|
var contentView: UIComponent? by contentViewProperty
|
||||||
|
|
||||||
|
|
||||||
|
override val root = borderpane {
|
||||||
|
prefHeight = 600.0
|
||||||
|
prefWidth = 800.0
|
||||||
|
top {
|
||||||
|
toolbar {
|
||||||
|
prefHeight = 40.0
|
||||||
|
button("Load directory") {
|
||||||
|
action {
|
||||||
|
val chooser = DirectoryChooser()
|
||||||
|
chooser.title = "Select directory to view"
|
||||||
|
val homeDir = NumassProperties.getNumassProperty("numass.viewer.lastPath")
|
||||||
|
try {
|
||||||
|
if (homeDir == null) {
|
||||||
|
chooser.initialDirectory = File(".").absoluteFile
|
||||||
|
} else {
|
||||||
|
chooser.initialDirectory = File(homeDir)
|
||||||
|
}
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
NumassProperties.setNumassProperty("numass.viewer.lastPath", null)
|
||||||
|
}
|
||||||
|
|
||||||
|
val rootDir = chooser.showDialog(primaryStage.scene.window)
|
||||||
|
|
||||||
|
if (rootDir != null) {
|
||||||
|
NumassProperties.setNumassProperty("numass.viewer.lastPath", rootDir.absolutePath)
|
||||||
|
async {
|
||||||
|
runLater {
|
||||||
|
path = rootDir.toPath()
|
||||||
|
}
|
||||||
|
load(rootDir.toPath())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button("Load file") {
|
||||||
|
action {
|
||||||
|
val chooser = FileChooser()
|
||||||
|
chooser.title = "Select file to view"
|
||||||
|
val homeDir = NumassProperties.getNumassProperty("numass.viewer.lastPath")
|
||||||
|
try {
|
||||||
|
if (homeDir == null) {
|
||||||
|
chooser.initialDirectory = File(".").absoluteFile
|
||||||
|
} else {
|
||||||
|
chooser.initialDirectory = File(homeDir)
|
||||||
|
}
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
NumassProperties.setNumassProperty("numass.viewer.lastPath", null)
|
||||||
|
}
|
||||||
|
|
||||||
|
val file = chooser.showOpenDialog(primaryStage.scene.window)
|
||||||
|
if (file != null) {
|
||||||
|
NumassProperties.setNumassProperty("numass.viewer.lastPath", file.parentFile.absolutePath)
|
||||||
|
async {
|
||||||
|
runLater {
|
||||||
|
path = file.toPath()
|
||||||
|
}
|
||||||
|
load(file.toPath())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
label(pathProperty.asString()) {
|
||||||
|
padding = Insets(0.0, 0.0, 0.0, 10.0);
|
||||||
|
font = Font.font("System Bold", 13.0);
|
||||||
|
}
|
||||||
|
pane {
|
||||||
|
hgrow = Priority.ALWAYS
|
||||||
|
}
|
||||||
|
togglebutton("Console") {
|
||||||
|
isSelected = false
|
||||||
|
logFragment.bindWindow(this@togglebutton)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bottom = statusBar
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
contentViewProperty.onChange {
|
||||||
|
root.center = it?.root
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun load(path: Path) {
|
||||||
|
runLater {
|
||||||
|
contentView = null
|
||||||
|
}
|
||||||
|
if (Files.isDirectory(path)) {
|
||||||
|
if (Files.exists(path.resolve(NumassDataLoader.META_FRAGMENT_NAME))) {
|
||||||
|
//build set view
|
||||||
|
runGoal("viewer.load.set[$path]") {
|
||||||
|
title = "Load set ($path)"
|
||||||
|
message = "Building numass set..."
|
||||||
|
NumassDataLoader.fromDir(context, path)
|
||||||
|
} ui {
|
||||||
|
contentView = SpectrumView().apply {
|
||||||
|
add(it.name, it)
|
||||||
|
}
|
||||||
|
} except {
|
||||||
|
alert(
|
||||||
|
type = Alert.AlertType.ERROR,
|
||||||
|
header = "Error during set loading",
|
||||||
|
content = it.toString()
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//build storage
|
||||||
|
runGoal("viewer.load.storage[$path]") {
|
||||||
|
title = "Load storage ($path)"
|
||||||
|
message = "Building numass storage tree..."
|
||||||
|
StorageManager.buildStorage(
|
||||||
|
context,
|
||||||
|
NumassStorageFactory.buildStorageMeta(path.toUri(), true, false)
|
||||||
|
)
|
||||||
|
} ui {
|
||||||
|
contentView = StorageView(it)
|
||||||
|
} except {
|
||||||
|
alert(
|
||||||
|
type = Alert.AlertType.ERROR,
|
||||||
|
header = "Error during storage loading",
|
||||||
|
content = it.toString()
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//Reading individual file
|
||||||
|
val envelope = try {
|
||||||
|
NumassFileEnvelope.open(path,true)
|
||||||
|
} catch (ex: Exception){
|
||||||
|
runLater {
|
||||||
|
alert(
|
||||||
|
type = Alert.AlertType.ERROR,
|
||||||
|
header = "Can't load DF envelope from file $path",
|
||||||
|
content = ex.toString()
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
envelope?.let {
|
||||||
|
if(it.meta.hasMeta("external_meta")){
|
||||||
|
//try to read as point
|
||||||
|
val point = NumassPoint.read(it)
|
||||||
|
runLater {
|
||||||
|
contentView = AmplitudeView().apply {
|
||||||
|
add(path.toString(), point)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert(
|
||||||
|
type = Alert.AlertType.ERROR,
|
||||||
|
header = "Unknown envelope content: $path"
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package inr.numass.viewer
|
||||||
|
|
||||||
|
import hep.dataforge.fx.meta.MetaViewer
|
||||||
|
import inr.numass.data.analyzers.NumassAnalyzer
|
||||||
|
import inr.numass.data.api.NumassPoint
|
||||||
|
import tornadofx.*
|
||||||
|
import tornadofx.controlsfx.borders
|
||||||
|
|
||||||
|
class PointInfoView(val point: NumassPoint) : MetaViewer(point.meta) {
|
||||||
|
private val count: Int by lazy {
|
||||||
|
PointCache[point].sumBy { it.getValue(NumassAnalyzer.COUNT_KEY).int }
|
||||||
|
}
|
||||||
|
|
||||||
|
override val root = super.root.apply {
|
||||||
|
top {
|
||||||
|
gridpane {
|
||||||
|
borders {
|
||||||
|
lineBorder().build()
|
||||||
|
}
|
||||||
|
row {
|
||||||
|
hbox {
|
||||||
|
label("Total number of events: ")
|
||||||
|
label("$count")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
row {
|
||||||
|
hbox {
|
||||||
|
label("Total count rate: ")
|
||||||
|
label(String.format("%.2f", count.toDouble() / point.length.toMillis() * 1000))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,16 +5,11 @@ import hep.dataforge.fx.plots.PlotContainer
|
|||||||
import hep.dataforge.fx.runGoal
|
import hep.dataforge.fx.runGoal
|
||||||
import hep.dataforge.fx.ui
|
import hep.dataforge.fx.ui
|
||||||
import hep.dataforge.kodex.configure
|
import hep.dataforge.kodex.configure
|
||||||
import hep.dataforge.meta.Meta
|
|
||||||
import hep.dataforge.plots.PlotFrame
|
import hep.dataforge.plots.PlotFrame
|
||||||
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.tables.Adapters
|
import hep.dataforge.tables.Adapters
|
||||||
import hep.dataforge.tables.Table
|
|
||||||
import inr.numass.data.analyzers.NumassAnalyzer
|
|
||||||
import inr.numass.data.analyzers.SimpleAnalyzer
|
|
||||||
import inr.numass.data.analyzers.countInWindow
|
import inr.numass.data.analyzers.countInWindow
|
||||||
import inr.numass.data.api.NumassPoint
|
|
||||||
import inr.numass.data.api.NumassSet
|
import inr.numass.data.api.NumassSet
|
||||||
import javafx.beans.property.SimpleIntegerProperty
|
import javafx.beans.property.SimpleIntegerProperty
|
||||||
import javafx.collections.FXCollections
|
import javafx.collections.FXCollections
|
||||||
@ -26,7 +21,6 @@ import javafx.scene.image.ImageView
|
|||||||
import javafx.util.converter.NumberStringConverter
|
import javafx.util.converter.NumberStringConverter
|
||||||
import org.controlsfx.control.RangeSlider
|
import org.controlsfx.control.RangeSlider
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import java.util.stream.Collectors
|
import java.util.stream.Collectors
|
||||||
|
|
||||||
@ -35,10 +29,7 @@ import java.util.stream.Collectors
|
|||||||
* @param analyzer
|
* @param analyzer
|
||||||
* @param cache - optional global point immutable
|
* @param cache - optional global point immutable
|
||||||
*/
|
*/
|
||||||
class SpectrumView(
|
class SpectrumView : View(title = "Numass spectrum plot", icon = ImageView(dfIcon)) {
|
||||||
val analyzer: NumassAnalyzer = SimpleAnalyzer(),
|
|
||||||
val cache: MutableMap<NumassPoint, Table> = ConcurrentHashMap()
|
|
||||||
) : View(title = "Numass spectrum plot", icon = ImageView(dfIcon)) {
|
|
||||||
|
|
||||||
private val frame: PlotFrame = JFreeChartFrame().configure {
|
private val frame: PlotFrame = JFreeChartFrame().configure {
|
||||||
"xAxis.title" to "U"
|
"xAxis.title" to "U"
|
||||||
@ -119,11 +110,6 @@ class SpectrumView(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSpectrum(point: NumassPoint): Table {
|
|
||||||
return cache.computeIfAbsent(point) { analyzer.getAmplitudeSpectrum(point, Meta.empty()) }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateView() {
|
private fun updateView() {
|
||||||
runLater { container.progress = 0.0 }
|
runLater { container.progress = 0.0 }
|
||||||
val progress = AtomicInteger(0)
|
val progress = AtomicInteger(0)
|
||||||
@ -134,7 +120,7 @@ class SpectrumView(
|
|||||||
|
|
||||||
runGoal("spectrumData[$name]") {
|
runGoal("spectrumData[$name]") {
|
||||||
set.points.map { point ->
|
set.points.map { point ->
|
||||||
val count = getSpectrum(point).countInWindow(loChannel.toShort(), upChannel.toShort());
|
val count = PointCache[point].countInWindow(loChannel.toShort(), upChannel.toShort());
|
||||||
val seconds = point.length.toMillis() / 1000.0;
|
val seconds = point.length.toMillis() / 1000.0;
|
||||||
runLater {
|
runLater {
|
||||||
container.progress = progress.incrementAndGet().toDouble() / totalProgress
|
container.progress = progress.incrementAndGet().toDouble() / totalProgress
|
||||||
|
@ -1,55 +1,25 @@
|
|||||||
package inr.numass.viewer
|
package inr.numass.viewer
|
||||||
|
|
||||||
import hep.dataforge.context.Context
|
import hep.dataforge.fx.dfIconView
|
||||||
import hep.dataforge.context.Global
|
|
||||||
import hep.dataforge.fx.*
|
|
||||||
import hep.dataforge.fx.fragments.LogFragment
|
|
||||||
import hep.dataforge.fx.meta.MetaViewer
|
import hep.dataforge.fx.meta.MetaViewer
|
||||||
|
import hep.dataforge.fx.runGoal
|
||||||
import hep.dataforge.meta.Metoid
|
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.api.TableLoader
|
||||||
import hep.dataforge.storage.commons.StorageManager
|
|
||||||
import hep.dataforge.tables.Table
|
|
||||||
import inr.numass.NumassProperties
|
|
||||||
import inr.numass.data.api.NumassPoint
|
import inr.numass.data.api.NumassPoint
|
||||||
import inr.numass.data.api.NumassSet
|
import inr.numass.data.api.NumassSet
|
||||||
import inr.numass.data.storage.NumassDataLoader
|
import inr.numass.data.storage.NumassDataLoader
|
||||||
import inr.numass.data.storage.NumassStorageFactory
|
|
||||||
import javafx.beans.property.SimpleBooleanProperty
|
import javafx.beans.property.SimpleBooleanProperty
|
||||||
import javafx.beans.property.SimpleObjectProperty
|
|
||||||
import javafx.beans.property.SimpleStringProperty
|
|
||||||
import javafx.geometry.Insets
|
|
||||||
import javafx.scene.control.Alert
|
|
||||||
import javafx.scene.control.ContextMenu
|
import javafx.scene.control.ContextMenu
|
||||||
import javafx.scene.control.TreeItem
|
import javafx.scene.control.TreeItem
|
||||||
import javafx.scene.image.ImageView
|
|
||||||
import javafx.scene.layout.Priority
|
|
||||||
import javafx.scene.text.Font
|
|
||||||
import javafx.stage.DirectoryChooser
|
|
||||||
import org.controlsfx.control.StatusBar
|
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
import java.io.File
|
|
||||||
import java.net.URI
|
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
import kotlin.streams.toList
|
import kotlin.streams.toList
|
||||||
|
|
||||||
class StorageView(private val context: Context = Global) : View(title = "Numass storage", icon = ImageView(dfIcon)) {
|
class StorageView(val storage: Storage) : View(title = "Numass storage", icon = dfIconView) {
|
||||||
|
|
||||||
|
private val ampView: AmplitudeView by inject();
|
||||||
val storageProperty = SimpleObjectProperty<Storage?>()
|
private val spectrumView: SpectrumView by inject();
|
||||||
var storage by storageProperty
|
|
||||||
|
|
||||||
|
|
||||||
private val storageNameProperty = SimpleStringProperty("")
|
|
||||||
private var storageName by storageNameProperty
|
|
||||||
|
|
||||||
private val statusBar = StatusBar();
|
|
||||||
|
|
||||||
private val cache: MutableMap<NumassPoint, Table> = ConcurrentHashMap()
|
|
||||||
|
|
||||||
private val ampView: AmplitudeView by inject(params = mapOf("cache" to cache));
|
|
||||||
private val spectrumView: SpectrumView by inject(params = mapOf("cache" to cache));
|
|
||||||
private val hvView: HVView by inject();
|
private val hvView: HVView by inject();
|
||||||
private val scView: SlowControlView by inject();
|
private val scView: SlowControlView by inject();
|
||||||
|
|
||||||
@ -57,6 +27,14 @@ class StorageView(private val context: Context = Global) : View(title = "Numass
|
|||||||
val checkedProperty = SimpleBooleanProperty(false)
|
val checkedProperty = SimpleBooleanProperty(false)
|
||||||
var checked by checkedProperty
|
var checked by checkedProperty
|
||||||
|
|
||||||
|
val infoView: UIComponent? by lazy {
|
||||||
|
when (content) {
|
||||||
|
is NumassPoint -> PointInfoView(content)
|
||||||
|
is Metoid -> MetaViewer(content.meta, title = "Meta view: $id")
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
checkedProperty.onChange { selected ->
|
checkedProperty.onChange { selected ->
|
||||||
when (content) {
|
when (content) {
|
||||||
@ -90,7 +68,10 @@ class StorageView(private val context: Context = Global) : View(title = "Numass
|
|||||||
val children: List<Container>? by lazy {
|
val children: List<Container>? by lazy {
|
||||||
when (content) {
|
when (content) {
|
||||||
is Storage -> (content.shelves().sorted() + content.loaders().sorted()).map { buildContainer(it, this) }
|
is Storage -> (content.shelves().sorted() + content.loaders().sorted()).map { buildContainer(it, this) }
|
||||||
is NumassSet -> content.points.map { buildContainer(it, this) }.toList().sortedBy { it.id }
|
is NumassSet -> content.points
|
||||||
|
.sorted(compareBy { it.index })
|
||||||
|
.map { buildContainer(it, this) }
|
||||||
|
.toList()
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,158 +81,87 @@ class StorageView(private val context: Context = Global) : View(title = "Numass
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override val root = borderpane {
|
|
||||||
top {
|
|
||||||
toolbar {
|
|
||||||
prefHeight = 40.0
|
|
||||||
button("Load") {
|
|
||||||
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)
|
override val root = splitpane {
|
||||||
|
treeview<Container> {
|
||||||
if (rootDir != null) {
|
//isShowRoot = false
|
||||||
NumassProperties.setNumassProperty("numass.storage.root", rootDir.absolutePath)
|
root = TreeItem(Container(storage.name, storage))
|
||||||
loadDirectory(rootDir.toURI())
|
root.isExpanded = true
|
||||||
}
|
runGoal("viewer.storage.populateTree") {
|
||||||
}
|
populate { parent -> parent.value.children }
|
||||||
}
|
|
||||||
label(storageNameProperty) {
|
|
||||||
padding = Insets(0.0, 0.0, 0.0, 10.0);
|
|
||||||
font = Font.font("System Bold", 13.0);
|
|
||||||
}
|
|
||||||
pane {
|
|
||||||
hgrow = Priority.ALWAYS
|
|
||||||
}
|
|
||||||
togglebutton("Console") {
|
|
||||||
isSelected = false
|
|
||||||
LogFragment().apply {
|
|
||||||
addLogHandler(context.logger)
|
|
||||||
bindWindow(this@togglebutton)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
cellFormat { value ->
|
||||||
}
|
when (value.content) {
|
||||||
center {
|
is Storage -> {
|
||||||
splitpane {
|
text = value.content.name
|
||||||
treeview<Container> {
|
graphic = null
|
||||||
//isShowRoot = false
|
}
|
||||||
storageProperty.onChange {
|
is NumassSet -> {
|
||||||
if (it != null) {
|
text = null
|
||||||
root = TreeItem(Container(it.name, it))
|
graphic = checkbox(value.content.name).apply {
|
||||||
root.isExpanded = true
|
selectedProperty().bindBidirectional(value.checkedProperty)
|
||||||
runGoal("populateTree") {
|
|
||||||
runLater { statusBar.progress = -1.0 }
|
|
||||||
populate { parent ->
|
|
||||||
val value = parent.value.content
|
|
||||||
when (value) {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
runLater { statusBar.progress = 0.0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
lazyPopulate( leafCheck = { it.value.hasChildren }) {
|
|
||||||
runLater { statusBar.progress = -1.0 }
|
|
||||||
it.value.children.also {
|
|
||||||
runLater { statusBar.progress = 0.0 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cellFormat { value ->
|
is NumassPoint -> {
|
||||||
when (value.content) {
|
text = null
|
||||||
is Storage -> {
|
graphic = checkbox("${value.content.voltage}[${value.content.index}]").apply {
|
||||||
text = value.content.name
|
selectedProperty().bindBidirectional(value.checkedProperty)
|
||||||
graphic = null
|
|
||||||
}
|
|
||||||
is NumassSet -> {
|
|
||||||
text = null
|
|
||||||
graphic = checkbox(value.content.name).apply {
|
|
||||||
selectedProperty().bindBidirectional(value.checkedProperty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is NumassPoint -> {
|
|
||||||
text = null
|
|
||||||
graphic = checkbox("${value.content.voltage}[${value.content.index}]").apply {
|
|
||||||
selectedProperty().bindBidirectional(value.checkedProperty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is TableLoader -> {
|
|
||||||
text = null
|
|
||||||
graphic = checkbox(value.content.name).apply {
|
|
||||||
selectedProperty().bindBidirectional(value.checkedProperty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
text = value.id
|
|
||||||
graphic = null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
contextMenu = ContextMenu()
|
}
|
||||||
contextMenu.item("Clear all") {
|
is TableLoader -> {
|
||||||
|
text = null
|
||||||
|
graphic = checkbox(value.content.name).apply {
|
||||||
|
selectedProperty().bindBidirectional(value.checkedProperty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
text = value.id
|
||||||
|
graphic = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contextMenu = ContextMenu().apply {
|
||||||
|
item("Clear all") {
|
||||||
|
action {
|
||||||
|
this@cellFormat.treeItem.uncheckAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value.infoView?.let {
|
||||||
|
item("Info") {
|
||||||
action {
|
action {
|
||||||
this@cellFormat.treeItem.uncheckAll()
|
it.openModal(escapeClosesWindow = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (value.content is Metoid) {
|
|
||||||
contextMenu.item("Meta") {
|
|
||||||
action {
|
|
||||||
openInternalWindow(MetaViewer(value.content.meta), escapeClosesWindow = true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tabpane {
|
|
||||||
tab("Amplitude spectra") {
|
|
||||||
content = ampView.root
|
|
||||||
isClosable = false
|
|
||||||
//visibleWhen(ampView.isEmpty.not())
|
|
||||||
}
|
|
||||||
tab("HV") {
|
|
||||||
content = hvView.root
|
|
||||||
isClosable = false
|
|
||||||
//visibleWhen(hvView.isEmpty.not())
|
|
||||||
}
|
|
||||||
tab("Numass spectra") {
|
|
||||||
content = spectrumView.root
|
|
||||||
isClosable = false
|
|
||||||
//visibleWhen(spectrumView.isEmpty.not())
|
|
||||||
}
|
|
||||||
tab("Slow control") {
|
|
||||||
content = scView.root
|
|
||||||
isClosable = false
|
|
||||||
//visibleWhen(scView.isEmpty.not())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setDividerPosition(0, 0.3);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tabpane {
|
||||||
bottom = statusBar;
|
tab("Amplitude spectra") {
|
||||||
|
content = ampView.root
|
||||||
|
isClosable = false
|
||||||
|
//visibleWhen(ampView.isEmpty.not())
|
||||||
|
}
|
||||||
|
tab("HV") {
|
||||||
|
content = hvView.root
|
||||||
|
isClosable = false
|
||||||
|
//visibleWhen(hvView.isEmpty.not())
|
||||||
|
}
|
||||||
|
tab("Numass spectra") {
|
||||||
|
content = spectrumView.root
|
||||||
|
isClosable = false
|
||||||
|
//visibleWhen(spectrumView.isEmpty.not())
|
||||||
|
}
|
||||||
|
tab("Slow control") {
|
||||||
|
content = scView.root
|
||||||
|
isClosable = false
|
||||||
|
//visibleWhen(scView.isEmpty.not())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setDividerPosition(0, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun TreeItem<Container>.uncheckAll() {
|
private fun TreeItem<Container>.uncheckAll() {
|
||||||
this.value.checked = false
|
this.value.checked = false
|
||||||
this.children.forEach { it.uncheckAll() }
|
this.children.forEach { it.uncheckAll() }
|
||||||
@ -280,21 +190,4 @@ class StorageView(private val context: Context = Global) : View(title = "Numass
|
|||||||
else -> throw IllegalArgumentException("Unknown content type: ${content::class.java}");
|
else -> throw IllegalArgumentException("Unknown content type: ${content::class.java}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadDirectory(path: URI) {
|
|
||||||
statusBar.text = "Loading storage: $path"
|
|
||||||
runGoal("loadDirectory[$path]") {
|
|
||||||
title = "Load storage ($path)"
|
|
||||||
message = "Building numass storage tree..."
|
|
||||||
StorageManager.buildStorage(context, NumassStorageFactory.buildStorageMeta(path, true, false))
|
|
||||||
} ui {
|
|
||||||
storage = it
|
|
||||||
storageName = "Storage: $path"
|
|
||||||
|
|
||||||
statusBar.text = "OK"
|
|
||||||
} except {
|
|
||||||
alert(type = Alert.AlertType.ERROR, header = "Error during storage loading", content = it.toString()).show()
|
|
||||||
it.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,11 @@ import ch.qos.logback.classic.Level
|
|||||||
import ch.qos.logback.classic.Logger
|
import ch.qos.logback.classic.Logger
|
||||||
import hep.dataforge.context.Global
|
import hep.dataforge.context.Global
|
||||||
import hep.dataforge.fx.dfIcon
|
import hep.dataforge.fx.dfIcon
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.tables.Table
|
||||||
|
import hep.dataforge.utils.Misc
|
||||||
|
import inr.numass.data.analyzers.SimpleAnalyzer
|
||||||
|
import inr.numass.data.api.NumassPoint
|
||||||
import javafx.stage.Stage
|
import javafx.stage.Stage
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
@ -11,7 +16,7 @@ import tornadofx.*
|
|||||||
/**
|
/**
|
||||||
* Created by darksnake on 14-Apr-17.
|
* Created by darksnake on 14-Apr-17.
|
||||||
*/
|
*/
|
||||||
class Viewer : App(StorageView::class) {
|
class Viewer : App(MainView::class) {
|
||||||
init{
|
init{
|
||||||
(LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME) as Logger).level = Level.INFO
|
(LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME) as Logger).level = Level.INFO
|
||||||
}
|
}
|
||||||
@ -25,4 +30,16 @@ class Viewer : App(StorageView::class) {
|
|||||||
super.stop()
|
super.stop()
|
||||||
Global.terminate();
|
Global.terminate();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global point cache
|
||||||
|
*/
|
||||||
|
object PointCache{
|
||||||
|
private val analyzer = SimpleAnalyzer()
|
||||||
|
private val cache: MutableMap<NumassPoint, Table> = Misc.getLRUCache(1000)
|
||||||
|
|
||||||
|
operator fun get(point: NumassPoint): Table {
|
||||||
|
return cache.computeIfAbsent(point) { analyzer.getAmplitudeSpectrum(point, Meta.empty()) }
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user