Add renderers

This commit is contained in:
Alexander Nozik 2021-12-21 13:29:48 +03:00
parent d1ddf89c6e
commit 7d053d4fa9
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
18 changed files with 309 additions and 97 deletions

2
.gitignore vendored
View File

@ -4,6 +4,6 @@
out/ out/
.gradle .gradle
build/ build/
/notebooks/.ipynb_checkpoints
!gradle-wrapper.jar !gradle-wrapper.jar

View File

@ -9,15 +9,15 @@ allprojects {
} }
group = "ru.inr.mass" group = "ru.inr.mass"
version = "0.1.0-dev-1" version = "0.1.0"
} }
val dataforgeVersion by extra("0.5.2") val dataforgeVersion by extra("0.5.2")
val tablesVersion: String by extra("0.1.1") val tablesVersion: String by extra("0.1.2")
val kmathVersion by extra("0.3.0-dev-17") val kmathVersion by extra("0.3.0-dev-17")
val plotlyVersion: String by extra("0.5.0") val plotlyVersion: String by extra("0.5.0")
ksciencePublish{ ksciencePublish{
git("https://mipt-npm.jetbrains.space/p/numass/code/numass/") github("numass")
space("https://maven.pkg.jetbrains.space/mipt-npm/p/numass/maven") space("https://maven.pkg.jetbrains.space/mipt-npm/p/numass/maven")
} }

View File

@ -0,0 +1,140 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "2a640dcc-4696-408f-b1f0-0cdf917e4719",
"metadata": {},
"outputs": [],
"source": [
"@file:Repository(\"https://repo.kotlin.link\")\n",
"@file:Repository(\"*mavenLocal\")\n",
"@file:DependsOn(\"ru.inr.mass:numass-workspace:0.1.0\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2d193fb2-6c18-4c64-b5c3-3e9ed4099d5b",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"val repo: DataTree<NumassDirectorySet> = Numass.readNumassRepository(\"D:\\\\Work\\\\Numass\\\\data\\\\test\")\n",
"repo"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "373de92b-2533-4cfc-820b-ca90b9d028fc",
"metadata": {},
"outputs": [],
"source": [
"val numassSet = repo[\"set_7\"]\n",
"numassSet"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d0845a15-2928-4e6e-a891-fee130ef5326",
"metadata": {},
"outputs": [],
"source": [
"val point = numassSet.points.first{it.voltage == 14000.0}"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "842dfbcb-17f0-4df9-b5d4-2835f15f3a50",
"metadata": {},
"outputs": [],
"source": [
"point"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "50df6925-82f5-4330-a1c2-3e43fb9cd17d",
"metadata": {},
"outputs": [],
"source": [
"Plotly.plotNumassBlock(point, eventExtractor = NumassEventExtractor.TQDC)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "196f94ca-0439-4190-bda7-8d692c37b2db",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"val frames = point.listFrames()\n",
"Plotly.page {\n",
" p { +\"${frames.size} frames\" }\n",
" h2 { +\"Random frames\" }\n",
" plot {\n",
" val random = kotlin.random.Random(1234)\n",
"\n",
" repeat(10) {\n",
" val frame = frames.random(random)\n",
" scatter {\n",
" y.numbers = frame.signal.map { (it.toUShort().toInt() - Short.MAX_VALUE).toShort() }\n",
" }\n",
" }\n",
" }\n",
" h2 { +\"Analysis\" }\n",
" plot {\n",
" histogram {\n",
" name = \"max\"\n",
" x.numbers = frames.map { frame -> frame.signal.maxOf { (it.toUShort().toInt() - Short.MAX_VALUE).toShort() } }\n",
" }\n",
"\n",
" histogram {\n",
" name = \"max-min\"\n",
" xbins {\n",
" size = 2.0\n",
" }\n",
" x.numbers = frames.map { frame ->\n",
" frame.signal.maxOf { it.toUShort().toInt() - Short.MAX_VALUE } -\n",
" frame.signal.minOf { it.toUShort().toInt() - Short.MAX_VALUE }\n",
" }\n",
" }\n",
" }\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5320d9d5-eae3-469b-a1f2-5d33d3db286c",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Kotlin",
"language": "kotlin",
"name": "kotlin"
},
"language_info": {
"codemirror_mode": "text/x-kotlin",
"file_extension": ".kt",
"mimetype": "text/x-kotlin",
"name": "kotlin",
"nbconvert_exporter": "",
"pygments_lexer": "kotlin",
"version": "1.6.20-dev-6372"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -1,35 +0,0 @@
{
"imports": [
"kscience.plotly.*",
"kscience.plotly.models.*",
"kscience.plotly.JupyterPlotly",
"space.kscience.dataforge.meta.*",
"kotlinx.html.*",
"ru.inr.mass.workspace.*"
],
"repositories": [
"*mavenLocal",
"https://dl.bintray.com/mipt-npm/dataforge",
"https://dl.bintray.com/mipt-npm/kscience",
"https://dl.bintray.com/mipt-npm/dev",
"https://kotlin.bintray.com/kotlinx"
],
"properties": {
"v": "0.1.0-SNAPSHOT"
},
"link": "https://mipt-npm.jetbrains.space/p/numass/code/numass",
"dependencies": [
"ru.inr.mass:numass-workspace:$v"
],
"init": [
"DISPLAY(HTML(JupyterPlotly.loadJs().toString()))",
"DISPLAY(HTML(\"<p>Plotly.kt jupyter integration is in the development phase. Expect glitches!</p>\"))"
],
"renderers": {
"kscience.plotly.HtmlFragment": "HTML($it.toString())",
"kscience.plotly.Plot": "HTML(JupyterPlotly.renderPlot($it))",
"kscience.plotly.PlotlyFragment": "HTML(JupyterPlotly.renderFragment($it))",
"kscience.plotly.PlotlyPage": "HTML(JupyterPlotly.renderPage($it), true)",
"ru.inr.mass.data.proto.NumassDirectorySet": "HTML(JupyterPlotly.renderPage(${it.plotlyPage()}), true)"
}
}

View File

@ -12,7 +12,9 @@ public class NumassAmplitudeSpectrum(public val amplitudes: Map<UShort, ULong>)
public val minChannel: UShort by lazy { amplitudes.keys.minOf { it } } public val minChannel: UShort by lazy { amplitudes.keys.minOf { it } }
public val maxChannel: UShort by lazy { amplitudes.keys.maxOf { it } } public val maxChannel: UShort by lazy { amplitudes.keys.maxOf { it } }
public fun binned(binSize: UInt, range: UIntRange = minChannel..maxChannel): Map<UIntRange, Double> { public val channels: UIntRange by lazy { minChannel..maxChannel }
public fun binned(binSize: UInt, range: UIntRange = channels): Map<UIntRange, Double> {
val keys = sequence { val keys = sequence {
var left = range.first var left = range.first
do { do {
@ -24,6 +26,9 @@ public class NumassAmplitudeSpectrum(public val amplitudes: Map<UShort, ULong>)
return keys.associateWith { bin -> amplitudes.filter { it.key in bin }.values.sum().toDouble() } return keys.associateWith { bin -> amplitudes.filter { it.key in bin }.values.sum().toDouble() }
} }
public fun sum(range: UIntRange = channels): ULong =
amplitudes.filter { it.key in range }.values.sum()
} }
/** /**

View File

@ -15,9 +15,9 @@ public class TimeAnalyzerParameters : Scheme() {
/** /**
* The relative fraction of events that should be removed by time cut * The relative fraction of events that should be removed by time cut
*/ */
public var crFraction by double() public var crFraction: Double? by double()
public var min by double(0.0) public var min: Double by double(0.0)
public var crMin by double(0.0) public var crMin: Double by double(0.0)
/** /**
* The number of events in chunk to split the chain into. If null, no chunks are used * The number of events in chunk to split the chain into. If null, no chunks are used

View File

@ -1,6 +1,7 @@
package ru.inr.mass.data.analysis package ru.inr.mass.data.analysis
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import ru.inr.mass.data.api.NumassBlock import ru.inr.mass.data.api.NumassBlock
import ru.inr.mass.data.api.NumassEvent import ru.inr.mass.data.api.NumassEvent
@ -12,6 +13,30 @@ public fun interface NumassEventExtractor {
* A default event extractor that ignores frames * A default event extractor that ignores frames
*/ */
public val EVENTS_ONLY: NumassEventExtractor = NumassEventExtractor { it.events } public val EVENTS_ONLY: NumassEventExtractor = NumassEventExtractor { it.events }
public val TQDC: NumassEventExtractor = NumassEventExtractor { block ->
block.frames.map { frame ->
var max = 0
var min = 0
var indexOfMax = 0
frame.signal.forEachIndexed { index, sh ->
val corrected = sh.toUShort().toInt() - Short.MAX_VALUE
if (corrected >= max) {
max = corrected
indexOfMax = index
}
if (corrected <= min) {
min = corrected
}
}
NumassEvent(
(max - min).toShort().toUShort(),
frame.timeOffset + frame.tickSize.inWholeNanoseconds * indexOfMax,
block
)
}
}
} }
} }

View File

@ -8,6 +8,7 @@ import ru.inr.mass.data.api.NumassBlock
import ru.inr.mass.data.api.getTime import ru.inr.mass.data.api.getTime
import space.kscience.kmath.histogram.UnivariateHistogram import space.kscience.kmath.histogram.UnivariateHistogram
import kotlin.math.max import kotlin.math.max
import kotlin.time.DurationUnit
public fun <T, R> Flow<T>.zipWithNext(block: (l: T, r: T) -> R): Flow<R> { public fun <T, R> Flow<T>.zipWithNext(block: (l: T, r: T) -> R): Flow<R> {
var current: T? = null var current: T? = null
@ -26,7 +27,7 @@ public fun NumassBlock.timeHistogram(
runBlocking { runBlocking {
extractor.extract(this@timeHistogram).zipWithNext { l, r -> extractor.extract(this@timeHistogram).zipWithNext { l, r ->
if(l.owner == r.owner) { if(l.owner == r.owner) {
max((r.getTime() - l.getTime()).inWholeMicroseconds,0L) max((r.getTime() - l.getTime()).toDouble(DurationUnit.SECONDS),0.0)
} else { } else {
0 0
} }

View File

@ -1,17 +1,17 @@
package ru.inr.mass.data.api package ru.inr.mass.data.api
import kotlinx.datetime.Instant
import kotlin.time.Duration import kotlin.time.Duration
/** /**
* The continuous frame of digital detector data * The continuous frame of digital detector data
* Created by darksnake on 06-Jul-17. * Created by darksnake on 06-Jul-17.
* @param time The absolute start time of the frame * @param timeOffset The time offset relative to block start in nanos
* @param tickSize The time interval per tick * @param tickSize The time interval per tick
* @param signal The buffered signal shape in ticks * @param signal The buffered signal shape in ticks
*/ */
public class NumassFrame( public class NumassFrame(
public val time: Instant, public val timeOffset: Long,
public val tickSize: Duration, public val tickSize: Duration,
public val signal: ShortArray, public val signal: ShortArray,
) { ) {

View File

@ -89,6 +89,8 @@ public interface NumassPoint : ParentBlock {
} }
} }
public val NumassPoint.title: String get() = "p$index(HV=$voltage)"
/** /**
* Get the first block if it exists. Throw runtime exception otherwise. * Get the first block if it exists. Throw runtime exception otherwise.
* *

View File

@ -19,9 +19,7 @@ package ru.inr.mass.data.proto
import io.ktor.utils.io.core.readBytes import io.ktor.utils.io.core.readBytes
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.datetime.DateTimeUnit
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import kotlinx.datetime.plus
import okio.ByteString import okio.ByteString
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import ru.inr.mass.data.api.* import ru.inr.mass.data.api.*
@ -202,9 +200,9 @@ public class ProtoNumassBlock(
get() { get() {
val tickSize = block.bin_size.nanoseconds val tickSize = block.bin_size.nanoseconds
return block.frames.asFlow().map { frame -> return block.frames.asFlow().map { frame ->
val time = startTime.plus(frame.time, DateTimeUnit.NANOSECOND) //val time = startTime.plus(frame.time, DateTimeUnit.NANOSECOND)
val frameData = frame.data_ val frameData = frame.data_
NumassFrame(time, tickSize, frameData.toShortArray()) NumassFrame(frame.time, tickSize, frameData.toShortArray())
} }
} }

View File

@ -33,7 +33,7 @@ class TestNumassDirectory {
fun testTQDCRead() = runBlocking { fun testTQDCRead() = runBlocking {
val pointPath = Path.of("src/test/resources", "testData/tqdc") val pointPath = Path.of("src/test/resources", "testData/tqdc")
val set: NumassSet = context.readNumassDirectory(pointPath) val set: NumassSet = context.readNumassDirectory(pointPath)
val point = set.first { it.voltage == 16000.0 } val point = set.first { it.voltage == 18200.0 }
point.getChannels().forEach { (channel, block) -> point.getChannels().forEach { (channel, block) ->
println("$channel: $block") println("$channel: $block")
if(block is ParentBlock){ if(block is ParentBlock){

View File

@ -1,6 +1,6 @@
plugins { plugins {
kotlin("jvm") id("ru.mipt.npm.gradle.jvm")
id("ru.mipt.npm.gradle.common") id("com.github.johnrengelman.shadow") version "7.1.1"
`maven-publish` `maven-publish`
} }
@ -11,6 +11,7 @@ kotlin {
val dataforgeVersion: String by rootProject.extra val dataforgeVersion: String by rootProject.extra
val plotlyVersion: String by rootProject.extra val plotlyVersion: String by rootProject.extra
val kmathVersion: String by rootProject.extra val kmathVersion: String by rootProject.extra
val tablesVersion: String by rootProject.extra
dependencies { dependencies {
implementation(projects.numassDataProto) implementation(projects.numassDataProto)
@ -19,6 +20,7 @@ dependencies {
implementation("space.kscience:dataforge-workspace:$dataforgeVersion") implementation("space.kscience:dataforge-workspace:$dataforgeVersion")
implementation("space.kscience:plotlykt-jupyter:$plotlyVersion") implementation("space.kscience:plotlykt-jupyter:$plotlyVersion")
implementation("space.kscience:kmath-jupyter:$kmathVersion") implementation("space.kscience:kmath-jupyter:$kmathVersion")
implementation("space.kscience:tables-kt:$tablesVersion")
} }
kscience{ kscience{

View File

@ -4,10 +4,17 @@ package ru.inr.mass.notebook
import org.jetbrains.kotlinx.jupyter.api.HTML import org.jetbrains.kotlinx.jupyter.api.HTML
import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration
import ru.inr.mass.data.api.NumassBlock import ru.inr.mass.data.api.NumassBlock
import ru.inr.mass.data.api.NumassFrame
import ru.inr.mass.data.api.NumassSet import ru.inr.mass.data.api.NumassSet
import ru.inr.mass.data.proto.NumassDirectorySet
import ru.inr.mass.workspace.Numass import ru.inr.mass.workspace.Numass
import ru.inr.mass.workspace.numassSet import ru.inr.mass.workspace.plotNumassBlock
import ru.inr.mass.workspace.plotNumassSet
import space.kscience.dataforge.data.DataTree
import space.kscience.plotly.Plotly import space.kscience.plotly.Plotly
import space.kscience.plotly.scatter
import space.kscience.plotly.toHTML
import space.kscience.plotly.toPage
internal class NumassJupyter : JupyterIntegration() { internal class NumassJupyter : JupyterIntegration() {
override fun Builder.onLoaded() { override fun Builder.onLoaded() {
@ -30,11 +37,26 @@ internal class NumassJupyter : JupyterIntegration() {
render<NumassBlock> { render<NumassBlock> {
HTML(Plotly.plotNumassBlock(it).toPage().render())
}
render<NumassFrame> { numassFrame ->
HTML(
Plotly.plot {
scatter {
x.numbers = numassFrame.signal.indices.map { numassFrame.tickSize.times(it).inWholeNanoseconds }
y.numbers = numassFrame.signal.toList()
}
}.toHTML()
)
} }
render<NumassSet> { numassSet -> render<NumassSet> { numassSet ->
HTML(Plotly.numassSet(numassSet).render(), true) HTML(Plotly.plotNumassSet(numassSet).toPage().render())
}
render<DataTree<NumassDirectorySet>> { tree ->
HTML("TODO: render repository tree")
} }
} }
} }

View File

@ -2,7 +2,7 @@ package ru.inr.mass.scripts
import ru.inr.mass.data.proto.NumassDirectorySet import ru.inr.mass.data.proto.NumassDirectorySet
import ru.inr.mass.workspace.Numass.readNumassRepository import ru.inr.mass.workspace.Numass.readNumassRepository
import ru.inr.mass.workspace.numassSet import ru.inr.mass.workspace.plotNumassSet
import space.kscience.dataforge.data.DataTree import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.data.await import space.kscience.dataforge.data.await
import space.kscience.dataforge.data.getData import space.kscience.dataforge.data.getData
@ -14,5 +14,5 @@ suspend fun main() {
//val dataPath = Path.of("D:\\Work\\Numass\\data\\2018_04\\Adiabacity_19\\set_4\\") //val dataPath = Path.of("D:\\Work\\Numass\\data\\2018_04\\Adiabacity_19\\set_4\\")
//val testSet = NUMASS.context.readNumassDirectory(dataPath) //val testSet = NUMASS.context.readNumassDirectory(dataPath)
val testSet = repo.getData("Adiabacity_19.set_3")?.await() ?: error("Not found") val testSet = repo.getData("Adiabacity_19.set_3")?.await() ?: error("Not found")
Plotly.numassSet(testSet).makeFile() Plotly.plotNumassSet(testSet).makeFile()
} }

View File

@ -1,19 +1,19 @@
package ru.inr.mass.scripts package ru.inr.mass.scripts
import kotlinx.coroutines.flow.toList
import kotlinx.html.h2 import kotlinx.html.h2
import kotlinx.html.p import kotlinx.html.p
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import ru.inr.mass.workspace.Numass.readNumassDirectory import ru.inr.mass.workspace.Numass.readNumassDirectory
import ru.inr.mass.workspace.listFrames
import space.kscience.dataforge.meta.MetaSerializer import space.kscience.dataforge.meta.MetaSerializer
import space.kscience.plotly.* import space.kscience.plotly.*
suspend fun main() { suspend fun main() {
//val repo: DataTree<NumassDirectorySet> = readNumassRepository("D:\\Work\\numass-data\\") //val repo: DataTree<NumassDirectorySet> = readNumassRepository("D:\\Work\\numass-data\\")
val directory = readNumassDirectory("D:\\Work\\numass-data\\set_3\\") val directory = readNumassDirectory("D:\\Work\\Numass\\data\\test\\set_7")
val point = directory.points.first() val point = directory.points.first()
val frames = point.frames.toList() val frames = point.listFrames()
Plotly.page { Plotly.page {
p { +"${frames.size} frames" } p { +"${frames.size} frames" }
h2 { +"Random frames" } h2 { +"Random frames" }
@ -23,7 +23,7 @@ suspend fun main() {
repeat(10) { repeat(10) {
val frame = frames.random(random) val frame = frames.random(random)
scatter { scatter {
y.numbers = frame.signal.map { it.toUShort().toInt() - Short.MAX_VALUE } y.numbers = frame.signal.map { (it.toUShort().toInt() - Short.MAX_VALUE).toShort() }
} }
} }
} }
@ -31,7 +31,7 @@ suspend fun main() {
plot { plot {
histogram { histogram {
name = "max" name = "max"
x.numbers = frames.map { frame -> frame.signal.maxOf { it.toUShort().toInt() - Short.MAX_VALUE } } x.numbers = frames.map { frame -> frame.signal.maxOf { (it.toUShort().toInt() - Short.MAX_VALUE).toShort() } }
} }
histogram { histogram {

View File

@ -1,8 +1,10 @@
package ru.inr.mass.workspace package ru.inr.mass.workspace
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import ru.inr.mass.data.api.NumassBlock
import ru.inr.mass.data.api.NumassSet import ru.inr.mass.data.api.NumassSet
import ru.inr.mass.data.proto.NumassDirectorySet import ru.inr.mass.data.proto.NumassDirectorySet
import ru.inr.mass.data.proto.readNumassDirectory import ru.inr.mass.data.proto.readNumassDirectory
@ -45,3 +47,7 @@ object Numass {
operator fun DataSet<NumassSet>.get(name: String): NumassSet? = runBlocking { operator fun DataSet<NumassSet>.get(name: String): NumassSet? = runBlocking {
getData(Name.parse(name))?.await() getData(Name.parse(name))?.await()
} }
fun NumassBlock.listFrames() = runBlocking { frames.toList() }
fun NumassBlock.listEvents() = runBlocking { events.toList() }

View File

@ -7,7 +7,10 @@ import ru.inr.mass.data.analysis.NumassAmplitudeSpectrum
import ru.inr.mass.data.analysis.NumassEventExtractor import ru.inr.mass.data.analysis.NumassEventExtractor
import ru.inr.mass.data.analysis.amplitudeSpectrum import ru.inr.mass.data.analysis.amplitudeSpectrum
import ru.inr.mass.data.analysis.timeHistogram import ru.inr.mass.data.analysis.timeHistogram
import ru.inr.mass.data.api.NumassBlock
import ru.inr.mass.data.api.NumassPoint
import ru.inr.mass.data.api.NumassSet import ru.inr.mass.data.api.NumassSet
import ru.inr.mass.data.api.title
import ru.inr.mass.data.proto.HVData import ru.inr.mass.data.proto.HVData
import ru.inr.mass.data.proto.NumassDirectorySet import ru.inr.mass.data.proto.NumassDirectorySet
import space.kscience.dataforge.values.asValue import space.kscience.dataforge.values.asValue
@ -20,6 +23,7 @@ import space.kscience.kmath.structures.Buffer
import space.kscience.kmath.structures.DoubleBuffer import space.kscience.kmath.structures.DoubleBuffer
import space.kscience.plotly.* import space.kscience.plotly.*
import space.kscience.plotly.models.* import space.kscience.plotly.models.*
import kotlin.time.DurationUnit
/** /**
* Plot a kmath histogram * Plot a kmath histogram
@ -52,47 +56,89 @@ fun Plot.hvData(data: HVData): Trace = scatter {
y.numbers = data.map { it.value } y.numbers = data.map { it.value }
} }
fun Plotly.numassSet(
set: NumassSet, fun Plotly.plotNumassBlock(
block: NumassBlock,
amplitudeBinSize: UInt = 20U, amplitudeBinSize: UInt = 20U,
eventExtractor: NumassEventExtractor = NumassEventExtractor.EVENTS_ONLY, eventExtractor: NumassEventExtractor = NumassEventExtractor.EVENTS_ONLY,
): PlotlyPage = splitChannels: Boolean = true
Plotly.page { ): PlotlyFragment = Plotly.fragment {
h1 { plot {
+"Numass point set ${ShapeType.path}" runBlocking {
} if (splitChannels && block is NumassPoint) {
h2 { block.getChannels().forEach { (channel, channelBlock) ->
+"Amplitude spectrum" val spectrum = channelBlock.amplitudeSpectrum(eventExtractor)
} histogram(spectrum, amplitudeBinSize) {
plot { name = block.title + "[$channel]"
runBlocking { }
set.points.sortedBy { it.index }.forEach {
histogram(it.amplitudeSpectrum(eventExtractor), amplitudeBinSize)
} }
} } else {
} scatter {
val spectrum = block.amplitudeSpectrum(eventExtractor)
h2 { histogram(spectrum, amplitudeBinSize)
+"Time spectra"
}
plot {
set.points.sortedBy { it.index }.forEach {
histogram(it.timeHistogram(1e3))
}
layout.yaxis.type = AxisType.log
}
if (set is NumassDirectorySet) {
set.getHvData()?.let { entries ->
h2 {
+"HV"
}
plot {
hvData(entries)
} }
} }
} }
} }
}
fun Plotly.plotNumassSet(
set: NumassSet,
amplitudeBinSize: UInt = 20U,
eventExtractor: NumassEventExtractor = NumassEventExtractor.EVENTS_ONLY,
): PlotlyFragment = Plotly.fragment {
h1 { +"Numass point set ${(set as? NumassDirectorySet)?.path ?: ""}" }
//TODO do in parallel
val spectra = runBlocking {
set.points.sortedBy { it.index }.map { it to it.amplitudeSpectrum(eventExtractor) }
}
h2 { +"Amplitude spectrum" }
plot {
spectra.forEach { (point, spectrum) ->
histogram(spectrum, amplitudeBinSize) {
name = point.title
}
}
}
h2 { +"Time spectra" }
plot {
spectra.forEach { (point,spectrum) ->
val countRate = runBlocking {
spectrum.sum().toDouble() / point.getLength().toDouble(DurationUnit.SECONDS)
}
val binSize = 1.0 / countRate / 10.0
histogram(point.timeHistogram(binSize)) {
name = point.title
}
}
layout.yaxis.type = AxisType.log
}
h2 { +"Integral spectrum" }
plot {
scatter {
mode = ScatterMode.markers
x.numbers = spectra.map { it.first.voltage }
y.numbers = spectra.map { it.second.sum().toLong() }
}
}
if (set is NumassDirectorySet) {
set.getHvData()?.let { entries ->
h2 { +"HV" }
plot {
hvData(entries)
}
}
}
}
/** /**
* Add a number buffer accessor for Plotly trace values * Add a number buffer accessor for Plotly trace values