Skip to content

Commit 5b1567c

Browse files
committed
fix: faster (threaded) plotting
Signed-off-by: Henry Schreiner <[email protected]>
1 parent a0494a9 commit 5b1567c

File tree

3 files changed

+46
-11
lines changed

3 files changed

+46
-11
lines changed

src/uproot_browser/tui/browser.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import textual.containers
1414
import textual.events
1515
import textual.widgets
16+
import textual.worker
1617
from textual.reactive import var
1718

1819
with contextlib.suppress(AttributeError):
@@ -36,7 +37,7 @@
3637
from .header import Header
3738
from .help import HelpScreen
3839
from .left_panel import UprootTree
39-
from .messages import ErrorMessage, UprootSelected
40+
from .messages import ErrorMessage, RequestPlot, UprootSelected
4041
from .plot import Plotext
4142
from .tools import Info, Tools
4243
from .viewer import ViewWidget
@@ -138,6 +139,16 @@ def on_empty_message(self) -> None:
138139
def on_error_message(self, message: ErrorMessage) -> None:
139140
self.view_widget.item = message.err
140141

142+
def on_request_plot(self, message: RequestPlot) -> None:
143+
self.render_plot(message.plot)
144+
145+
@textual.work(exclusive=True, thread=True)
146+
def render_plot(self, plot: Plotext) -> None:
147+
worker = textual.worker.get_current_worker()
148+
new_plot = plot.make_plot()
149+
if new_plot and not worker.is_cancelled:
150+
self.call_from_thread(self.view_widget.plot_widget.update, new_plot)
151+
141152

142153
if __name__ in {"<run_path>", "__main__"}:
143154
fname = "../scikit-hep-testdata/src/skhep_testdata/data/uproot-Event.root"

src/uproot_browser/tui/messages.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
if TYPE_CHECKING:
99
from .error import Error
10+
from .plot import Plotext
1011

1112

1213
@rich.repr.auto
@@ -27,3 +28,10 @@ class ErrorMessage(textual.message.Message, bubble=True):
2728
def __init__(self, err: Error) -> None:
2829
self.err = err
2930
super().__init__()
31+
32+
33+
@rich.repr.auto
34+
class RequestPlot(textual.message.Message, bubble=True):
35+
def __init__(self, plot: Plotext) -> None:
36+
self.plot = plot
37+
super().__init__()

src/uproot_browser/tui/plot.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from uproot_browser.exceptions import EmptyTreeError
1313

1414
from .error import Error
15-
from .messages import EmptyMessage, ErrorMessage
15+
from .messages import EmptyMessage, ErrorMessage, RequestPlot
1616

1717
if TYPE_CHECKING:
1818
from .browser import Browser
@@ -42,6 +42,23 @@ class Plotext:
4242
selection: str
4343
theme: str
4444
app: Browser
45+
size: tuple[int, int] | None = None
46+
previous: rich.text.Text | None = None
47+
48+
def make_plot(self) -> Plotext | None:
49+
*_, item = apply_selection(self.upfile, self.selection.split(":"))
50+
assert self.size
51+
try:
52+
canvas = make_plot(item, self.theme, *self.size)
53+
return dataclasses.replace(self, previous=rich.text.Text.from_ansi(canvas))
54+
except EmptyTreeError:
55+
self.app.post_message(EmptyMessage())
56+
return None
57+
except Exception:
58+
exc = sys.exc_info()
59+
assert exc[1]
60+
self.app.post_message(ErrorMessage(Error(exc)))
61+
return None
4562

4663
def __rich_console__(
4764
self, console: rich.console.Console, options: rich.console.ConsoleOptions
@@ -55,12 +72,11 @@ def __rich_console__(
5572
width = options.max_width or console.width
5673
height = options.height or console.height
5774

58-
try:
59-
canvas = make_plot(item, self.theme, width, height)
60-
yield rich.text.Text.from_ansi(canvas)
61-
except EmptyTreeError:
62-
self.app.post_message(EmptyMessage())
63-
except Exception:
64-
exc = sys.exc_info()
65-
assert exc[1]
66-
self.app.post_message(ErrorMessage(Error(exc)))
75+
if self.size and (width, height) == self.size and self.previous is not None:
76+
yield self.previous
77+
78+
else:
79+
self.size = (width, height)
80+
self.previous = rich.text.Text("... plotting ...")
81+
yield self.previous
82+
self.app.post_message(RequestPlot(self))

0 commit comments

Comments
 (0)