From 1d6d62e698f36accfd19d14f76c76885bec73a49 Mon Sep 17 00:00:00 2001 From: Mike Prosser Date: Fri, 13 Jun 2025 10:35:04 -0500 Subject: [PATCH 1/9] Add more samples, to make testing with multiple panels easier. --- examples/sample/sample_2.py | 17 +++++++++++++++++ examples/sample/sample_3.py | 17 +++++++++++++++++ examples/sample/sample_panel_2.py | 19 +++++++++++++++++++ examples/sample/sample_panel_3.py | 19 +++++++++++++++++++ 4 files changed, 72 insertions(+) create mode 100644 examples/sample/sample_2.py create mode 100644 examples/sample/sample_3.py create mode 100644 examples/sample/sample_panel_2.py create mode 100644 examples/sample/sample_panel_3.py diff --git a/examples/sample/sample_2.py b/examples/sample/sample_2.py new file mode 100644 index 0000000..fdaabc0 --- /dev/null +++ b/examples/sample/sample_2.py @@ -0,0 +1,17 @@ +"""This example demonstrates how to open/update a Streamlit application using nipanel package.""" + +import pathlib + +import nipanel + +script_path = pathlib.Path(__file__) +panel_script_path = str(script_path.with_name("sample_panel_2.py")) + +panel = nipanel.StreamlitPanel( + panel_id="sample_panel_2", + streamlit_script_path=panel_script_path, +) +panel.set_value("sample_string", "Hello, World! #2") +panel.set_value("sample_int", 42) + +print(f"Panel URL: {panel.panel_url}") diff --git a/examples/sample/sample_3.py b/examples/sample/sample_3.py new file mode 100644 index 0000000..839d5c7 --- /dev/null +++ b/examples/sample/sample_3.py @@ -0,0 +1,17 @@ +"""This example demonstrates how to open/update a Streamlit application using nipanel package.""" + +import pathlib + +import nipanel + +script_path = pathlib.Path(__file__) +panel_script_path = str(script_path.with_name("sample_panel_3.py")) + +panel = nipanel.StreamlitPanel( + panel_id="sample_panel_3", + streamlit_script_path=panel_script_path, +) +panel.set_value("sample_string", "Hello, World #3!") +panel.set_value("float_values", [1.1, 2.2, 3.3]) + +print(f"Panel URL: {panel.panel_url}") diff --git a/examples/sample/sample_panel_2.py b/examples/sample/sample_panel_2.py new file mode 100644 index 0000000..11eec94 --- /dev/null +++ b/examples/sample/sample_panel_2.py @@ -0,0 +1,19 @@ +"""Streamlit application script for displaying values using nipanel package.""" + +import streamlit as st + +import nipanel + +panel = nipanel.StreamlitPanelValueAccessor(panel_id="sample_panel_2") + +st.title("Sample Panel Two") + +col1, col2 = st.columns([0.4, 0.6]) + +with col1: + st.write("String") + st.write("Integer") + +with col2: + st.write(panel.get_value("sample_string")) + st.write(panel.get_value("sample_int")) diff --git a/examples/sample/sample_panel_3.py b/examples/sample/sample_panel_3.py new file mode 100644 index 0000000..2a896f9 --- /dev/null +++ b/examples/sample/sample_panel_3.py @@ -0,0 +1,19 @@ +"""Streamlit application script for displaying values using nipanel package.""" + +import streamlit as st + +import nipanel + +panel = nipanel.StreamlitPanelValueAccessor(panel_id="sample_panel_3") + +st.title("Sample Panel Three") + +col1, col2 = st.columns([0.4, 0.6]) + +with col1: + st.write("String") + st.write("List") + +with col2: + st.write(panel.get_value("sample_string")) + st.write(panel.get_value("float_values")) From 4c1483eea4964a3626d2bb2630c9051cc7d3ce38 Mon Sep 17 00:00:00 2001 From: Mike Prosser Date: Fri, 13 Jun 2025 16:20:10 -0500 Subject: [PATCH 2/9] use nipanel.initialize_panel() --- examples/sample/sample_panel_2.py | 2 +- examples/sample/sample_panel_3.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/sample/sample_panel_2.py b/examples/sample/sample_panel_2.py index 11eec94..f62ed7a 100644 --- a/examples/sample/sample_panel_2.py +++ b/examples/sample/sample_panel_2.py @@ -4,7 +4,7 @@ import nipanel -panel = nipanel.StreamlitPanelValueAccessor(panel_id="sample_panel_2") +panel = nipanel.initialize_panel() st.title("Sample Panel Two") diff --git a/examples/sample/sample_panel_3.py b/examples/sample/sample_panel_3.py index 2a896f9..cdf9d9b 100644 --- a/examples/sample/sample_panel_3.py +++ b/examples/sample/sample_panel_3.py @@ -4,7 +4,7 @@ import nipanel -panel = nipanel.StreamlitPanelValueAccessor(panel_id="sample_panel_3") +panel = nipanel.initialize_panel() st.title("Sample Panel Three") From 6f6c6836c6d5e70a316d68b4a1103a472b434fe4 Mon Sep 17 00:00:00 2001 From: Mike Prosser Date: Fri, 20 Jun 2025 10:29:26 -0500 Subject: [PATCH 3/9] all_types example (from placeholder) --- examples/all_types/README.md | 15 ++++++ examples/all_types/all_types.py | 23 ++++++++ examples/all_types/all_types_panel.py | 19 +++++++ examples/all_types/define_types.py | 55 +++++++++++++++++++ examples/placeholder.py | 58 --------------------- examples/sample/sample.py | 10 ++-- examples/sample/sample_2.py | 17 ------ examples/sample/sample_3.py | 17 ------ examples/sample/sample_panel_2.py | 19 ------- examples/sample/sample_panel_3.py | 19 ------- src/nipanel/__init__.py | 10 +++- src/nipanel/_streamlit_panel_initializer.py | 25 +++++++++ 12 files changed, 148 insertions(+), 139 deletions(-) create mode 100644 examples/all_types/README.md create mode 100644 examples/all_types/all_types.py create mode 100644 examples/all_types/all_types_panel.py create mode 100644 examples/all_types/define_types.py delete mode 100644 examples/placeholder.py delete mode 100644 examples/sample/sample_2.py delete mode 100644 examples/sample/sample_3.py delete mode 100644 examples/sample/sample_panel_2.py delete mode 100644 examples/sample/sample_panel_3.py diff --git a/examples/all_types/README.md b/examples/all_types/README.md new file mode 100644 index 0000000..46a09fa --- /dev/null +++ b/examples/all_types/README.md @@ -0,0 +1,15 @@ +## All Types Example + +This is a nipanel example that demonstrates all supported data types + +### Feature + +- Demonstrates support for all data types + +### Required Software + +- Python 3.9 or later + +### Usage + +Run `poetry run examples/all_types/all_types.py` \ No newline at end of file diff --git a/examples/all_types/all_types.py b/examples/all_types/all_types.py new file mode 100644 index 0000000..9b536d3 --- /dev/null +++ b/examples/all_types/all_types.py @@ -0,0 +1,23 @@ +"""example script for nipanel package demonstrating various data types.""" + +from pathlib import Path + +from define_types import all_types_with_values + +import nipanel + +panel_script_path = Path(__file__).with_name("all_types_panel.py") +panel = nipanel.create_panel(panel_script_path) + +print("Setting values") +for name, value in all_types_with_values.items(): + print(f"{name:>15} {value}") + panel.set_value(name, value) + +print() +print("Getting values") +for name in all_types_with_values.keys(): + the_value = panel.get_value(name) + print(f"{name:>20} {the_value}") + +print(f"Panel URL: {panel.panel_url}") diff --git a/examples/all_types/all_types_panel.py b/examples/all_types/all_types_panel.py new file mode 100644 index 0000000..d24ec05 --- /dev/null +++ b/examples/all_types/all_types_panel.py @@ -0,0 +1,19 @@ +"""A Streamlit panel to demonstrate various types and their values.""" + +import streamlit as st +from define_types import all_types_with_values + +import nipanel + +panel = nipanel.initialize_panel() + +st.title("All Types") + +for name in all_types_with_values.keys(): + col1, col2 = st.columns([0.4, 0.6]) + + with col1: + st.write(name) + + with col2: + st.write(panel.get_value(name)) diff --git a/examples/all_types/define_types.py b/examples/all_types/define_types.py new file mode 100644 index 0000000..5a6139d --- /dev/null +++ b/examples/all_types/define_types.py @@ -0,0 +1,55 @@ +"""Define types.""" + +import enum + + +class MyIntFlags(enum.IntFlag): + """Example of an IntFlag enum.""" + + VALUE1 = 1 + VALUE2 = 2 + VALUE4 = 4 + + +class MyIntEnum(enum.IntEnum): + """Example of an IntEnum enum.""" + + VALUE10 = 10 + VALUE20 = 20 + VALUE30 = 30 + + +class MyStrEnum(str, enum.Enum): + """Example of a mixin string enum.""" + + VALUE1 = "value1" + VALUE2 = "value2" + VALUE3 = "value3" + + +all_types_with_values = { + # supported scalar types + "bool_scalar": True, + "bytes_scalar": b"robotext", + "float_scalar": 13.12, + "int_scalar": 42, + "str_scalar": "sample string", + # supported collection types + "bool_collection": [True, False, True], + "bytes_collection": [b"one", b"two", b"three"], + "float_collection": [1.1, 2.2, 3.3], + "int_collection": [1, 2, 3], + "str_collection": ["one", "two", "three"], + # supported enum and flag types + "intflags_scalar": MyIntFlags.VALUE1 | MyIntFlags.VALUE4, + "intenum_scalar": MyIntEnum.VALUE20, + "strenum_scalar": MyStrEnum.VALUE3, + "intflags_collection": [MyIntFlags.VALUE1, MyIntFlags.VALUE2, MyIntFlags.VALUE4], + "intenum_collection": [MyIntEnum.VALUE10, MyIntEnum.VALUE20, MyIntEnum.VALUE30], + "strenum_collection": [MyStrEnum.VALUE1, MyStrEnum.VALUE2, MyStrEnum.VALUE3], + # supported collections + "list": [1, 2, 3], + "tuple": (4, 5, 6), + "set": {7, 8, 9}, + "frozenset": frozenset([10, 11, 12]), +} diff --git a/examples/placeholder.py b/examples/placeholder.py deleted file mode 100644 index aa1c745..0000000 --- a/examples/placeholder.py +++ /dev/null @@ -1,58 +0,0 @@ -"""Placeholder example for the package.""" - -import enum - -import nipanel - - -class MyIntFlags(enum.IntFlag): - """Example of an IntFlag enum.""" - - VALUE1 = 1 - VALUE2 = 2 - VALUE4 = 4 - - -class MyIntEnum(enum.IntEnum): - """Example of an IntEnum enum.""" - - VALUE10 = 10 - VALUE20 = 20 - VALUE30 = 30 - - -class MyStrEnum(str, enum.Enum): - """Example of a mixin string enum.""" - - VALUE1 = "value1" - VALUE2 = "value2" - VALUE3 = "value3" - - -if __name__ == "__main__": - my_panel = nipanel.StreamlitPanel( - panel_id="placeholder", - streamlit_script_path=__file__, - ) - - my_types = { - "my_str": "im justa smol str", - "my_int": 42, - "my_float": 13.12, - "my_bool": True, - "my_bytes": b"robotext", - "my_intflags": MyIntFlags.VALUE1 | MyIntFlags.VALUE4, - "my_intenum": MyIntEnum.VALUE20, - "my_strenum": MyStrEnum.VALUE3, - } - - print("Setting values") - for name, value in my_types.items(): - print(f"{name:>15} {value}") - my_panel.set_value(name, value) - - print() - print("Getting values") - for name in my_types.keys(): - the_value = my_panel.get_value(name) - print(f"{name:>15} {the_value}") diff --git a/examples/sample/sample.py b/examples/sample/sample.py index 09977e4..bcb9030 100644 --- a/examples/sample/sample.py +++ b/examples/sample/sample.py @@ -1,16 +1,12 @@ """This example demonstrates how to open/update a Streamlit application using nipanel package.""" -import pathlib +from pathlib import Path import nipanel -script_path = pathlib.Path(__file__) -panel_script_path = str(script_path.with_name("sample_panel.py")) +panel_script_path = Path(__file__).with_name("sample_panel.py") +panel = nipanel.create_panel(panel_script_path) -panel = nipanel.StreamlitPanel( - panel_id="sample_panel", - streamlit_script_path=panel_script_path, -) panel.set_value("sample_string", "Hello, World!") panel.set_value("sample_int", 42) panel.set_value("sample_float", 3.14) diff --git a/examples/sample/sample_2.py b/examples/sample/sample_2.py deleted file mode 100644 index fdaabc0..0000000 --- a/examples/sample/sample_2.py +++ /dev/null @@ -1,17 +0,0 @@ -"""This example demonstrates how to open/update a Streamlit application using nipanel package.""" - -import pathlib - -import nipanel - -script_path = pathlib.Path(__file__) -panel_script_path = str(script_path.with_name("sample_panel_2.py")) - -panel = nipanel.StreamlitPanel( - panel_id="sample_panel_2", - streamlit_script_path=panel_script_path, -) -panel.set_value("sample_string", "Hello, World! #2") -panel.set_value("sample_int", 42) - -print(f"Panel URL: {panel.panel_url}") diff --git a/examples/sample/sample_3.py b/examples/sample/sample_3.py deleted file mode 100644 index 839d5c7..0000000 --- a/examples/sample/sample_3.py +++ /dev/null @@ -1,17 +0,0 @@ -"""This example demonstrates how to open/update a Streamlit application using nipanel package.""" - -import pathlib - -import nipanel - -script_path = pathlib.Path(__file__) -panel_script_path = str(script_path.with_name("sample_panel_3.py")) - -panel = nipanel.StreamlitPanel( - panel_id="sample_panel_3", - streamlit_script_path=panel_script_path, -) -panel.set_value("sample_string", "Hello, World #3!") -panel.set_value("float_values", [1.1, 2.2, 3.3]) - -print(f"Panel URL: {panel.panel_url}") diff --git a/examples/sample/sample_panel_2.py b/examples/sample/sample_panel_2.py deleted file mode 100644 index f62ed7a..0000000 --- a/examples/sample/sample_panel_2.py +++ /dev/null @@ -1,19 +0,0 @@ -"""Streamlit application script for displaying values using nipanel package.""" - -import streamlit as st - -import nipanel - -panel = nipanel.initialize_panel() - -st.title("Sample Panel Two") - -col1, col2 = st.columns([0.4, 0.6]) - -with col1: - st.write("String") - st.write("Integer") - -with col2: - st.write(panel.get_value("sample_string")) - st.write(panel.get_value("sample_int")) diff --git a/examples/sample/sample_panel_3.py b/examples/sample/sample_panel_3.py deleted file mode 100644 index cdf9d9b..0000000 --- a/examples/sample/sample_panel_3.py +++ /dev/null @@ -1,19 +0,0 @@ -"""Streamlit application script for displaying values using nipanel package.""" - -import streamlit as st - -import nipanel - -panel = nipanel.initialize_panel() - -st.title("Sample Panel Three") - -col1, col2 = st.columns([0.4, 0.6]) - -with col1: - st.write("String") - st.write("List") - -with col2: - st.write(panel.get_value("sample_string")) - st.write(panel.get_value("float_values")) diff --git a/src/nipanel/__init__.py b/src/nipanel/__init__.py index d79c161..89d1ba9 100644 --- a/src/nipanel/__init__.py +++ b/src/nipanel/__init__.py @@ -4,10 +4,16 @@ from nipanel._panel import Panel from nipanel._streamlit_panel import StreamlitPanel -from nipanel._streamlit_panel_initializer import initialize_panel +from nipanel._streamlit_panel_initializer import create_panel, initialize_panel from nipanel._streamlit_panel_value_accessor import StreamlitPanelValueAccessor -__all__ = ["Panel", "StreamlitPanel", "StreamlitPanelValueAccessor", "initialize_panel"] +__all__ = [ + "create_panel", + "initialize_panel", + "Panel", + "StreamlitPanel", + "StreamlitPanelValueAccessor", +] # Hide that it was defined in a helper file Panel.__module__ = __name__ diff --git a/src/nipanel/_streamlit_panel_initializer.py b/src/nipanel/_streamlit_panel_initializer.py index 6932ebf..4c1199c 100644 --- a/src/nipanel/_streamlit_panel_initializer.py +++ b/src/nipanel/_streamlit_panel_initializer.py @@ -1,13 +1,38 @@ +from pathlib import Path from typing import cast import streamlit as st +from nipanel._streamlit_panel import StreamlitPanel from nipanel._streamlit_panel_value_accessor import StreamlitPanelValueAccessor from nipanel.streamlit_refresh import initialize_refresh_component PANEL_ACCESSOR_KEY = "StreamlitPanelValueAccessor" +def create_panel(streamlit_script_path: Path) -> StreamlitPanel: + """Create a Streamlit panel with the specified script path. + + This function initializes a Streamlit panel using the provided script path. + The panel ID will be derived from the script path, which is expected to be a valid Streamlit script. + It is typically used to create a new panel instance for use in a Streamlit application. + + Args: + streamlit_script_path: The file path of the Streamlit script to be used for the panel. + + Returns: + A StreamlitPanel instance initialized with the given panel ID. + """ + path_str = str(streamlit_script_path) + if not path_str.endswith(".py"): + raise ValueError( + "The provided script path must be a valid Streamlit script ending with '.py'." + ) + + panel_id = path_str.replace("\\", "/").split("/")[-1].replace(".py", "") + return StreamlitPanel(panel_id, path_str) + + def initialize_panel() -> StreamlitPanelValueAccessor: """Initialize and return the Streamlit panel value accessor. From d3a1df8fe0bbeb2b549494fa203d7d0a29b021f5 Mon Sep 17 00:00:00 2001 From: Mike Prosser Date: Mon, 23 Jun 2025 10:33:03 -0500 Subject: [PATCH 4/9] add nitypes to all_types, and update comments --- examples/all_types/README.md | 2 +- examples/all_types/all_types.py | 2 +- examples/all_types/all_types_panel.py | 2 +- examples/all_types/define_types.py | 23 ++++++++++++++------- src/nipanel/_streamlit_panel_initializer.py | 12 +++++++---- 5 files changed, 26 insertions(+), 15 deletions(-) diff --git a/examples/all_types/README.md b/examples/all_types/README.md index 46a09fa..c23a42b 100644 --- a/examples/all_types/README.md +++ b/examples/all_types/README.md @@ -1,6 +1,6 @@ ## All Types Example -This is a nipanel example that demonstrates all supported data types +This is an example for `nipanel` that demonstrates all supported data types ### Feature diff --git a/examples/all_types/all_types.py b/examples/all_types/all_types.py index 9b536d3..8162b6e 100644 --- a/examples/all_types/all_types.py +++ b/examples/all_types/all_types.py @@ -1,4 +1,4 @@ -"""example script for nipanel package demonstrating various data types.""" +"""An example that demonstrates the supported data types for nipanel scripts.""" from pathlib import Path diff --git a/examples/all_types/all_types_panel.py b/examples/all_types/all_types_panel.py index d24ec05..7c2cf0d 100644 --- a/examples/all_types/all_types_panel.py +++ b/examples/all_types/all_types_panel.py @@ -1,4 +1,4 @@ -"""A Streamlit panel to demonstrate various types and their values.""" +"""A Streamlit visualization panel for the all_types.py example script.""" import streamlit as st from define_types import all_types_with_values diff --git a/examples/all_types/define_types.py b/examples/all_types/define_types.py index 5a6139d..5eab8ec 100644 --- a/examples/all_types/define_types.py +++ b/examples/all_types/define_types.py @@ -2,6 +2,10 @@ import enum +import numpy as np +from nitypes.scalar import Scalar +from nitypes.waveform import AnalogWaveform + class MyIntFlags(enum.IntFlag): """Example of an IntFlag enum.""" @@ -29,11 +33,11 @@ class MyStrEnum(str, enum.Enum): all_types_with_values = { # supported scalar types - "bool_scalar": True, - "bytes_scalar": b"robotext", - "float_scalar": 13.12, - "int_scalar": 42, - "str_scalar": "sample string", + "bool": True, + "bytes": b"robotext", + "float": 13.12, + "int": 42, + "str": "sample string", # supported collection types "bool_collection": [True, False, True], "bytes_collection": [b"one", b"two", b"three"], @@ -41,9 +45,9 @@ class MyStrEnum(str, enum.Enum): "int_collection": [1, 2, 3], "str_collection": ["one", "two", "three"], # supported enum and flag types - "intflags_scalar": MyIntFlags.VALUE1 | MyIntFlags.VALUE4, - "intenum_scalar": MyIntEnum.VALUE20, - "strenum_scalar": MyStrEnum.VALUE3, + "intflags": MyIntFlags.VALUE1 | MyIntFlags.VALUE4, + "intenum": MyIntEnum.VALUE20, + "strenum": MyStrEnum.VALUE3, "intflags_collection": [MyIntFlags.VALUE1, MyIntFlags.VALUE2, MyIntFlags.VALUE4], "intenum_collection": [MyIntEnum.VALUE10, MyIntEnum.VALUE20, MyIntEnum.VALUE30], "strenum_collection": [MyStrEnum.VALUE1, MyStrEnum.VALUE2, MyStrEnum.VALUE3], @@ -52,4 +56,7 @@ class MyStrEnum(str, enum.Enum): "tuple": (4, 5, 6), "set": {7, 8, 9}, "frozenset": frozenset([10, 11, 12]), + # NI types + "nitypes_Scalar": Scalar(42, "m"), + "nitypes_AnalogWaveform": AnalogWaveform.from_array_1d(np.array([1.0, 2.0, 3.0])), } diff --git a/src/nipanel/_streamlit_panel_initializer.py b/src/nipanel/_streamlit_panel_initializer.py index 4c1199c..3172adc 100644 --- a/src/nipanel/_streamlit_panel_initializer.py +++ b/src/nipanel/_streamlit_panel_initializer.py @@ -13,9 +13,13 @@ def create_panel(streamlit_script_path: Path) -> StreamlitPanel: """Create a Streamlit panel with the specified script path. - This function initializes a Streamlit panel using the provided script path. - The panel ID will be derived from the script path, which is expected to be a valid Streamlit script. - It is typically used to create a new panel instance for use in a Streamlit application. + This function initializes a Streamlit panel using the provided script path. It derives the panel + ID from the script's path, which it expects to be a valid Streamlit script. For example, if the + value for streamlit_script_path is "c:/example/some_example.py", then the panel's ID becomes + "some_example". + + Use this function when you want to create a new panel instance to use in a Streamlit + application. Args: streamlit_script_path: The file path of the Streamlit script to be used for the panel. @@ -29,7 +33,7 @@ def create_panel(streamlit_script_path: Path) -> StreamlitPanel: "The provided script path must be a valid Streamlit script ending with '.py'." ) - panel_id = path_str.replace("\\", "/").split("/")[-1].replace(".py", "") + panel_id = streamlit_script_path.stem return StreamlitPanel(panel_id, path_str) From 9526a40fd577caa4b5b482dc10f1d885580ae300 Mon Sep 17 00:00:00 2001 From: Mike Prosser Date: Mon, 23 Jun 2025 12:40:45 -0500 Subject: [PATCH 5/9] added simple graph example --- examples/simple_graph/README.md | 18 + examples/simple_graph/simple_graph.py | 38 +++ examples/simple_graph/simple_graph_panel.py | 59 ++++ poetry.lock | 345 +++++++++++++++----- pyproject.toml | 1 + 5 files changed, 381 insertions(+), 80 deletions(-) create mode 100644 examples/simple_graph/README.md create mode 100644 examples/simple_graph/simple_graph.py create mode 100644 examples/simple_graph/simple_graph_panel.py diff --git a/examples/simple_graph/README.md b/examples/simple_graph/README.md new file mode 100644 index 0000000..d7a9427 --- /dev/null +++ b/examples/simple_graph/README.md @@ -0,0 +1,18 @@ +# Simple Graph Example + +This example demonstrates using nipanel with Streamlit to display a dynamic sine wave using the `streamlit-echarts` library. + +## Features + +- Generates sine wave data with varying frequency +- Displays the data in an interactive chart using ECharts +- Updates automatically every 1 second +- Shows statistics about the displayed data + +### Required Software + +- Python 3.9 or later + +### Usage + +Run `poetry run examples/simple_graph/simple_graph.py` diff --git a/examples/simple_graph/simple_graph.py b/examples/simple_graph/simple_graph.py new file mode 100644 index 0000000..ab79929 --- /dev/null +++ b/examples/simple_graph/simple_graph.py @@ -0,0 +1,38 @@ +"""Example of using nipanel to display a sine wave graph using st_echarts.""" + +import math +import time +from pathlib import Path + +import numpy as np + +import nipanel + + +panel_script_path = Path(__file__).with_name("simple_graph_panel.py") +panel = nipanel.create_panel(panel_script_path) + +amplitude = 1.0 +frequency = 1.0 +num_points = 100 + +try: + print(f"Panel URL: {panel.panel_url}") + print("Press Ctrl+C to exit") + + # Generate and update the sine wave data periodically + while True: + time_points = np.linspace(0, num_points, num_points) + sine_values = amplitude * np.sin(frequency * time_points) + + panel.set_value("time_points", time_points.tolist()) + panel.set_value("sine_values", sine_values.tolist()) + panel.set_value("amplitude", amplitude) + panel.set_value("frequency", frequency) + + # Slowly vary the frequency for a more dynamic visualization + frequency = 1.0 + 0.5 * math.sin(time.time() / 5.0) + time.sleep(1) + +except KeyboardInterrupt: + print("Exiting...") diff --git a/examples/simple_graph/simple_graph_panel.py b/examples/simple_graph/simple_graph_panel.py new file mode 100644 index 0000000..5402493 --- /dev/null +++ b/examples/simple_graph/simple_graph_panel.py @@ -0,0 +1,59 @@ +"""Example of displaying a sine wave using streamlit-echarts in a nipanel.""" + +import streamlit as st +from streamlit_echarts import st_echarts + +from nipanel import initialize_panel + + +st.set_page_config(page_title="Simple Graph Example", page_icon="📈", layout="wide") +st.title("Simple Sine Wave Visualization") + +panel = initialize_panel() +time_points = panel.get_value("time_points", [0.0]) +sine_values = panel.get_value("sine_values", [0.0]) +amplitude = panel.get_value("amplitude", 1.0) +frequency = panel.get_value("frequency", 1.0) + +col1, col2, col3, col4, col5 = st.columns(5) +with col1: + st.metric("Amplitude", f"{amplitude:.2f}") +with col2: + st.metric("Frequency", f"{frequency:.2f} Hz") +with col3: + st.metric("Min Value", f"{min(sine_values):.3f}") +with col4: + st.metric("Max Value", f"{max(sine_values):.3f}") +with col5: + st.metric("Data Points", len(sine_values)) + +# Prepare data for echarts +data = [{"value": [x, y]} for x, y in zip(time_points, sine_values)] + +# Configure the chart options +options = { + "animation": False, # Disable animation for smoother updates + "title": {"text": "Sine Wave"}, + "tooltip": {"trigger": "axis"}, + "xAxis": {"type": "value", "name": "Time (s)", "nameLocation": "middle", "nameGap": 30}, + "yAxis": { + "type": "value", + "name": "Amplitude", + "nameLocation": "middle", + "nameGap": 30, + }, + "series": [ + { + "data": data, + "type": "line", + "showSymbol": True, + "smooth": True, + "lineStyle": {"width": 2, "color": "#1f77b4"}, + "areaStyle": {"color": "#1f77b4", "opacity": 0.3}, + "name": "Sine Wave", + } + ], +} + +# Display the chart +st_echarts(options=options, height="400px") diff --git a/poetry.lock b/poetry.lock index fd8e33d..e903238 100644 --- a/poetry.lock +++ b/poetry.lock @@ -166,13 +166,13 @@ files = [ [[package]] name = "cachetools" -version = "5.5.2" +version = "6.1.0" description = "Extensible memoizing collections and decorators" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a"}, - {file = "cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4"}, + {file = "cachetools-6.1.0-py3-none-any.whl", hash = "sha256:1c7bb3cf9193deaf3508b7c5f2a79986c13ea38965c5adcff1f84519cf39163e"}, + {file = "cachetools-6.1.0.tar.gz", hash = "sha256:b4c4f404392848db3ce7aac34950d17be4d864da4b8b66911008e430bc544587"}, ] [[package]] @@ -559,13 +559,13 @@ pydocstyle = ">=2.1" [[package]] name = "flake8-import-order" -version = "0.19.0" +version = "0.19.1" description = "Flake8 and pylama plugin that checks the ordering of import statements." optional = false python-versions = "*" files = [ - {file = "flake8_import_order-0.19.0-py3-none-any.whl", hash = "sha256:94f5293d575c39acd62eb5d911f3e54d347feeb664e5ff148d7a73ae2b17bbba"}, - {file = "flake8_import_order-0.19.0.tar.gz", hash = "sha256:4209620e63d3c6f4241ab7b0ebd4cdd29299edb96f145ebe95d3911910037fa3"}, + {file = "flake8_import_order-0.19.1-py3-none-any.whl", hash = "sha256:8235d8cba5bead8e119dc129b7286df2d92046ceebbd48fc18394abe57c5f467"}, + {file = "flake8_import_order-0.19.1.tar.gz", hash = "sha256:e071477eb9aaddbb75d30543cec0f83e1858502990d82bd8262f5a7575527fd0"}, ] [package.dependencies] @@ -1224,13 +1224,13 @@ types-protobuf = ">=4.24" [[package]] name = "narwhals" -version = "1.42.1" +version = "1.44.0" description = "Extremely lightweight compatibility layer between dataframe libraries" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "narwhals-1.42.1-py3-none-any.whl", hash = "sha256:7a270d44b94ccdb277a799ae890c42e8504c537c1849f195eb14717c6184977a"}, - {file = "narwhals-1.42.1.tar.gz", hash = "sha256:50a5635b11aeda98cf9c37e839fd34b0a24159f59a4dfae930290ad698320494"}, + {file = "narwhals-1.44.0-py3-none-any.whl", hash = "sha256:a170ea0bab4cf1f323d9f8bf17f2d7042c3d73802bea321996b39bf075d57de5"}, + {file = "narwhals-1.44.0.tar.gz", hash = "sha256:8cf0616d4f6f21225b3b56fcde96ccab6d05023561a0f162402aa9b8c33ad31d"}, ] [package.extras] @@ -1239,7 +1239,7 @@ dask = ["dask[dataframe] (>=2024.8)"] duckdb = ["duckdb (>=1.0)"] ibis = ["ibis-framework (>=6.0.0)", "packaging", "pyarrow-hotfix", "rich"] modin = ["modin"] -pandas = ["pandas (>=0.25.3)"] +pandas = ["pandas (>=1.1.3)"] polars = ["polars (>=0.20.3)"] pyarrow = ["pyarrow (>=11.0.0)"] pyspark = ["pyspark (>=3.5.0)"] @@ -1445,73 +1445,73 @@ files = [ [[package]] name = "numpy" -version = "2.3.0" +version = "2.3.1" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.11" files = [ - {file = "numpy-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c3c9fdde0fa18afa1099d6257eb82890ea4f3102847e692193b54e00312a9ae9"}, - {file = "numpy-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46d16f72c2192da7b83984aa5455baee640e33a9f1e61e656f29adf55e406c2b"}, - {file = "numpy-2.3.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a0be278be9307c4ab06b788f2a077f05e180aea817b3e41cebbd5aaf7bd85ed3"}, - {file = "numpy-2.3.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:99224862d1412d2562248d4710126355d3a8db7672170a39d6909ac47687a8a4"}, - {file = "numpy-2.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2393a914db64b0ead0ab80c962e42d09d5f385802006a6c87835acb1f58adb96"}, - {file = "numpy-2.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:7729c8008d55e80784bd113787ce876ca117185c579c0d626f59b87d433ea779"}, - {file = "numpy-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:06d4fb37a8d383b769281714897420c5cc3545c79dc427df57fc9b852ee0bf58"}, - {file = "numpy-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c39ec392b5db5088259c68250e342612db82dc80ce044cf16496cf14cf6bc6f8"}, - {file = "numpy-2.3.0-cp311-cp311-win32.whl", hash = "sha256:ee9d3ee70d62827bc91f3ea5eee33153212c41f639918550ac0475e3588da59f"}, - {file = "numpy-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:43c55b6a860b0eb44d42341438b03513cf3879cb3617afb749ad49307e164edd"}, - {file = "numpy-2.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:2e6a1409eee0cb0316cb64640a49a49ca44deb1a537e6b1121dc7c458a1299a8"}, - {file = "numpy-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:389b85335838155a9076e9ad7f8fdba0827496ec2d2dc32ce69ce7898bde03ba"}, - {file = "numpy-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9498f60cd6bb8238d8eaf468a3d5bb031d34cd12556af53510f05fcf581c1b7e"}, - {file = "numpy-2.3.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:622a65d40d8eb427d8e722fd410ac3ad4958002f109230bc714fa551044ebae2"}, - {file = "numpy-2.3.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:b9446d9d8505aadadb686d51d838f2b6688c9e85636a0c3abaeb55ed54756459"}, - {file = "numpy-2.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:50080245365d75137a2bf46151e975de63146ae6d79f7e6bd5c0e85c9931d06a"}, - {file = "numpy-2.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:c24bb4113c66936eeaa0dc1e47c74770453d34f46ee07ae4efd853a2ed1ad10a"}, - {file = "numpy-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4d8d294287fdf685281e671886c6dcdf0291a7c19db3e5cb4178d07ccf6ecc67"}, - {file = "numpy-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6295f81f093b7f5769d1728a6bd8bf7466de2adfa771ede944ce6711382b89dc"}, - {file = "numpy-2.3.0-cp312-cp312-win32.whl", hash = "sha256:e6648078bdd974ef5d15cecc31b0c410e2e24178a6e10bf511e0557eed0f2570"}, - {file = "numpy-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:0898c67a58cdaaf29994bc0e2c65230fd4de0ac40afaf1584ed0b02cd74c6fdd"}, - {file = "numpy-2.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:bd8df082b6c4695753ad6193018c05aac465d634834dca47a3ae06d4bb22d9ea"}, - {file = "numpy-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5754ab5595bfa2c2387d241296e0381c21f44a4b90a776c3c1d39eede13a746a"}, - {file = "numpy-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d11fa02f77752d8099573d64e5fe33de3229b6632036ec08f7080f46b6649959"}, - {file = "numpy-2.3.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:aba48d17e87688a765ab1cd557882052f238e2f36545dfa8e29e6a91aef77afe"}, - {file = "numpy-2.3.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4dc58865623023b63b10d52f18abaac3729346a7a46a778381e0e3af4b7f3beb"}, - {file = "numpy-2.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:df470d376f54e052c76517393fa443758fefcdd634645bc9c1f84eafc67087f0"}, - {file = "numpy-2.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:87717eb24d4a8a64683b7a4e91ace04e2f5c7c77872f823f02a94feee186168f"}, - {file = "numpy-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d8fa264d56882b59dcb5ea4d6ab6f31d0c58a57b41aec605848b6eb2ef4a43e8"}, - {file = "numpy-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e651756066a0eaf900916497e20e02fe1ae544187cb0fe88de981671ee7f6270"}, - {file = "numpy-2.3.0-cp313-cp313-win32.whl", hash = "sha256:e43c3cce3b6ae5f94696669ff2a6eafd9a6b9332008bafa4117af70f4b88be6f"}, - {file = "numpy-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:81ae0bf2564cf475f94be4a27ef7bcf8af0c3e28da46770fc904da9abd5279b5"}, - {file = "numpy-2.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:c8738baa52505fa6e82778580b23f945e3578412554d937093eac9205e845e6e"}, - {file = "numpy-2.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:39b27d8b38942a647f048b675f134dd5a567f95bfff481f9109ec308515c51d8"}, - {file = "numpy-2.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0eba4a1ea88f9a6f30f56fdafdeb8da3774349eacddab9581a21234b8535d3d3"}, - {file = "numpy-2.3.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:b0f1f11d0a1da54927436505a5a7670b154eac27f5672afc389661013dfe3d4f"}, - {file = "numpy-2.3.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:690d0a5b60a47e1f9dcec7b77750a4854c0d690e9058b7bef3106e3ae9117808"}, - {file = "numpy-2.3.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:8b51ead2b258284458e570942137155978583e407babc22e3d0ed7af33ce06f8"}, - {file = "numpy-2.3.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:aaf81c7b82c73bd9b45e79cfb9476cb9c29e937494bfe9092c26aece812818ad"}, - {file = "numpy-2.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f420033a20b4f6a2a11f585f93c843ac40686a7c3fa514060a97d9de93e5e72b"}, - {file = "numpy-2.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d344ca32ab482bcf8735d8f95091ad081f97120546f3d250240868430ce52555"}, - {file = "numpy-2.3.0-cp313-cp313t-win32.whl", hash = "sha256:48a2e8eaf76364c32a1feaa60d6925eaf32ed7a040183b807e02674305beef61"}, - {file = "numpy-2.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ba17f93a94e503551f154de210e4d50c5e3ee20f7e7a1b5f6ce3f22d419b93bb"}, - {file = "numpy-2.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:f14e016d9409680959691c109be98c436c6249eaf7f118b424679793607b5944"}, - {file = "numpy-2.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:80b46117c7359de8167cc00a2c7d823bdd505e8c7727ae0871025a86d668283b"}, - {file = "numpy-2.3.0-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:5814a0f43e70c061f47abd5857d120179609ddc32a613138cbb6c4e9e2dbdda5"}, - {file = "numpy-2.3.0-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:ef6c1e88fd6b81ac6d215ed71dc8cd027e54d4bf1d2682d362449097156267a2"}, - {file = "numpy-2.3.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:33a5a12a45bb82d9997e2c0b12adae97507ad7c347546190a18ff14c28bbca12"}, - {file = "numpy-2.3.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:54dfc8681c1906d239e95ab1508d0a533c4a9505e52ee2d71a5472b04437ef97"}, - {file = "numpy-2.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:e017a8a251ff4d18d71f139e28bdc7c31edba7a507f72b1414ed902cbe48c74d"}, - {file = "numpy-2.3.0.tar.gz", hash = "sha256:581f87f9e9e9db2cba2141400e160e9dd644ee248788d6f90636eeb8fd9260a6"}, + {file = "numpy-2.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6ea9e48336a402551f52cd8f593343699003d2353daa4b72ce8d34f66b722070"}, + {file = "numpy-2.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ccb7336eaf0e77c1635b232c141846493a588ec9ea777a7c24d7166bb8533ae"}, + {file = "numpy-2.3.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:0bb3a4a61e1d327e035275d2a993c96fa786e4913aa089843e6a2d9dd205c66a"}, + {file = "numpy-2.3.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:e344eb79dab01f1e838ebb67aab09965fb271d6da6b00adda26328ac27d4a66e"}, + {file = "numpy-2.3.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:467db865b392168ceb1ef1ffa6f5a86e62468c43e0cfb4ab6da667ede10e58db"}, + {file = "numpy-2.3.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:afed2ce4a84f6b0fc6c1ce734ff368cbf5a5e24e8954a338f3bdffa0718adffb"}, + {file = "numpy-2.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0025048b3c1557a20bc80d06fdeb8cc7fc193721484cca82b2cfa072fec71a93"}, + {file = "numpy-2.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5ee121b60aa509679b682819c602579e1df14a5b07fe95671c8849aad8f2115"}, + {file = "numpy-2.3.1-cp311-cp311-win32.whl", hash = "sha256:a8b740f5579ae4585831b3cf0e3b0425c667274f82a484866d2adf9570539369"}, + {file = "numpy-2.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:d4580adadc53311b163444f877e0789f1c8861e2698f6b2a4ca852fda154f3ff"}, + {file = "numpy-2.3.1-cp311-cp311-win_arm64.whl", hash = "sha256:ec0bdafa906f95adc9a0c6f26a4871fa753f25caaa0e032578a30457bff0af6a"}, + {file = "numpy-2.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2959d8f268f3d8ee402b04a9ec4bb7604555aeacf78b360dc4ec27f1d508177d"}, + {file = "numpy-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:762e0c0c6b56bdedfef9a8e1d4538556438288c4276901ea008ae44091954e29"}, + {file = "numpy-2.3.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:867ef172a0976aaa1f1d1b63cf2090de8b636a7674607d514505fb7276ab08fc"}, + {file = "numpy-2.3.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:4e602e1b8682c2b833af89ba641ad4176053aaa50f5cacda1a27004352dde943"}, + {file = "numpy-2.3.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8e333040d069eba1652fb08962ec5b76af7f2c7bce1df7e1418c8055cf776f25"}, + {file = "numpy-2.3.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e7cbf5a5eafd8d230a3ce356d892512185230e4781a361229bd902ff403bc660"}, + {file = "numpy-2.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5f1b8f26d1086835f442286c1d9b64bb3974b0b1e41bb105358fd07d20872952"}, + {file = "numpy-2.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ee8340cb48c9b7a5899d1149eece41ca535513a9698098edbade2a8e7a84da77"}, + {file = "numpy-2.3.1-cp312-cp312-win32.whl", hash = "sha256:e772dda20a6002ef7061713dc1e2585bc1b534e7909b2030b5a46dae8ff077ab"}, + {file = "numpy-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:cfecc7822543abdea6de08758091da655ea2210b8ffa1faf116b940693d3df76"}, + {file = "numpy-2.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:7be91b2239af2658653c5bb6f1b8bccafaf08226a258caf78ce44710a0160d30"}, + {file = "numpy-2.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:25a1992b0a3fdcdaec9f552ef10d8103186f5397ab45e2d25f8ac51b1a6b97e8"}, + {file = "numpy-2.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7dea630156d39b02a63c18f508f85010230409db5b2927ba59c8ba4ab3e8272e"}, + {file = "numpy-2.3.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:bada6058dd886061f10ea15f230ccf7dfff40572e99fef440a4a857c8728c9c0"}, + {file = "numpy-2.3.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:a894f3816eb17b29e4783e5873f92faf55b710c2519e5c351767c51f79d8526d"}, + {file = "numpy-2.3.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:18703df6c4a4fee55fd3d6e5a253d01c5d33a295409b03fda0c86b3ca2ff41a1"}, + {file = "numpy-2.3.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:5902660491bd7a48b2ec16c23ccb9124b8abfd9583c5fdfa123fe6b421e03de1"}, + {file = "numpy-2.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:36890eb9e9d2081137bd78d29050ba63b8dab95dff7912eadf1185e80074b2a0"}, + {file = "numpy-2.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a780033466159c2270531e2b8ac063704592a0bc62ec4a1b991c7c40705eb0e8"}, + {file = "numpy-2.3.1-cp313-cp313-win32.whl", hash = "sha256:39bff12c076812595c3a306f22bfe49919c5513aa1e0e70fac756a0be7c2a2b8"}, + {file = "numpy-2.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d5ee6eec45f08ce507a6570e06f2f879b374a552087a4179ea7838edbcbfa42"}, + {file = "numpy-2.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:0c4d9e0a8368db90f93bd192bfa771ace63137c3488d198ee21dfb8e7771916e"}, + {file = "numpy-2.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:b0b5397374f32ec0649dd98c652a1798192042e715df918c20672c62fb52d4b8"}, + {file = "numpy-2.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c5bdf2015ccfcee8253fb8be695516ac4457c743473a43290fd36eba6a1777eb"}, + {file = "numpy-2.3.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d70f20df7f08b90a2062c1f07737dd340adccf2068d0f1b9b3d56e2038979fee"}, + {file = "numpy-2.3.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:2fb86b7e58f9ac50e1e9dd1290154107e47d1eef23a0ae9145ded06ea606f992"}, + {file = "numpy-2.3.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:23ab05b2d241f76cb883ce8b9a93a680752fbfcbd51c50eff0b88b979e471d8c"}, + {file = "numpy-2.3.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:ce2ce9e5de4703a673e705183f64fd5da5bf36e7beddcb63a25ee2286e71ca48"}, + {file = "numpy-2.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c4913079974eeb5c16ccfd2b1f09354b8fed7e0d6f2cab933104a09a6419b1ee"}, + {file = "numpy-2.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:010ce9b4f00d5c036053ca684c77441f2f2c934fd23bee058b4d6f196efd8280"}, + {file = "numpy-2.3.1-cp313-cp313t-win32.whl", hash = "sha256:6269b9edfe32912584ec496d91b00b6d34282ca1d07eb10e82dfc780907d6c2e"}, + {file = "numpy-2.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:2a809637460e88a113e186e87f228d74ae2852a2e0c44de275263376f17b5bdc"}, + {file = "numpy-2.3.1-cp313-cp313t-win_arm64.whl", hash = "sha256:eccb9a159db9aed60800187bc47a6d3451553f0e1b08b068d8b277ddfbb9b244"}, + {file = "numpy-2.3.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ad506d4b09e684394c42c966ec1527f6ebc25da7f4da4b1b056606ffe446b8a3"}, + {file = "numpy-2.3.1-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:ebb8603d45bc86bbd5edb0d63e52c5fd9e7945d3a503b77e486bd88dde67a19b"}, + {file = "numpy-2.3.1-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:15aa4c392ac396e2ad3d0a2680c0f0dee420f9fed14eef09bdb9450ee6dcb7b7"}, + {file = "numpy-2.3.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c6e0bf9d1a2f50d2b65a7cf56db37c095af17b59f6c132396f7c6d5dd76484df"}, + {file = "numpy-2.3.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:eabd7e8740d494ce2b4ea0ff05afa1b7b291e978c0ae075487c51e8bd93c0c68"}, + {file = "numpy-2.3.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:e610832418a2bc09d974cc9fecebfa51e9532d6190223bc5ef6a7402ebf3b5cb"}, + {file = "numpy-2.3.1.tar.gz", hash = "sha256:1ec9ae20a4226da374362cca3c62cd753faf2f951440b0e3b98e93c235441d2b"}, ] [[package]] name = "packaging" -version = "24.2" +version = "25.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, - {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, ] [[package]] @@ -1769,6 +1769,23 @@ files = [ dev = ["pre-commit", "tox"] testing = ["coverage", "pytest", "pytest-benchmark"] +[[package]] +name = "prettytable" +version = "3.16.0" +description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format" +optional = false +python-versions = ">=3.9" +files = [ + {file = "prettytable-3.16.0-py3-none-any.whl", hash = "sha256:b5eccfabb82222f5aa46b798ff02a8452cf530a352c31bddfa29be41242863aa"}, + {file = "prettytable-3.16.0.tar.gz", hash = "sha256:3c64b31719d961bf69c9a7e03d0c1e477320906a98da63952bc6698d6164ff57"}, +] + +[package.dependencies] +wcwidth = "*" + +[package.extras] +tests = ["pytest", "pytest-cov", "pytest-lazy-fixtures"] + [[package]] name = "protobuf" version = "4.25.8" @@ -1934,6 +1951,28 @@ snowballstemmer = ">=2.2.0" [package.extras] toml = ["tomli (>=1.2.3)"] +[[package]] +name = "pyecharts" +version = "2.0.8" +description = "Python options, make charting easier" +optional = false +python-versions = "*" +files = [ + {file = "pyecharts-2.0.8-py3-none-any.whl", hash = "sha256:8b711ba139f39f89bc1b2a869d7adda89dc74c910d158a1f9063109fe66bc985"}, + {file = "pyecharts-2.0.8.tar.gz", hash = "sha256:908dbd939862dd3c76bb53697bdb41d3cdd0b5ba48ca69a76a6085d0aa27dbdf"}, +] + +[package.dependencies] +jinja2 = "*" +prettytable = "*" +simplejson = "*" + +[package.extras] +images = ["PIL"] +phantomjs = ["snapshot-phantomjs"] +pyppeteer = ["snapshot-pyppeteer"] +selenium = ["snapshot-selenium"] + [[package]] name = "pyflakes" version = "2.5.0" @@ -1958,13 +1997,13 @@ files = [ [[package]] name = "pygments" -version = "2.19.1" +version = "2.19.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" files = [ - {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, - {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, + {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, + {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, ] [package.extras] @@ -2390,6 +2429,125 @@ enabler = ["pytest-enabler (>=2.2)"] test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.14.*)", "pytest-mypy"] +[[package]] +name = "simplejson" +version = "3.20.1" +description = "Simple, fast, extensible JSON encoder/decoder for Python" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.5" +files = [ + {file = "simplejson-3.20.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:f5272b5866b259fe6c33c4a8c5073bf8b359c3c97b70c298a2f09a69b52c7c41"}, + {file = "simplejson-3.20.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5c0de368f3052a59a1acf21f8b2dd28686a9e4eba2da7efae7ed9554cb31e7bc"}, + {file = "simplejson-3.20.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:0821871404a537fd0e22eba240c74c0467c28af6cc435903eca394cfc74a0497"}, + {file = "simplejson-3.20.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:c939a1e576bded47d7d03aa2afc2ae90b928b2cf1d9dc2070ceec51fd463f430"}, + {file = "simplejson-3.20.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:3c4f0a61cdc05550782ca4a2cdb311ea196c2e6be6b24a09bf71360ca8c3ca9b"}, + {file = "simplejson-3.20.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:6c21f5c026ca633cfffcb6bc1fac2e99f65cb2b24657d3bef21aed9916cc3bbf"}, + {file = "simplejson-3.20.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:8d23b7f8d6b72319d6d55a0261089ff621ce87e54731c2d3de6a9bf7be5c028c"}, + {file = "simplejson-3.20.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:cda5c32a98f392909088111ecec23f2b0d39346ceae1a0fea23ab2d1f84ec21d"}, + {file = "simplejson-3.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e580aa65d5f6c3bf41b9b4afe74be5d5ddba9576701c107c772d936ea2b5043a"}, + {file = "simplejson-3.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4a586ce4f78cec11f22fe55c5bee0f067e803aab9bad3441afe2181693b5ebb5"}, + {file = "simplejson-3.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74a1608f9e6e8c27a4008d70a54270868306d80ed48c9df7872f9f4b8ac87808"}, + {file = "simplejson-3.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03db8cb64154189a92a7786209f24e391644f3a3fa335658be2df2af1960b8d8"}, + {file = "simplejson-3.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eea7e2b7d858f6fdfbf0fe3cb846d6bd8a45446865bc09960e51f3d473c2271b"}, + {file = "simplejson-3.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e66712b17d8425bb7ff8968d4c7c7fd5a2dd7bd63728b28356223c000dd2f91f"}, + {file = "simplejson-3.20.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2cc4f6486f9f515b62f5831ff1888886619b84fc837de68f26d919ba7bbdcbc"}, + {file = "simplejson-3.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a3c2df555ee4016148fa192e2b9cd9e60bc1d40769366134882685e90aee2a1e"}, + {file = "simplejson-3.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:78520f04b7548a5e476b5396c0847e066f1e0a4c0c5e920da1ad65e95f410b11"}, + {file = "simplejson-3.20.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f4bd49ecde87b0fe9f55cc971449a32832bca9910821f7072bbfae1155eaa007"}, + {file = "simplejson-3.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7eaae2b88eb5da53caaffdfa50e2e12022553949b88c0df4f9a9663609373f72"}, + {file = "simplejson-3.20.1-cp310-cp310-win32.whl", hash = "sha256:e836fb88902799eac8debc2b642300748f4860a197fa3d9ea502112b6bb8e142"}, + {file = "simplejson-3.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:b122a19b552b212fc3b5b96fc5ce92333d4a9ac0a800803e1f17ebb16dac4be5"}, + {file = "simplejson-3.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:325b8c107253d3217e89d7b50c71015b5b31e2433e6c5bf38967b2f80630a8ca"}, + {file = "simplejson-3.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88a7baa8211089b9e58d78fbc1b0b322103f3f3d459ff16f03a36cece0d0fcf0"}, + {file = "simplejson-3.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:299b1007b8101d50d95bc0db1bf5c38dc372e85b504cf77f596462083ee77e3f"}, + {file = "simplejson-3.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ec618ed65caab48e81e3ed29586236a8e57daef792f1f3bb59504a7e98cd10"}, + {file = "simplejson-3.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2cdead1d3197f0ff43373cf4730213420523ba48697743e135e26f3d179f38"}, + {file = "simplejson-3.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3466d2839fdc83e1af42e07b90bc8ff361c4e8796cd66722a40ba14e458faddd"}, + {file = "simplejson-3.20.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d492ed8e92f3a9f9be829205f44b1d0a89af6582f0cf43e0d129fa477b93fe0c"}, + {file = "simplejson-3.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f924b485537b640dc69434565463fd6fc0c68c65a8c6e01a823dd26c9983cf79"}, + {file = "simplejson-3.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9e8eacf6a3491bf76ea91a8d46726368a6be0eb94993f60b8583550baae9439e"}, + {file = "simplejson-3.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d34d04bf90b4cea7c22d8b19091633908f14a096caa301b24c2f3d85b5068fb8"}, + {file = "simplejson-3.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:69dd28d4ce38390ea4aaf212902712c0fd1093dc4c1ff67e09687c3c3e15a749"}, + {file = "simplejson-3.20.1-cp311-cp311-win32.whl", hash = "sha256:dfe7a9da5fd2a3499436cd350f31539e0a6ded5da6b5b3d422df016444d65e43"}, + {file = "simplejson-3.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:896a6c04d7861d507d800da7642479c3547060bf97419d9ef73d98ced8258766"}, + {file = "simplejson-3.20.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f31c4a3a7ab18467ee73a27f3e59158255d1520f3aad74315edde7a940f1be23"}, + {file = "simplejson-3.20.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:884e6183d16b725e113b83a6fc0230152ab6627d4d36cb05c89c2c5bccfa7bc6"}, + {file = "simplejson-3.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03d7a426e416fe0d3337115f04164cd9427eb4256e843a6b8751cacf70abc832"}, + {file = "simplejson-3.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:000602141d0bddfcff60ea6a6e97d5e10c9db6b17fd2d6c66199fa481b6214bb"}, + {file = "simplejson-3.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:af8377a8af78226e82e3a4349efdde59ffa421ae88be67e18cef915e4023a595"}, + {file = "simplejson-3.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15c7de4c88ab2fbcb8781a3b982ef883696736134e20b1210bca43fb42ff1acf"}, + {file = "simplejson-3.20.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:455a882ff3f97d810709f7b620007d4e0aca8da71d06fc5c18ba11daf1c4df49"}, + {file = "simplejson-3.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:fc0f523ce923e7f38eb67804bc80e0a028c76d7868500aa3f59225574b5d0453"}, + {file = "simplejson-3.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76461ec929282dde4a08061071a47281ad939d0202dc4e63cdd135844e162fbc"}, + {file = "simplejson-3.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ab19c2da8c043607bde4d4ef3a6b633e668a7d2e3d56f40a476a74c5ea71949f"}, + {file = "simplejson-3.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b2578bedaedf6294415197b267d4ef678fea336dd78ee2a6d2f4b028e9d07be3"}, + {file = "simplejson-3.20.1-cp312-cp312-win32.whl", hash = "sha256:339f407373325a36b7fd744b688ba5bae0666b5d340ec6d98aebc3014bf3d8ea"}, + {file = "simplejson-3.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:627d4486a1ea7edf1f66bb044ace1ce6b4c1698acd1b05353c97ba4864ea2e17"}, + {file = "simplejson-3.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:71e849e7ceb2178344998cbe5ade101f1b329460243c79c27fbfc51c0447a7c3"}, + {file = "simplejson-3.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b63fdbab29dc3868d6f009a59797cefaba315fd43cd32ddd998ee1da28e50e29"}, + {file = "simplejson-3.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1190f9a3ce644fd50ec277ac4a98c0517f532cfebdcc4bd975c0979a9f05e1fb"}, + {file = "simplejson-3.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1336ba7bcb722ad487cd265701ff0583c0bb6de638364ca947bb84ecc0015d1"}, + {file = "simplejson-3.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e975aac6a5acd8b510eba58d5591e10a03e3d16c1cf8a8624ca177491f7230f0"}, + {file = "simplejson-3.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a6dd11ee282937ad749da6f3b8d87952ad585b26e5edfa10da3ae2536c73078"}, + {file = "simplejson-3.20.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab980fcc446ab87ea0879edad41a5c28f2d86020014eb035cf5161e8de4474c6"}, + {file = "simplejson-3.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f5aee2a4cb6b146bd17333ac623610f069f34e8f31d2f4f0c1a2186e50c594f0"}, + {file = "simplejson-3.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:652d8eecbb9a3b6461b21ec7cf11fd0acbab144e45e600c817ecf18e4580b99e"}, + {file = "simplejson-3.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:8c09948f1a486a89251ee3a67c9f8c969b379f6ffff1a6064b41fea3bce0a112"}, + {file = "simplejson-3.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cbbd7b215ad4fc6f058b5dd4c26ee5c59f72e031dfda3ac183d7968a99e4ca3a"}, + {file = "simplejson-3.20.1-cp313-cp313-win32.whl", hash = "sha256:ae81e482476eaa088ef9d0120ae5345de924f23962c0c1e20abbdff597631f87"}, + {file = "simplejson-3.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:1b9fd15853b90aec3b1739f4471efbf1ac05066a2c7041bf8db821bb73cd2ddc"}, + {file = "simplejson-3.20.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c7edf279c1376f28bf41e916c015a2a08896597869d57d621f55b6a30c7e1e6d"}, + {file = "simplejson-3.20.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9202b9de38f12e99a40addd1a8d508a13c77f46d87ab1f9095f154667f4fe81"}, + {file = "simplejson-3.20.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:391345b4157cc4e120027e013bd35c45e2c191e2bf48b8913af488cdc3b9243c"}, + {file = "simplejson-3.20.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c6fdcc9debb711ddd2ad6d69f9386a3d9e8e253234bbb30513e0a7caa9510c51"}, + {file = "simplejson-3.20.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9daf8cdc7ee8a9e9f7a3b313ba0a003391857e90d0e82fbcd4d614aa05cb7c3b"}, + {file = "simplejson-3.20.1-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:c02f4868a3a46ffe284a51a88d134dc96feff6079a7115164885331a1ba8ed9f"}, + {file = "simplejson-3.20.1-cp36-cp36m-musllinux_1_2_i686.whl", hash = "sha256:3d7310172d5340febd258cb147f46aae30ad57c445f4d7e1ae8461c10aaf43b0"}, + {file = "simplejson-3.20.1-cp36-cp36m-musllinux_1_2_ppc64le.whl", hash = "sha256:4762e05577955312a4c6802f58dd02e040cc79ae59cda510aa1564d84449c102"}, + {file = "simplejson-3.20.1-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:8bb98fdf318c05aefd08a92583bd6ee148e93c6756fb1befb7b2d5f27824be78"}, + {file = "simplejson-3.20.1-cp36-cp36m-win32.whl", hash = "sha256:9a74e70818818981294b8e6956ce3496c5e1bd4726ac864fae473197671f7b85"}, + {file = "simplejson-3.20.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e041add470e8f8535cc05509485eb7205729a84441f03b25cde80ad48823792e"}, + {file = "simplejson-3.20.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7e9d73f46119240e4f4f07868241749d67d09873f40cb968d639aa9ccc488b86"}, + {file = "simplejson-3.20.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae6e637dc24f8fee332ed23dd070e81394138e42cd4fd9d0923e5045ba122e27"}, + {file = "simplejson-3.20.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:efd3bc6c6b17e3d4620eb6be5196f0d1c08b6ce7c3101fa8e292b79e0908944b"}, + {file = "simplejson-3.20.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87fc623d457173a0213bc9ca4e346b83c9d443f63ed5cca847fb0cacea3cfc95"}, + {file = "simplejson-3.20.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec6a1e0a7aff76f0e008bebfa950188b9c50b58c1885d898145f48fc8e189a56"}, + {file = "simplejson-3.20.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:9c079606f461a6e950099167e21e13985147c8a24be8eea66c9ad68f73fad744"}, + {file = "simplejson-3.20.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:9faceb68fba27ef17eda306e4cd97a7b4b14fdadca5fbb15790ba8b26ebeec0c"}, + {file = "simplejson-3.20.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:7ceed598e4bacbf5133fe7a418f7991bb2df0683f3ac11fbf9e36a2bc7aa4b85"}, + {file = "simplejson-3.20.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:ede69c765e9901861ad7c6139023b7b7d5807c48a2539d817b4ab40018002d5f"}, + {file = "simplejson-3.20.1-cp37-cp37m-win32.whl", hash = "sha256:d8853c269a4c5146ddca4aa7c70e631795e9d11239d5fedb1c6bbc91ffdebcac"}, + {file = "simplejson-3.20.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ed6a17fd397f0e2b3ad668fc9e19253ed2e3875ad9086bd7f795c29a3223f4a1"}, + {file = "simplejson-3.20.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7551682b60bba3a9e2780742e101cf0a64250e76de7d09b1c4b0c8a7c7cc6834"}, + {file = "simplejson-3.20.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bd9577ec1c8c3a43040e3787711e4c257c70035b7551a21854b5dec88dad09e1"}, + {file = "simplejson-3.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a8e197e4cf6d42c2c57e7c52cd7c1e7b3e37c5911df1314fb393320131e2101"}, + {file = "simplejson-3.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bd09c8c75666e7f62a33d2f1fb57f81da1fcbb19a9fe7d7910b5756e1dd6048"}, + {file = "simplejson-3.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1bd6bfe5678d73fbd5328eea6a35216503796428fc47f1237432522febaf3a0c"}, + {file = "simplejson-3.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:71b75d448fd0ceb2e7c90e72bb82c41f8462550d48529980bc0bab1d2495bfbb"}, + {file = "simplejson-3.20.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7e15b716d09f318c8cda3e20f82fae81684ce3d3acd1d7770fa3007df1769de"}, + {file = "simplejson-3.20.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:3e7963197d958fcf9e98b212b80977d56c022384621ff463d98afc3b6b1ce7e8"}, + {file = "simplejson-3.20.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:2e671dd62051129185d3a9a92c60101f56cbc174854a1a3dfb69114ebd9e1699"}, + {file = "simplejson-3.20.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:e25b2a0c396f3b84fb89573d07b0e1846ed563eb364f2ea8230ca92b8a8cb786"}, + {file = "simplejson-3.20.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:489c3a43116082bad56795215786313832ba3991cca1f55838e52a553f451ab6"}, + {file = "simplejson-3.20.1-cp38-cp38-win32.whl", hash = "sha256:4a92e948bad8df7fa900ba2ba0667a98303f3db206cbaac574935c332838208e"}, + {file = "simplejson-3.20.1-cp38-cp38-win_amd64.whl", hash = "sha256:49d059b8363327eee3c94799dd96782314b2dbd7bcc293b4ad48db69d6f4d362"}, + {file = "simplejson-3.20.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a8011f1dd1d676befcd4d675ebdbfdbbefd3bf350052b956ba8c699fca7d8cef"}, + {file = "simplejson-3.20.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e91703a4c5fec53e36875ae426ad785f4120bd1d93b65bed4752eeccd1789e0c"}, + {file = "simplejson-3.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e39eaa57c7757daa25bcd21f976c46be443b73dd6c3da47fe5ce7b7048ccefe2"}, + {file = "simplejson-3.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceab2ce2acdc7fbaa433a93006758db6ba9a659e80c4faa13b80b9d2318e9b17"}, + {file = "simplejson-3.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d4f320c33277a5b715db5bf5b10dae10c19076bd6d66c2843e04bd12d1f1ea5"}, + {file = "simplejson-3.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b6436c48e64378fa844d8c9e58a5ed0352bbcfd4028369a9b46679b7ab79d2d"}, + {file = "simplejson-3.20.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e18345c8dda5d699be8166b61f9d80aaee4545b709f1363f60813dc032dac53"}, + {file = "simplejson-3.20.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:90b573693d1526bed576f6817e2a492eaaef68f088b57d7a9e83d122bbb49e51"}, + {file = "simplejson-3.20.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:272cc767826e924a6bd369ea3dbf18e166ded29059c7a4d64d21a9a22424b5b5"}, + {file = "simplejson-3.20.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:51b41f284d603c4380732d7d619f8b34bd04bc4aa0ed0ed5f4ffd0539b14da44"}, + {file = "simplejson-3.20.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6e6697a3067d281f01de0fe96fc7cba4ea870d96d7deb7bfcf85186d74456503"}, + {file = "simplejson-3.20.1-cp39-cp39-win32.whl", hash = "sha256:6dd3a1d5aca87bf947f3339b0f8e8e329f1badf548bdbff37fac63c17936da8e"}, + {file = "simplejson-3.20.1-cp39-cp39-win_amd64.whl", hash = "sha256:463f1fca8fbf23d088e5850fdd0dd4d5faea8900a9f9680270bd98fd649814ca"}, + {file = "simplejson-3.20.1-py3-none-any.whl", hash = "sha256:8a6c1bbac39fa4a79f83cbf1df6ccd8ff7069582a9fd8db1e52cea073bc2c697"}, + {file = "simplejson-3.20.1.tar.gz", hash = "sha256:e64139b4ec4f1f24c142ff7dcafe55a22b811a74d86d66560c8815687143037d"}, +] + [[package]] name = "six" version = "1.17.0" @@ -2640,23 +2798,23 @@ pbr = ">=2.0.0" [[package]] name = "streamlit" -version = "1.45.1" +version = "1.46.0" description = "A faster way to build and share data apps" optional = false python-versions = "!=3.9.7,>=3.9" files = [ - {file = "streamlit-1.45.1-py3-none-any.whl", hash = "sha256:9ab6951585e9444672dd650850f81767b01bba5d87c8dac9bc2e1c859d6cc254"}, - {file = "streamlit-1.45.1.tar.gz", hash = "sha256:e37d56c0af5240dbc240976880e81366689c290a559376417246f9b3f51b4217"}, + {file = "streamlit-1.46.0-py3-none-any.whl", hash = "sha256:f8624acabafcf18611a0fac2635cf181a7ba922b45bd131ae15fc8f80e1a5482"}, + {file = "streamlit-1.46.0.tar.gz", hash = "sha256:0b2734b48f11f1e5c8046011b6b1a2274982dc657eef2ade8db70f0e1dc53dda"}, ] [package.dependencies] altair = ">=4.0,<6" blinker = ">=1.5.0,<2" -cachetools = ">=4.0,<6" +cachetools = ">=4.0,<7" click = ">=7.0,<9" gitpython = ">=3.0.7,<3.1.19 || >3.1.19,<4" numpy = ">=1.23,<3" -packaging = ">=20,<25" +packaging = ">=20,<26" pandas = ">=1.4.0,<3" pillow = ">=7.1.0,<12" protobuf = ">=3.20,<7" @@ -2665,13 +2823,29 @@ pydeck = ">=0.8.0b4,<1" requests = ">=2.27,<3" tenacity = ">=8.1.0,<10" toml = ">=0.10.1,<2" -tornado = ">=6.0.3,<7" +tornado = ">=6.0.3,<6.5.0 || >6.5.0,<7" typing-extensions = ">=4.4.0,<5" watchdog = {version = ">=2.1.5,<7", markers = "platform_system != \"Darwin\""} [package.extras] snowflake = ["snowflake-connector-python (>=3.3.0)", "snowflake-snowpark-python[modin] (>=1.17.0)"] +[[package]] +name = "streamlit-echarts" +version = "0.4.0" +description = "Echarts custom component for Streamlit" +optional = false +python-versions = ">=3.6" +files = [ + {file = "streamlit-echarts-0.4.0.tar.gz", hash = "sha256:33cc5329b99ddce8b64ce6c4607733e02db575c379af6394a8c78ae5df14934d"}, + {file = "streamlit_echarts-0.4.0-py3-none-any.whl", hash = "sha256:aa86679da0e7680ee43b7a6def31439273a686a8d71de522c55655047e80ec9b"}, +] + +[package.dependencies] +pyecharts = ">=1.9" +simplejson = ">=3.0" +streamlit = ">=0.63" + [[package]] name = "tenacity" version = "9.1.2" @@ -2817,13 +2991,13 @@ files = [ [[package]] name = "urllib3" -version = "2.4.0" +version = "2.5.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" files = [ - {file = "urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813"}, - {file = "urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466"}, + {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, + {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, ] [package.extras] @@ -2874,7 +3048,18 @@ files = [ [package.extras] watchmedo = ["PyYAML (>=3.10)"] +[[package]] +name = "wcwidth" +version = "0.2.13" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, +] + [metadata] lock-version = "2.0" python-versions = ">=3.9,<4.0,!=3.9.7" -content-hash = "ad2491b853963ec0501a51fc5c2754991650928ee489ccab6c0b2ba836963971" +content-hash = "067db79239cc901576e6365bf1d2d6e40e2c68039ed8b638dbb384e8f2324671" diff --git a/pyproject.toml b/pyproject.toml index 9cc9902..6ef5fdf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,6 +13,7 @@ protobuf = {version=">=4.21"} ni-measurement-plugin-sdk = {version=">=2.3"} typing-extensions = ">=4.13.2" streamlit = ">=1.24" +streamlit-echarts = ">=0.4.0" nitypes = {version=">=0.1.0dev2", allow-prereleases=true} debugpy = ">=1.8.1" From 59ac9d9e51853b0536f686927b3ae4f214634707 Mon Sep 17 00:00:00 2001 From: Mike Prosser Date: Mon, 23 Jun 2025 13:17:24 -0500 Subject: [PATCH 6/9] fix mypy issues and move streamlit-echarts to examples dependancy group --- CONTRIBUTING.md | 11 +++++++++++ examples/all_types/README.md | 2 +- examples/sample/README.md | 2 +- examples/simple_graph/README.md | 2 +- examples/simple_graph/simple_graph_panel.py | 2 +- pyproject.toml | 7 ++++++- src/nipanel/converters/protobuf_types.py | 2 +- 7 files changed, 22 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d28ad97..cb10b3e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -54,6 +54,17 @@ poetry run sphinx-build docs docs/_build --builder html --fail-on-warning start docs\_build\index.html ``` +## Running examples + +1. First, run the PythonPanelService (not part of this repo, provided seperately) +2. Run the command `poetry run python examples/sample/sample.py` +3. Open http://localhost:42001/panel-service/panels/sample_panel/ in your browser +4. If there is an error about missing imports (especially nipanel), execute this + command to install the dependencies into the venv: `C:\Users\mprosser\AppData\Local\Temp\python_panel_service_venv\Scripts\python.exe + -m pip install C:\dev\fireserp\nipanel-python[examples,dev]`, then restart the PythonPanelService and re-run sample.py. + +You can see all running panels (and stop them) at: http://localhost:42001/panel-service/ + # Debugging on the streamlit side Debugging the measurement script can be done using standard Python debugging diff --git a/examples/all_types/README.md b/examples/all_types/README.md index c23a42b..7b56c38 100644 --- a/examples/all_types/README.md +++ b/examples/all_types/README.md @@ -12,4 +12,4 @@ This is an example for `nipanel` that demonstrates all supported data types ### Usage -Run `poetry run examples/all_types/all_types.py` \ No newline at end of file +Run `poetry run python examples/all_types/all_types.py` diff --git a/examples/sample/README.md b/examples/sample/README.md index 38e3292..957e353 100644 --- a/examples/sample/README.md +++ b/examples/sample/README.md @@ -12,4 +12,4 @@ This is a nipanel example that displays an interactive Streamlit app and updates ### Usage -Run `poetry run examples/sample/sample.py` \ No newline at end of file +Run `poetry run python examples/sample/sample.py` \ No newline at end of file diff --git a/examples/simple_graph/README.md b/examples/simple_graph/README.md index d7a9427..6264444 100644 --- a/examples/simple_graph/README.md +++ b/examples/simple_graph/README.md @@ -15,4 +15,4 @@ This example demonstrates using nipanel with Streamlit to display a dynamic sine ### Usage -Run `poetry run examples/simple_graph/simple_graph.py` +Run `poetry run python examples/simple_graph/simple_graph.py` diff --git a/examples/simple_graph/simple_graph_panel.py b/examples/simple_graph/simple_graph_panel.py index 5402493..d4df263 100644 --- a/examples/simple_graph/simple_graph_panel.py +++ b/examples/simple_graph/simple_graph_panel.py @@ -1,7 +1,7 @@ """Example of displaying a sine wave using streamlit-echarts in a nipanel.""" import streamlit as st -from streamlit_echarts import st_echarts +from streamlit_echarts import st_echarts # type: ignore from nipanel import initialize_panel diff --git a/pyproject.toml b/pyproject.toml index 6ef5fdf..ae2db61 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,6 @@ protobuf = {version=">=4.21"} ni-measurement-plugin-sdk = {version=">=2.3"} typing-extensions = ">=4.13.2" streamlit = ">=1.24" -streamlit-echarts = ">=0.4.0" nitypes = {version=">=0.1.0dev2", allow-prereleases=true} debugpy = ">=1.8.1" @@ -53,6 +52,12 @@ sphinx-autoapi = ">=1.8.4" m2r2 = ">=0.3.2" toml = ">=0.10.2" +[tool.poetry.group.examples] +optional = true + +[tool.poetry.group.examples.dependencies] +streamlit-echarts = ">=0.4.0" + [build-system] requires = ["poetry-core>=1.8.0"] build-backend = "poetry.core.masonry.api" diff --git a/src/nipanel/converters/protobuf_types.py b/src/nipanel/converters/protobuf_types.py index ebdae61..4c99096 100644 --- a/src/nipanel/converters/protobuf_types.py +++ b/src/nipanel/converters/protobuf_types.py @@ -100,7 +100,7 @@ def _value_to_attribute(self, value: ExtendedPropertyValue) -> WaveformAttribute def to_python_value(self, protobuf_message: DoubleAnalogWaveform) -> AnalogWaveform[np.float64]: """Convert the protobuf DoubleAnalogWaveform to a Python AnalogWaveform.""" # Declare timing to accept both bintime and dt.datetime to satisfy mypy. - timing: Timing[bt.DateTime | dt.datetime] + timing: Timing[Union[bt.DateTime, dt.datetime]] if not protobuf_message.dt and not protobuf_message.HasField("t0"): # If both dt and t0 are unset, use Timing.empty. timing = Timing.empty From 3d60ea77935aacc7ea38f82b84edc63a480c9f1d Mon Sep 17 00:00:00 2001 From: Mike Prosser Date: Mon, 23 Jun 2025 13:27:51 -0500 Subject: [PATCH 7/9] fix lock file and add titles and icons to the panel tabs --- examples/all_types/all_types_panel.py | 3 ++- examples/sample/sample_panel.py | 4 +++- examples/simple_graph/simple_graph_panel.py | 5 +++-- poetry.lock | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/examples/all_types/all_types_panel.py b/examples/all_types/all_types_panel.py index 7c2cf0d..1f20fee 100644 --- a/examples/all_types/all_types_panel.py +++ b/examples/all_types/all_types_panel.py @@ -7,7 +7,8 @@ panel = nipanel.initialize_panel() -st.title("All Types") +st.set_page_config(page_title="All Types Example", page_icon="📊", layout="wide") +st.title("All Types Example") for name in all_types_with_values.keys(): col1, col2 = st.columns([0.4, 0.6]) diff --git a/examples/sample/sample_panel.py b/examples/sample/sample_panel.py index 18a1941..ec9564f 100644 --- a/examples/sample/sample_panel.py +++ b/examples/sample/sample_panel.py @@ -6,7 +6,9 @@ panel = nipanel.initialize_panel() -st.title("Sample Panel") + +st.set_page_config(page_title="Sample Panel Example", page_icon="📊", layout="wide") +st.title("Sample Panel Example") col1, col2 = st.columns([0.4, 0.6]) diff --git a/examples/simple_graph/simple_graph_panel.py b/examples/simple_graph/simple_graph_panel.py index d4df263..be57791 100644 --- a/examples/simple_graph/simple_graph_panel.py +++ b/examples/simple_graph/simple_graph_panel.py @@ -6,10 +6,11 @@ from nipanel import initialize_panel +panel = initialize_panel() + st.set_page_config(page_title="Simple Graph Example", page_icon="📈", layout="wide") -st.title("Simple Sine Wave Visualization") +st.title("Simple Graph Example") -panel = initialize_panel() time_points = panel.get_value("time_points", [0.0]) sine_values = panel.get_value("sine_values", [0.0]) amplitude = panel.get_value("amplitude", 1.0) diff --git a/poetry.lock b/poetry.lock index e903238..12133c0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3062,4 +3062,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">=3.9,<4.0,!=3.9.7" -content-hash = "067db79239cc901576e6365bf1d2d6e40e2c68039ed8b638dbb384e8f2324671" +content-hash = "296f5d5ca9c4ab5d392a67d43884fe8a9f63ea0e9437bce8a572793d62827603" From 0d3aa3c0b540e47d901d389561622e197b159ef3 Mon Sep 17 00:00:00 2001 From: Mike Prosser Date: Mon, 23 Jun 2025 13:55:33 -0500 Subject: [PATCH 8/9] rename initialize_panel to get_panel_accessor and throw exceptions when called improperly --- examples/all_types/all_types_panel.py | 2 +- examples/sample/sample_panel.py | 2 +- examples/simple_graph/simple_graph_panel.py | 4 ++-- src/nipanel/__init__.py | 4 ++-- src/nipanel/_streamlit_panel_initializer.py | 19 ++++++++++++++----- 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/examples/all_types/all_types_panel.py b/examples/all_types/all_types_panel.py index 1f20fee..2805836 100644 --- a/examples/all_types/all_types_panel.py +++ b/examples/all_types/all_types_panel.py @@ -5,7 +5,7 @@ import nipanel -panel = nipanel.initialize_panel() +panel = nipanel.get_panel_accessor() st.set_page_config(page_title="All Types Example", page_icon="📊", layout="wide") st.title("All Types Example") diff --git a/examples/sample/sample_panel.py b/examples/sample/sample_panel.py index ec9564f..f71d368 100644 --- a/examples/sample/sample_panel.py +++ b/examples/sample/sample_panel.py @@ -4,7 +4,7 @@ import nipanel -panel = nipanel.initialize_panel() +panel = nipanel.get_panel_accessor() st.set_page_config(page_title="Sample Panel Example", page_icon="📊", layout="wide") diff --git a/examples/simple_graph/simple_graph_panel.py b/examples/simple_graph/simple_graph_panel.py index be57791..92cfaa7 100644 --- a/examples/simple_graph/simple_graph_panel.py +++ b/examples/simple_graph/simple_graph_panel.py @@ -3,10 +3,10 @@ import streamlit as st from streamlit_echarts import st_echarts # type: ignore -from nipanel import initialize_panel +import nipanel -panel = initialize_panel() +panel = nipanel.get_panel_accessor() st.set_page_config(page_title="Simple Graph Example", page_icon="📈", layout="wide") st.title("Simple Graph Example") diff --git a/src/nipanel/__init__.py b/src/nipanel/__init__.py index 89d1ba9..05d5a73 100644 --- a/src/nipanel/__init__.py +++ b/src/nipanel/__init__.py @@ -4,12 +4,12 @@ from nipanel._panel import Panel from nipanel._streamlit_panel import StreamlitPanel -from nipanel._streamlit_panel_initializer import create_panel, initialize_panel +from nipanel._streamlit_panel_initializer import create_panel, get_panel_accessor from nipanel._streamlit_panel_value_accessor import StreamlitPanelValueAccessor __all__ = [ "create_panel", - "initialize_panel", + "get_panel_accessor", "Panel", "StreamlitPanel", "StreamlitPanelValueAccessor", diff --git a/src/nipanel/_streamlit_panel_initializer.py b/src/nipanel/_streamlit_panel_initializer.py index 3172adc..ebf3478 100644 --- a/src/nipanel/_streamlit_panel_initializer.py +++ b/src/nipanel/_streamlit_panel_initializer.py @@ -19,7 +19,7 @@ def create_panel(streamlit_script_path: Path) -> StreamlitPanel: "some_example". Use this function when you want to create a new panel instance to use in a Streamlit - application. + application. Do not call this function from within a Streamlit script. Args: streamlit_script_path: The file path of the Streamlit script to be used for the panel. @@ -27,6 +27,11 @@ def create_panel(streamlit_script_path: Path) -> StreamlitPanel: Returns: A StreamlitPanel instance initialized with the given panel ID. """ + if st.get_option("server.baseUrlPath") != "": + raise RuntimeError( + "nipanel.create_panel() should not be called from a Streamlit script. Call nipanel.get_panel_accessor() instead." + ) + path_str = str(streamlit_script_path) if not path_str.endswith(".py"): raise ValueError( @@ -37,17 +42,21 @@ def create_panel(streamlit_script_path: Path) -> StreamlitPanel: return StreamlitPanel(panel_id, path_str) -def initialize_panel() -> StreamlitPanelValueAccessor: +def get_panel_accessor() -> StreamlitPanelValueAccessor: """Initialize and return the Streamlit panel value accessor. This function retrieves the Streamlit panel value accessor for the current Streamlit script. - It is typically used within a Streamlit script to access and manipulate panel values. - The accessor will be cached in the Streamlit session state to ensure that it is reused across - reruns of the script. + This function should only be called from within a Streamlit script. The accessor will be cached + in the Streamlit session state to ensure that it is reused across reruns of the script. Returns: A StreamlitPanelValueAccessor instance for the current panel. """ + if st.get_option("server.baseUrlPath") == "": + raise RuntimeError( + "nipanel.get_panel_accessor() should only be called from a Streamlit script. Call nipanel.create_panel() instead." + ) + if PANEL_ACCESSOR_KEY not in st.session_state: st.session_state[PANEL_ACCESSOR_KEY] = _initialize_panel_from_base_path() From c3dad08ba6874008d414a4b773479095e6a97821 Mon Sep 17 00:00:00 2001 From: Mike Prosser Date: Mon, 23 Jun 2025 14:16:27 -0500 Subject: [PATCH 9/9] change sample to hello, and address other feedback --- CONTRIBUTING.md | 9 ++++--- examples/hello/README.md | 15 ++++++++++++ examples/hello/hello.py | 12 +++++++++ examples/hello/hello_panel.py | 11 +++++++++ examples/sample/README.md | 15 ------------ examples/sample/sample.py | 16 ------------ examples/sample/sample_panel.py | 27 --------------------- examples/simple_graph/simple_graph_panel.py | 2 +- src/nipanel/_streamlit_panel_initializer.py | 4 +-- src/nipanel/converters/protobuf_types.py | 4 ++- 10 files changed, 49 insertions(+), 66 deletions(-) create mode 100644 examples/hello/README.md create mode 100644 examples/hello/hello.py create mode 100644 examples/hello/hello_panel.py delete mode 100644 examples/sample/README.md delete mode 100644 examples/sample/sample.py delete mode 100644 examples/sample/sample_panel.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cb10b3e..5b45770 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -57,11 +57,12 @@ start docs\_build\index.html ## Running examples 1. First, run the PythonPanelService (not part of this repo, provided seperately) -2. Run the command `poetry run python examples/sample/sample.py` -3. Open http://localhost:42001/panel-service/panels/sample_panel/ in your browser +2. Run the command `poetry run python examples/hello/hello.py` +3. Open http://localhost:42001/panel-service/panels/hello_panel/ in your browser 4. If there is an error about missing imports (especially nipanel), execute this - command to install the dependencies into the venv: `C:\Users\mprosser\AppData\Local\Temp\python_panel_service_venv\Scripts\python.exe - -m pip install C:\dev\fireserp\nipanel-python[examples,dev]`, then restart the PythonPanelService and re-run sample.py. + command (from the nipanel-python directory) to install the dependencies into the venv: + `%localappdata%\Temp\python_panel_service_venv\Scripts\python.exe -m pip install .\[examples,dev]`, + then restart the PythonPanelService and re-run hello.py. You can see all running panels (and stop them) at: http://localhost:42001/panel-service/ diff --git a/examples/hello/README.md b/examples/hello/README.md new file mode 100644 index 0000000..b6d6bd6 --- /dev/null +++ b/examples/hello/README.md @@ -0,0 +1,15 @@ +## Hello + +This is a simple nipanel example that displays a Streamlit app. + +### Feature + +- Just a Hello World + +### Required Software + +- Python 3.9 or later + +### Usage + +Run `poetry run python examples/hello/hello.py` \ No newline at end of file diff --git a/examples/hello/hello.py b/examples/hello/hello.py new file mode 100644 index 0000000..ad2d97a --- /dev/null +++ b/examples/hello/hello.py @@ -0,0 +1,12 @@ +"""This example demonstrates how to open/update a Streamlit application using nipanel package.""" + +from pathlib import Path + +import nipanel + +panel_script_path = Path(__file__).with_name("hello_panel.py") +panel = nipanel.create_panel(panel_script_path) + +panel.set_value("hello_string", "Hello, World!") + +print(f"Panel URL: {panel.panel_url}") diff --git a/examples/hello/hello_panel.py b/examples/hello/hello_panel.py new file mode 100644 index 0000000..d1cd735 --- /dev/null +++ b/examples/hello/hello_panel.py @@ -0,0 +1,11 @@ +"""A Streamlit visualization panel for the hello.py example script.""" + +import streamlit as st + +import nipanel + +panel = nipanel.get_panel_accessor() + +st.set_page_config(page_title="Hello World Example", page_icon="📊", layout="wide") +st.title("Hello World Example") +st.write(panel.get_value("hello_string", "")) diff --git a/examples/sample/README.md b/examples/sample/README.md deleted file mode 100644 index 957e353..0000000 --- a/examples/sample/README.md +++ /dev/null @@ -1,15 +0,0 @@ -## Sample - -This is a nipanel example that displays an interactive Streamlit app and updates its values. - -### Feature - -- Supports various data types - -### Required Software - -- Python 3.9 or later - -### Usage - -Run `poetry run python examples/sample/sample.py` \ No newline at end of file diff --git a/examples/sample/sample.py b/examples/sample/sample.py deleted file mode 100644 index bcb9030..0000000 --- a/examples/sample/sample.py +++ /dev/null @@ -1,16 +0,0 @@ -"""This example demonstrates how to open/update a Streamlit application using nipanel package.""" - -from pathlib import Path - -import nipanel - -panel_script_path = Path(__file__).with_name("sample_panel.py") -panel = nipanel.create_panel(panel_script_path) - -panel.set_value("sample_string", "Hello, World!") -panel.set_value("sample_int", 42) -panel.set_value("sample_float", 3.14) -panel.set_value("sample_bool", True) -panel.set_value("float_values", [1.1, 2.2, 3.3]) - -print(f"Panel URL: {panel.panel_url}") diff --git a/examples/sample/sample_panel.py b/examples/sample/sample_panel.py deleted file mode 100644 index f71d368..0000000 --- a/examples/sample/sample_panel.py +++ /dev/null @@ -1,27 +0,0 @@ -"""Streamlit application script for displaying values using nipanel package.""" - -import streamlit as st - -import nipanel - -panel = nipanel.get_panel_accessor() - - -st.set_page_config(page_title="Sample Panel Example", page_icon="📊", layout="wide") -st.title("Sample Panel Example") - -col1, col2 = st.columns([0.4, 0.6]) - -with col1: - st.write("String") - st.write("Integer") - st.write("Float") - st.write("Boolean") - st.write("List") - -with col2: - st.write(panel.get_value("sample_string", "")) - st.write(panel.get_value("sample_int", 0)) - st.write(panel.get_value("sample_float", 0.0)) - st.write(panel.get_value("sample_bool", False)) - st.write(panel.get_value("float_values", [])) diff --git a/examples/simple_graph/simple_graph_panel.py b/examples/simple_graph/simple_graph_panel.py index 92cfaa7..f7c8a1a 100644 --- a/examples/simple_graph/simple_graph_panel.py +++ b/examples/simple_graph/simple_graph_panel.py @@ -1,4 +1,4 @@ -"""Example of displaying a sine wave using streamlit-echarts in a nipanel.""" +"""A Streamlit visualization panel for the simple_graph.py example script.""" import streamlit as st from streamlit_echarts import st_echarts # type: ignore diff --git a/src/nipanel/_streamlit_panel_initializer.py b/src/nipanel/_streamlit_panel_initializer.py index ebf3478..7dee3fd 100644 --- a/src/nipanel/_streamlit_panel_initializer.py +++ b/src/nipanel/_streamlit_panel_initializer.py @@ -32,13 +32,13 @@ def create_panel(streamlit_script_path: Path) -> StreamlitPanel: "nipanel.create_panel() should not be called from a Streamlit script. Call nipanel.get_panel_accessor() instead." ) - path_str = str(streamlit_script_path) - if not path_str.endswith(".py"): + if streamlit_script_path.suffix != ".py": raise ValueError( "The provided script path must be a valid Streamlit script ending with '.py'." ) panel_id = streamlit_script_path.stem + path_str = str(streamlit_script_path) return StreamlitPanel(panel_id, path_str) diff --git a/src/nipanel/converters/protobuf_types.py b/src/nipanel/converters/protobuf_types.py index 4c99096..07cc15f 100644 --- a/src/nipanel/converters/protobuf_types.py +++ b/src/nipanel/converters/protobuf_types.py @@ -1,5 +1,7 @@ """Classes to convert between measurement specific protobuf types and containers.""" +from __future__ import annotations + import collections.abc import datetime as dt from typing import Type, Union @@ -100,7 +102,7 @@ def _value_to_attribute(self, value: ExtendedPropertyValue) -> WaveformAttribute def to_python_value(self, protobuf_message: DoubleAnalogWaveform) -> AnalogWaveform[np.float64]: """Convert the protobuf DoubleAnalogWaveform to a Python AnalogWaveform.""" # Declare timing to accept both bintime and dt.datetime to satisfy mypy. - timing: Timing[Union[bt.DateTime, dt.datetime]] + timing: Timing[bt.DateTime | dt.datetime] if not protobuf_message.dt and not protobuf_message.HasField("t0"): # If both dt and t0 are unset, use Timing.empty. timing = Timing.empty