rework web server so multiple clients can be server at a time
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
import numpy as np
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_warning
|
||||
from backend.data_types import (
|
||||
COLORMAPS,
|
||||
DataField,
|
||||
@@ -120,7 +121,4 @@ class Annotations:
|
||||
return (ImageData(annotated, metadata={"annotation_context": context}),)
|
||||
|
||||
def _send_warning(self, message: str):
|
||||
fn = Annotations._broadcast_warning_fn
|
||||
nid = Annotations._current_node_id
|
||||
if fn and nid:
|
||||
fn(nid, message)
|
||||
emit_warning(message)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
import numpy as np
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_overlay
|
||||
from backend.data_types import DataField, datafield_to_uint8, encode_preview
|
||||
|
||||
|
||||
@@ -61,20 +62,16 @@ class CropResizeField:
|
||||
x2 = float(np.clip(x2, 0.0, 1.0))
|
||||
y2 = float(np.clip(y2, 0.0, 1.0))
|
||||
|
||||
if CropResizeField._broadcast_overlay_fn is not None:
|
||||
CropResizeField._broadcast_overlay_fn(
|
||||
CropResizeField._current_node_id,
|
||||
{
|
||||
"kind": "crop_box",
|
||||
"image": encode_preview(datafield_to_uint8(field, field.colormap)),
|
||||
"x1": x1,
|
||||
"y1": y1,
|
||||
"x2": x2,
|
||||
"y2": y2,
|
||||
"a_locked": corner_a is not None,
|
||||
"b_locked": corner_b is not None,
|
||||
},
|
||||
)
|
||||
emit_overlay({
|
||||
"kind": "crop_box",
|
||||
"image": encode_preview(datafield_to_uint8(field, field.colormap)),
|
||||
"x1": x1,
|
||||
"y1": y1,
|
||||
"x2": x2,
|
||||
"y2": y2,
|
||||
"a_locked": corner_a is not None,
|
||||
"b_locked": corner_b is not None,
|
||||
})
|
||||
|
||||
left = min(x1, x2)
|
||||
right = max(x1, x2)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
import numpy as np
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_overlay
|
||||
from backend.data_types import DataField, LineData, datafield_to_uint8, encode_preview
|
||||
from backend.nodes.helpers import _extend_to_edges
|
||||
|
||||
@@ -73,19 +74,14 @@ class CrossSection:
|
||||
|
||||
profile = map_coordinates(field.data, [coords_y, coords_x], order=3, mode="nearest")
|
||||
|
||||
if CrossSection._broadcast_overlay_fn is not None:
|
||||
image_uri = encode_preview(datafield_to_uint8(field, field.colormap))
|
||||
|
||||
CrossSection._broadcast_overlay_fn(
|
||||
CrossSection._current_node_id,
|
||||
{
|
||||
"image": image_uri,
|
||||
"x1": marker_x1, "y1": marker_y1,
|
||||
"x2": marker_x2, "y2": marker_y2,
|
||||
"a_locked": marker_pair is not None,
|
||||
"b_locked": marker_pair is not None,
|
||||
},
|
||||
)
|
||||
image_uri = encode_preview(datafield_to_uint8(field, field.colormap))
|
||||
emit_overlay({
|
||||
"image": image_uri,
|
||||
"x1": marker_x1, "y1": marker_y1,
|
||||
"x2": marker_x2, "y2": marker_y2,
|
||||
"a_locked": marker_pair is not None,
|
||||
"b_locked": marker_pair is not None,
|
||||
})
|
||||
|
||||
dx_real = (x2 - x1) * field.xreal
|
||||
dy_real = (y2 - y1) * field.yreal
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
import numpy as np
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_overlay
|
||||
from backend.data_types import DataField, LineData, MeasureTable, encode_preview, render_datafield_preview
|
||||
|
||||
|
||||
@@ -87,22 +88,18 @@ class Cursors:
|
||||
xa, ya = float(x[idx_a]), float(y[idx_a])
|
||||
xb, yb = float(x[idx_b]), float(y[idx_b])
|
||||
|
||||
if Cursors._broadcast_overlay_fn is not None:
|
||||
Cursors._broadcast_overlay_fn(
|
||||
Cursors._current_node_id,
|
||||
{
|
||||
"kind": "line_plot",
|
||||
"section_title": "Cursors",
|
||||
"line": y.tolist(),
|
||||
"x_axis": x.tolist(),
|
||||
"x1": x1,
|
||||
"x2": x2,
|
||||
"y1": float(y1),
|
||||
"y2": float(y2),
|
||||
"a_locked": locked,
|
||||
"b_locked": locked,
|
||||
},
|
||||
)
|
||||
emit_overlay({
|
||||
"kind": "line_plot",
|
||||
"section_title": "Cursors",
|
||||
"line": y.tolist(),
|
||||
"x_axis": x.tolist(),
|
||||
"x1": x1,
|
||||
"x2": x2,
|
||||
"y1": float(y1),
|
||||
"y2": float(y2),
|
||||
"a_locked": locked,
|
||||
"b_locked": locked,
|
||||
})
|
||||
|
||||
table = MeasureTable([
|
||||
{"quantity": "A x", "value": xa, "unit": x_unit},
|
||||
@@ -143,21 +140,17 @@ class Cursors:
|
||||
bx = float(field.xoff + x2 * field.xreal)
|
||||
by = float(field.yoff + y2 * field.yreal)
|
||||
|
||||
if Cursors._broadcast_overlay_fn is not None:
|
||||
Cursors._broadcast_overlay_fn(
|
||||
Cursors._current_node_id,
|
||||
{
|
||||
"kind": "cursor_points",
|
||||
"section_title": "Cursors",
|
||||
"image": encode_preview(render_datafield_preview(field, field.colormap)),
|
||||
"x1": x1,
|
||||
"y1": y1,
|
||||
"x2": x2,
|
||||
"y2": y2,
|
||||
"a_locked": locked,
|
||||
"b_locked": locked,
|
||||
},
|
||||
)
|
||||
emit_overlay({
|
||||
"kind": "cursor_points",
|
||||
"section_title": "Cursors",
|
||||
"image": encode_preview(render_datafield_preview(field, field.colormap)),
|
||||
"x1": x1,
|
||||
"y1": y1,
|
||||
"x2": x2,
|
||||
"y2": y2,
|
||||
"a_locked": locked,
|
||||
"b_locked": locked,
|
||||
})
|
||||
|
||||
table = MeasureTable([
|
||||
{"quantity": "A x", "value": ax, "unit": field.si_unit_xy},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
import numpy as np
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_overlay
|
||||
from backend.data_types import DataField, datafield_to_uint8, encode_preview
|
||||
from backend.nodes.helpers import _parse_mask_strokes, _rasterize_mask
|
||||
|
||||
@@ -40,17 +41,13 @@ class DrawMask:
|
||||
if invert:
|
||||
mask = np.where(mask > 127, np.uint8(0), np.uint8(255))
|
||||
|
||||
if DrawMask._broadcast_overlay_fn is not None:
|
||||
DrawMask._broadcast_overlay_fn(
|
||||
DrawMask._current_node_id,
|
||||
{
|
||||
"kind": "mask_paint",
|
||||
"section_title": "Mask",
|
||||
"image": encode_preview(datafield_to_uint8(field, "gray")),
|
||||
"image_width": field.xres,
|
||||
"image_height": field.yres,
|
||||
"invert": bool(invert),
|
||||
},
|
||||
)
|
||||
emit_overlay({
|
||||
"kind": "mask_paint",
|
||||
"section_title": "Mask",
|
||||
"image": encode_preview(datafield_to_uint8(field, "gray")),
|
||||
"image_width": field.xres,
|
||||
"image_height": field.yres,
|
||||
"invert": bool(invert),
|
||||
})
|
||||
|
||||
return (mask,)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
import numpy as np
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_overlay
|
||||
from backend.data_types import DataField, MeasureTable
|
||||
|
||||
|
||||
@@ -72,22 +73,18 @@ class Histogram:
|
||||
yb = float(counts[idx_b]) if len(counts) else 0.0
|
||||
count_unit = "count" if y_scale == "linear" else "log10(1+count)"
|
||||
|
||||
if Histogram._broadcast_overlay_fn is not None:
|
||||
Histogram._broadcast_overlay_fn(
|
||||
Histogram._current_node_id,
|
||||
{
|
||||
"kind": "line_plot",
|
||||
"section_title": "Histogram",
|
||||
"line": counts.tolist(),
|
||||
"x_axis": bin_centers.astype(np.float64).tolist(),
|
||||
"x1": float(np.clip(x1, 0.0, 1.0)),
|
||||
"x2": float(np.clip(x2, 0.0, 1.0)),
|
||||
"y1": float(y1),
|
||||
"y2": float(y2),
|
||||
"a_locked": False,
|
||||
"b_locked": False,
|
||||
},
|
||||
)
|
||||
emit_overlay({
|
||||
"kind": "line_plot",
|
||||
"section_title": "Histogram",
|
||||
"line": counts.tolist(),
|
||||
"x_axis": bin_centers.astype(np.float64).tolist(),
|
||||
"x1": float(np.clip(x1, 0.0, 1.0)),
|
||||
"x2": float(np.clip(x2, 0.0, 1.0)),
|
||||
"y1": float(y1),
|
||||
"y2": float(y2),
|
||||
"a_locked": False,
|
||||
"b_locked": False,
|
||||
})
|
||||
|
||||
table = MeasureTable([
|
||||
{"quantity": "A position", "value": xa, "unit": field.si_unit_z},
|
||||
|
||||
@@ -4,6 +4,7 @@ import numpy as np
|
||||
from pathlib import Path
|
||||
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_warning
|
||||
from backend.data_types import COLORMAPS, DataField, resolve_colormap_input
|
||||
from backend.nodes.helpers import _resolve_path, _SPM_EXTENSIONS, _import_ibw_loader
|
||||
|
||||
@@ -66,10 +67,7 @@ class Image:
|
||||
return fields
|
||||
|
||||
def _send_warning(self, message: str):
|
||||
fn = Image._broadcast_warning_fn
|
||||
nid = Image._current_node_id
|
||||
if fn and nid:
|
||||
fn(nid, message)
|
||||
emit_warning(message)
|
||||
|
||||
@staticmethod
|
||||
@lru_cache(maxsize=32)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_overlay
|
||||
from backend.data_types import (
|
||||
DataField,
|
||||
ImageData,
|
||||
@@ -70,17 +71,13 @@ class Markup:
|
||||
metadata=image_metadata(input),
|
||||
)
|
||||
|
||||
if Markup._broadcast_overlay_fn is not None:
|
||||
Markup._broadcast_overlay_fn(
|
||||
Markup._current_node_id,
|
||||
{
|
||||
"kind": "markup",
|
||||
"section_title": "Markup",
|
||||
"image": encode_preview(preview_base),
|
||||
"shape": str(shape),
|
||||
"stroke_color": _normalize_markup_color(stroke_color),
|
||||
"stroke_width": max(1, int(stroke_width)),
|
||||
},
|
||||
)
|
||||
emit_overlay({
|
||||
"kind": "markup",
|
||||
"section_title": "Markup",
|
||||
"image": encode_preview(preview_base),
|
||||
"shape": str(shape),
|
||||
"stroke_color": _normalize_markup_color(stroke_color),
|
||||
"stroke_width": max(1, int(stroke_width)),
|
||||
})
|
||||
|
||||
return (out,)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
import numpy as np
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_preview
|
||||
from backend.data_types import DataField, encode_preview
|
||||
from backend.nodes.helpers import _mask_overlay
|
||||
|
||||
@@ -53,10 +54,8 @@ class MaskCombine:
|
||||
|
||||
out = result.astype(np.uint8) * 255
|
||||
|
||||
if field is not None and MaskCombine._broadcast_fn is not None:
|
||||
if field is not None:
|
||||
overlay = _mask_overlay(field, out)
|
||||
MaskCombine._broadcast_fn(
|
||||
MaskCombine._current_node_id, encode_preview(overlay),
|
||||
)
|
||||
emit_preview(encode_preview(overlay))
|
||||
|
||||
return (out,)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
import numpy as np
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_preview
|
||||
from backend.data_types import DataField, encode_preview
|
||||
from backend.nodes.helpers import _mask_overlay
|
||||
|
||||
@@ -32,10 +33,8 @@ class MaskInvert:
|
||||
def process(self, mask: np.ndarray, field: DataField | None = None) -> tuple:
|
||||
out = np.where(mask > 127, np.uint8(0), np.uint8(255))
|
||||
|
||||
if field is not None and MaskInvert._broadcast_fn is not None:
|
||||
if field is not None:
|
||||
overlay = _mask_overlay(field, out)
|
||||
MaskInvert._broadcast_fn(
|
||||
MaskInvert._current_node_id, encode_preview(overlay),
|
||||
)
|
||||
emit_preview(encode_preview(overlay))
|
||||
|
||||
return (out,)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
import numpy as np
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_preview
|
||||
from backend.data_types import DataField, encode_preview
|
||||
from backend.nodes.helpers import _mask_overlay, _mask_structure
|
||||
|
||||
@@ -62,10 +63,8 @@ class MaskMorphology:
|
||||
|
||||
out = result.astype(np.uint8) * 255
|
||||
|
||||
if field is not None and MaskMorphology._broadcast_fn is not None:
|
||||
if field is not None:
|
||||
overlay = _mask_overlay(field, out)
|
||||
MaskMorphology._broadcast_fn(
|
||||
MaskMorphology._current_node_id, encode_preview(overlay),
|
||||
)
|
||||
emit_preview(encode_preview(overlay))
|
||||
|
||||
return (out,)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
import numpy as np
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_preview
|
||||
from backend.data_types import (
|
||||
COLORMAPS,
|
||||
colormap_to_uint8,
|
||||
@@ -68,7 +69,6 @@ class PreviewImage:
|
||||
|
||||
data_uri = encode_preview(arr_u8)
|
||||
|
||||
if PreviewImage._broadcast_fn is not None:
|
||||
PreviewImage._broadcast_fn(PreviewImage._current_node_id, data_uri)
|
||||
emit_preview(data_uri)
|
||||
|
||||
return ()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_table
|
||||
|
||||
|
||||
@register_node(display_name="Print Table")
|
||||
@@ -22,6 +23,5 @@ class PrintTable:
|
||||
_current_node_id: str = ""
|
||||
|
||||
def print_table(self, table: list) -> tuple:
|
||||
if PrintTable._broadcast_table_fn is not None:
|
||||
PrintTable._broadcast_table_fn(PrintTable._current_node_id, table)
|
||||
emit_table(table)
|
||||
return ()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
import numpy as np
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_warning
|
||||
from backend.data_types import DataField
|
||||
|
||||
|
||||
@@ -84,10 +85,7 @@ class RotateField:
|
||||
return (result,)
|
||||
|
||||
def _send_warning(self, message: str):
|
||||
fn = RotateField._broadcast_warning_fn
|
||||
nid = RotateField._current_node_id
|
||||
if fn and nid:
|
||||
fn(nid, message)
|
||||
emit_warning(message)
|
||||
|
||||
@staticmethod
|
||||
def _rotated_extents(field: DataField, angle: float, expand_canvas: bool) -> tuple[float, float]:
|
||||
|
||||
@@ -7,6 +7,7 @@ from pathlib import Path
|
||||
import numpy as np
|
||||
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_warning
|
||||
from backend.data_types import DataField, LineData, MeshModel, datafield_to_uint8, image_to_uint8
|
||||
|
||||
|
||||
@@ -255,7 +256,4 @@ class Save:
|
||||
path.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||||
|
||||
def _send_warning(self, message: str):
|
||||
fn = Save._broadcast_warning_fn
|
||||
nid = Save._current_node_id
|
||||
if fn and nid:
|
||||
fn(nid, message)
|
||||
emit_warning(message)
|
||||
|
||||
@@ -4,6 +4,7 @@ import numpy as np
|
||||
from pathlib import Path
|
||||
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_warning
|
||||
from backend.data_types import DataField, image_to_uint8
|
||||
from backend.nodes.helpers import _MAX_SAVE_FIELDS
|
||||
|
||||
@@ -174,9 +175,6 @@ class SaveImage:
|
||||
raise ValueError(f"Unsupported save layer type: {type(layer).__name__}")
|
||||
|
||||
def _send_warning(self, message: str):
|
||||
fn = SaveImage._broadcast_warning_fn
|
||||
nid = SaveImage._current_node_id
|
||||
if fn and nid:
|
||||
fn(nid, message)
|
||||
emit_warning(message)
|
||||
|
||||
return ()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
import numpy as np
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_value
|
||||
from backend.data_types import DataField, LineData, MeasureTable
|
||||
from backend.nodes.helpers import (
|
||||
LINE_OPS,
|
||||
@@ -71,11 +72,9 @@ class Stats:
|
||||
op_entry = ops[operation]
|
||||
fn = op_entry[0] if isinstance(op_entry, tuple) else op_entry
|
||||
result = fn(values)
|
||||
if Stats._broadcast_value_fn is not None:
|
||||
Stats._broadcast_value_fn(
|
||||
Stats._current_node_id,
|
||||
_scalar_payload(result, self._resolve_output_unit(input, source_type, resolved_column, operation)),
|
||||
)
|
||||
emit_value(
|
||||
_scalar_payload(result, self._resolve_output_unit(input, source_type, resolved_column, operation)),
|
||||
)
|
||||
return (result,)
|
||||
|
||||
def _resolve_output_unit(self, input_value, source_type: str, column: str | None, operation: str) -> str:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
import numpy as np
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_preview
|
||||
from backend.data_types import DataField, encode_preview
|
||||
from backend.nodes.helpers import _mask_overlay
|
||||
|
||||
@@ -52,10 +53,7 @@ class ThresholdMask:
|
||||
else:
|
||||
mask = (data < t).astype(np.uint8) * 255
|
||||
|
||||
if ThresholdMask._broadcast_fn is not None:
|
||||
overlay = _mask_overlay(field, mask)
|
||||
ThresholdMask._broadcast_fn(
|
||||
ThresholdMask._current_node_id, encode_preview(overlay),
|
||||
)
|
||||
overlay = _mask_overlay(field, mask)
|
||||
emit_preview(encode_preview(overlay))
|
||||
|
||||
return (mask,)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_value
|
||||
from backend.data_types import MeasureTable
|
||||
from backend.nodes.helpers import _measurement_entry, _measurement_value, _scalar_payload
|
||||
|
||||
@@ -38,6 +39,5 @@ class ValueDisplay:
|
||||
unit = row.get("unit", "") if isinstance(row.get("unit"), str) else ""
|
||||
else:
|
||||
numeric = float(value)
|
||||
if ValueDisplay._broadcast_value_fn is not None:
|
||||
ValueDisplay._broadcast_value_fn(ValueDisplay._current_node_id, _scalar_payload(numeric, unit))
|
||||
emit_value(_scalar_payload(numeric, unit))
|
||||
return (numeric,)
|
||||
|
||||
@@ -3,6 +3,7 @@ import base64
|
||||
import io
|
||||
import numpy as np
|
||||
from backend.node_registry import register_node
|
||||
from backend.execution_context import emit_mesh
|
||||
from backend.data_types import (
|
||||
COLORMAPS,
|
||||
DataField,
|
||||
@@ -211,8 +212,7 @@ class View3D:
|
||||
"y_range": [float(field.yoff), float(field.yoff + field.yreal)],
|
||||
}
|
||||
|
||||
if View3D._broadcast_mesh_fn is not None:
|
||||
View3D._broadcast_mesh_fn(View3D._current_node_id, mesh_data)
|
||||
emit_mesh(mesh_data)
|
||||
|
||||
annotation_context = _annotation_context_from_field(color_field, resolved_colormap)
|
||||
annotation_context["xreal"] = float(field.xreal)
|
||||
|
||||
Reference in New Issue
Block a user