Skip to content

Commit

Permalink
MNT #183 re-use the cache
Browse files Browse the repository at this point in the history
  • Loading branch information
prjemian committed Nov 28, 2023
1 parent 57f8692 commit 5f1505f
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 80 deletions.
2 changes: 1 addition & 1 deletion gemviz/bluesky_runs_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def doPlotSlot(self, run, stream_name, action, selections):
# setup datasets
try:
datasets, options = to_datasets(
run.run[stream_name], selections, scan_id=scan_id
run, stream_name, selections, scan_id=scan_id
)
except ValueError as exc:
self.setStatus(f"No plot: {exc}")
Expand Down
34 changes: 21 additions & 13 deletions gemviz/select_stream_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from PyQt5 import QtCore
from PyQt5 import QtWidgets

from . import tapi
from . import utils
from .select_fields_tablemodel import ColumnDataType
from .select_fields_tablemodel import FieldRuleType
Expand Down Expand Up @@ -77,7 +76,7 @@ def setStream(self, stream_name):
y_name = self.analysis["plot_signal"]

# describe the data fields for the dialog.
sdf = tapi.stream_data_fields(stream)
sdf = self.run.stream_data_fields(stream_name)
# print(f"{__name__}.{__class__.__name__}: {sdf=}")
fields = []
for field_name in sdf:
Expand All @@ -86,7 +85,15 @@ def setStream(self, stream_name):
selection = "X"
elif y_name is not None and field_name == y_name:
selection = "Y"
shape = tapi.stream_data_field_shape(stream, field_name)
shape = self.run.stream_data_field_shape(stream_name, field_name)
if len(shape) == 0:
# print(f"{stream_name=} {field_name=} {shape=}")
logger.debug(
"stream_name=%s field_name=%s shape=%s",
stream_name,
field_name,
shape,
)
field = TableField(field_name, selection=selection, shape=shape)
fields.append(field)
logger.debug("fields=%s", fields)
Expand All @@ -106,20 +113,23 @@ def relayPlotSelections(self, stream_name, action, selections):
self.selected.emit(stream_name, action, selections)


def to_datasets(stream, selections, scan_id=None):
def to_datasets(run, stream_name, selections, scan_id=None):
"""Prepare datasets and options for plotting."""
from . import chartview

stream = run.stream_data(stream_name)
stream_md = run.stream_metadata(stream_name)

x_axis = selections.get("X")
x_datetime = False # special scaling using datetime
if x_axis is None:
x_data = None
x_units = ""
x_axis = "data point number"
else:
x_data = stream["data"][x_axis].compute()
x_data = stream[x_axis].compute()
x_shape = x_data.shape
x_units = tapi.stream_data_field_units(stream, x_axis)
x_units = run.stream_data_field_units(stream_name, x_axis)
if len(x_shape) != 1:
# fmt: off
raise ValueError(
Expand All @@ -140,20 +150,18 @@ def to_datasets(stream, selections, scan_id=None):
color = chartview.auto_color()
symbol = chartview.auto_symbol()

y_data = stream["data"][y_axis].compute()
y_units = tapi.stream_data_field_units(stream, y_axis)
y_data = stream[y_axis].compute()
y_units = run.stream_data_field_units(stream_name, y_axis)
y_shape = y_data.shape
if len(y_shape) != 1:
# fmt: off
raise ValueError(
"Can only plot 1-D data now."
f" {y_axis} shape is {y_shape}"
)
suffix = stream.metadata["stream_name"]
run_uid = stream.metadata["descriptors"][0].get("run_start", "")
if scan_id is not None:
suffix = f"#{scan_id} {suffix} {run_uid[:7]}"
ds_options["name"] = f"{y_axis} ({suffix})"

run_uid = run.get_run_md("start", "uid")
ds_options["name"] = f"{y_axis} ({run.summary()} {run_uid[:7]})"
ds_options["pen"] = color # line color
ds_options["symbol"] = symbol
ds_options["symbolBrush"] = color # fill color
Expand Down
117 changes: 51 additions & 66 deletions gemviz/tapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@
~QueryTimeSince
~QueryTimeUntil
~RunMetadata
~stream_data_field_pv
~stream_data_field_shape
~stream_data_field_units
~stream_data_fields
~TiledServerError
"""

Expand Down Expand Up @@ -190,6 +186,57 @@ def stream_data(self, stream_name):

return self.streams_data[stream_name]

def stream_data_field_shape(self, stream_name, field_name):
"""Shape of this data field."""
stream = self.stream_data(stream_name)
try:
shape = stream[field_name].shape
except Exception:
shape = ()
return shape

def stream_data_fields(self, stream_name):
"""
Data field (names) of this BlueskyEventStream.
Sort the list by relevance.
First "time" (epoch timestamp for each event document), then "config" (the
caller provided these names as parameters for this stream), then "data"
(other signals in this stream, usually added from a Device hint).
"""
fields = sorted(self.stream_data(stream_name))

# Promote "time" field to first place.
if "time" in fields:
fields.remove("time")
fields.insert(0, "time")
return fields

def stream_data_field_pv(self, stream_name, field_name):
"""EPICS PV name of this field."""
pv = ""
try:
descriptors = self.stream_metadata(stream_name).get("descriptors", {})
assert len(descriptors) == 1, f"{stream_name=} has {len(descriptors)=}"
source = descriptors[0]["data_keys"][field_name].get("source", "")
if source.startswith("PV:"):
pv = source[3:]
except Exception:
pass
return pv

def stream_data_field_units(self, stream_name, field_name):
"""Engineering units of this field."""
units = ""
try:
descriptors = self.stream_metadata(stream_name).get("descriptors", {})
assert len(descriptors) == 1, f"{stream_name=} has {len(descriptors)=}"
units = descriptors[0]["data_keys"][field_name].get("units", "")
except Exception:
pass
return units

def stream_metadata(self, stream_name=None):
"""Return the metadata dictionary for this stream."""
if self.streams_md is None:
Expand Down Expand Up @@ -302,65 +349,3 @@ def get_tiled_runs(cat, since=None, until=None, text=[], text_case=[], **keys):
for v in text_case:
cat = cat.search(tiled.queries.FullText(v, case_sensitive=True))
return cat


def stream_data_fields(stream):
"""
Data field (names) of this BlueskyEventStream.
Sort the list by relevance.
First "time" (epoch timestamp for each event document), then "config" (the
caller provided these names as parameters for this stream), then "data"
(other signals in this stream, usually added from a Device hint).
"""
# List any stream["config"] names first.
fields = sorted(stream.get("config", []))

# Other names from "data" are sorted alphabetically.
for nm in sorted(stream.get("data", [])):
if nm not in fields:
fields.append(nm)

# Promote "time" field to first place.
if "time" in fields:
fields.remove("time")
fields.insert(0, "time")
return fields


def stream_data_field_shape(stream, field_name):
"""Shape of this data field."""
# TODO: Optimize.
# This is called for each field_name, new tiled request each time.
try:
shape = stream["data"][field_name].shape
except Exception:
shape = ()
return shape


def stream_data_field_pv(stream, field_name):
"""EPICS PV name of this field."""
pv = ""
try:
descriptors = list(stream.metadata["descriptors"])
assert len(descriptors) == 1, f"{stream=} has {len(descriptors)=}"
source = descriptors[0]["data_keys"][field_name].get("source", "")
if source.startswith("PV:"):
pv = source[3:]
except Exception:
pass
return pv


def stream_data_field_units(stream, field_name):
"""Engineering units of this field."""
units = ""
try:
descriptors = list(stream.metadata["descriptors"])
assert len(descriptors) == 1, f"{stream=} has {len(descriptors)=}"
units = descriptors[0]["data_keys"][field_name].get("units", "")
except Exception:
pass
return units

0 comments on commit 5f1505f

Please sign in to comment.