pfund-plot 0.0.3__tar.gz → 0.0.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/PKG-INFO +1 -1
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/pyproject.toml +1 -1
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/__init__.py +8 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/cli/commands/gallery/gallery_marimo.py +2 -2
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/layout/tabs/panel.py +12 -1
- pfund_plot-0.0.5/src/pfund_plot/plots/panel.py +45 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/plot.py +16 -8
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/utils/__init__.py +10 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/README.md +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/__main__.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/cli/__init__.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/cli/commands/gallery/__init__.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/cli/commands/serve.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/cli/main.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/config.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/enums/__init__.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/enums/dataframe_backend.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/enums/display_mode.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/enums/panel_design.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/enums/panel_theme.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/enums/plotting_backend.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/js_tap/components/candlestick.js +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/mixins/streaming_market_feed_mixin.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/altair.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/area/__init__.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/area/bokeh.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/bar/__init__.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/bar/bokeh.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/bokeh.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/candlestick/__init__.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/candlestick/bokeh.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/candlestick/svelte.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/holoviews.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/label/__init__.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/label/bokeh.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/layout/__init__.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/layout/layout.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/layout/panel.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/layout/tabs/__init__.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/lazy.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/line/__init__.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/line/bokeh.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/matplotlib.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/plotly.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/scatter/__init__.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/scatter/bokeh.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/scatter/marker.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/plots/ta.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/renderers/base.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/renderers/browser.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/renderers/desktop.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/renderers/notebook.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/typing.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/utils/bokeh.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/widgets/base.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/widgets/datetime_widget.py +0 -0
- {pfund_plot-0.0.3 → pfund_plot-0.0.5}/src/pfund_plot/widgets/ticker_widget.py +0 -0
|
@@ -51,6 +51,9 @@ if TYPE_CHECKING:
|
|
|
51
51
|
from pfund_plot.plots.matplotlib import (
|
|
52
52
|
Matplotlib as mpl,
|
|
53
53
|
)
|
|
54
|
+
from pfund_plot.plots.panel import (
|
|
55
|
+
Panel as panel,
|
|
56
|
+
)
|
|
54
57
|
from pfund_plot.plots.plotly import (
|
|
55
58
|
Plotly as plotly,
|
|
56
59
|
)
|
|
@@ -93,6 +96,10 @@ def __getattr__(name: str):
|
|
|
93
96
|
from pfund_plot.plots.plotly import Plotly
|
|
94
97
|
|
|
95
98
|
return Plotly
|
|
99
|
+
elif name == "panel":
|
|
100
|
+
from pfund_plot.plots.panel import Panel
|
|
101
|
+
|
|
102
|
+
return Panel
|
|
96
103
|
elif name in ("candlestick", "ohlc", "kline"):
|
|
97
104
|
from pfund_plot.plots.candlestick import Candlestick
|
|
98
105
|
|
|
@@ -167,6 +174,7 @@ __all__ = (
|
|
|
167
174
|
"matplotlib",
|
|
168
175
|
"mpl",
|
|
169
176
|
"ohlc",
|
|
177
|
+
"panel",
|
|
170
178
|
"plotly",
|
|
171
179
|
"scatter",
|
|
172
180
|
"tabs",
|
|
@@ -5,7 +5,7 @@ import marimo
|
|
|
5
5
|
__generated_with = "0.23.9"
|
|
6
6
|
app = marimo.App(width="columns")
|
|
7
7
|
|
|
8
|
-
with app.setup:
|
|
8
|
+
with app.setup(hide_code=True):
|
|
9
9
|
from threading import Thread
|
|
10
10
|
|
|
11
11
|
import altair as alt
|
|
@@ -72,7 +72,7 @@ with app.setup:
|
|
|
72
72
|
)
|
|
73
73
|
|
|
74
74
|
|
|
75
|
-
@app.cell
|
|
75
|
+
@app.cell(hide_code=True)
|
|
76
76
|
def _():
|
|
77
77
|
mo.md("""
|
|
78
78
|
# Gallery
|
|
@@ -41,8 +41,19 @@ def plot(
|
|
|
41
41
|
control: dict[str, Any],
|
|
42
42
|
**kwargs: Any,
|
|
43
43
|
) -> Tabs:
|
|
44
|
+
# In the marimo + svelte combo the plot's component is a mo.vstack (see
|
|
45
|
+
# Candlestick._create_component), which carries no name, so Panel assigns a
|
|
46
|
+
# default tab label like "Column01805". Panel's Tabs accepts a (name, object)
|
|
47
|
+
# tuple to label a tab explicitly, so pass the plot's name in that case.
|
|
48
|
+
# Every other component is a pn.Column that already carries its own name.
|
|
49
|
+
items = [
|
|
50
|
+
(plot.name, plot.component)
|
|
51
|
+
if plot._plot._is_using_marimo_svelte_combo()
|
|
52
|
+
else plot.component
|
|
53
|
+
for plot in plots
|
|
54
|
+
]
|
|
44
55
|
return Tabs(
|
|
45
|
-
*
|
|
56
|
+
*items,
|
|
46
57
|
height=style["height"],
|
|
47
58
|
width=style["width"],
|
|
48
59
|
dynamic=control["dynamic"],
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, ClassVar, Literal
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from panel.viewable import Viewable
|
|
7
|
+
|
|
8
|
+
import panel as pn
|
|
9
|
+
|
|
10
|
+
from pfund_plot.enums import PlottingBackend
|
|
11
|
+
from pfund_plot.plots.plot import BasePlot
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Panel(BasePlot):
|
|
15
|
+
"""Wraps a pre-built Panel ``Viewable`` so it can participate in layouts.
|
|
16
|
+
|
|
17
|
+
Combining plots with ``+`` or ``|`` produces a ``LazyRow``/``LazyColumn``
|
|
18
|
+
(raw Panel components), not a ``LazyPlot``. This adapter lets such a
|
|
19
|
+
component be dropped into ``plt.tabs`` / ``plt.layout`` like any other plot.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
SUPPORTED_BACKENDS: ClassVar[list[Literal[PlottingBackend.panel]]] = [
|
|
23
|
+
PlottingBackend.panel
|
|
24
|
+
]
|
|
25
|
+
REQUIRED_DATA: ClassVar[bool] = False
|
|
26
|
+
|
|
27
|
+
def __init__(self, viewable: Viewable, name: str | None = None):
|
|
28
|
+
super().__init__(data=None, name=name)
|
|
29
|
+
self._viewable: Viewable = viewable
|
|
30
|
+
|
|
31
|
+
# the viewable is already fully built — no plot/pane construction needed
|
|
32
|
+
def _create_plot(self) -> None:
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
def _create_pane(self) -> None:
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
def _create_component(self) -> None:
|
|
39
|
+
# The viewable is already a finished component (no plot/pane layer here),
|
|
40
|
+
# but Panel makes `name` a constant param — it can't be renamed after
|
|
41
|
+
# construction, and the pre-built viewable keeps Panel's auto name like
|
|
42
|
+
# "LazyRow03407". So wrap it in a named pn.Column (the only way to attach a
|
|
43
|
+
# name); that name is what plt.tabs shows as the tab label. With no name=
|
|
44
|
+
# passed, self.name falls back to the class name "panel".
|
|
45
|
+
self._component = pn.Column(self._viewable, name=self.name)
|
|
@@ -78,7 +78,7 @@ class BasePlot:
|
|
|
78
78
|
@staticmethod
|
|
79
79
|
def _check_if_inject_streaming_mixin(
|
|
80
80
|
cls: type[BasePlot], data: Any
|
|
81
|
-
) -> type[BasePlot]:
|
|
81
|
+
) -> type[BasePlot]:
|
|
82
82
|
"""Dynamically inject streaming mixin based on feed type if not already in MRO."""
|
|
83
83
|
if not cls.SUPPORT_STREAMING:
|
|
84
84
|
return cls
|
|
@@ -272,6 +272,16 @@ class BasePlot:
|
|
|
272
272
|
)
|
|
273
273
|
return df
|
|
274
274
|
|
|
275
|
+
def _widgets_enabled(self) -> bool:
|
|
276
|
+
"""Whether interactive widgets are active for this plot."""
|
|
277
|
+
from pfund_plot.config import get_config
|
|
278
|
+
|
|
279
|
+
return not (
|
|
280
|
+
get_config().disable_widgets
|
|
281
|
+
or self._control is None
|
|
282
|
+
or not self._control.get("widgets", True)
|
|
283
|
+
)
|
|
284
|
+
|
|
275
285
|
def _create_widgets(self) -> None:
|
|
276
286
|
def _has_required_cols(WidgetClass: type[BaseWidget]) -> bool:
|
|
277
287
|
"""Check if the df has the columns required by the widget."""
|
|
@@ -280,13 +290,7 @@ class BasePlot:
|
|
|
280
290
|
return True
|
|
281
291
|
return all(col in self._df.columns for col in required)
|
|
282
292
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
if (
|
|
286
|
-
get_config().disable_widgets
|
|
287
|
-
or self._control is None
|
|
288
|
-
or not self._control.get("widgets", True)
|
|
289
|
-
):
|
|
293
|
+
if not self._widgets_enabled():
|
|
290
294
|
return
|
|
291
295
|
|
|
292
296
|
for WidgetClass in self._ChosenWidgetClasses:
|
|
@@ -1055,10 +1059,14 @@ class BasePlot:
|
|
|
1055
1059
|
self._plot = self._build_plot(df=self._df)
|
|
1056
1060
|
|
|
1057
1061
|
def _create_pane(self):
|
|
1062
|
+
# num_data is the initial value of the DatetimeRangeWidget slider, so it
|
|
1063
|
+
# only applies when widgets are active. With widgets disabled there is no
|
|
1064
|
+
# slider to reveal the rest of the data, so show the full df instead.
|
|
1058
1065
|
if (
|
|
1059
1066
|
self._df is not None
|
|
1060
1067
|
and self._control
|
|
1061
1068
|
and self._control.get("num_data") is not None
|
|
1069
|
+
and self._widgets_enabled()
|
|
1062
1070
|
):
|
|
1063
1071
|
df = self._df.tail(self._control["num_data"])
|
|
1064
1072
|
else:
|
|
@@ -173,4 +173,14 @@ def convert_to_lazy_plot(
|
|
|
173
173
|
except ImportError:
|
|
174
174
|
pass
|
|
175
175
|
|
|
176
|
+
# Panel Viewable (e.g. the LazyRow/LazyColumn produced by combining plots
|
|
177
|
+
# with + or |, or any raw Panel component)
|
|
178
|
+
try:
|
|
179
|
+
from panel.viewable import Viewable
|
|
180
|
+
|
|
181
|
+
if isinstance(obj, Viewable):
|
|
182
|
+
return plt.panel(obj)
|
|
183
|
+
except ImportError:
|
|
184
|
+
pass
|
|
185
|
+
|
|
176
186
|
return obj
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|