update README, improved sample (in preparation for demo)
This commit is contained in:
parent
96bbb3602a
commit
b52e70e918
4 changed files with 164 additions and 54 deletions
72
README.md
72
README.md
|
|
@ -1,3 +1,71 @@
|
|||
# View1 Library
|
||||
# Watt42 Viewlib
|
||||
|
||||
Supports building a view for Watt42 systems.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You should be familiar with Python.
|
||||
|
||||
You need poetry installed:
|
||||
|
||||
- [Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer)
|
||||
|
||||
## Demo
|
||||
|
||||
You can [run the sample online](https://viewlib-demo.watt42.com). The sample code is in [sample.py](./sample.py).
|
||||
|
||||
TODO: provide more sophisticated demos online.
|
||||
|
||||
## Documentation
|
||||
|
||||
### Installation
|
||||
|
||||
Make sure you have poetry installed (see above), then run:
|
||||
|
||||
```bash
|
||||
poetry install
|
||||
```
|
||||
|
||||
You can now run the sample view in dev mode with:
|
||||
|
||||
|
||||
```bash
|
||||
poetry run panel serve sample.py --dev
|
||||
```
|
||||
|
||||
Dev mode enables hot reloading, so any changes you make to the code will be
|
||||
reflected immediately in the browser.
|
||||
|
||||
Your view will be available at `http://localhost:5006/sample`. In order for the
|
||||
view to work, you need to configure an access token, and the Watt42 system that
|
||||
you want to use. See #how-to-use below.
|
||||
|
||||
### How to use
|
||||
|
||||
Build your own front end for a Watt42 system by creating a Python script that
|
||||
uses Viewlib. Start off with the sample code in [sample.py](./sample.py). You
|
||||
can then extend the view by adding more widgets and logic.
|
||||
|
||||
1. Follow the installation instructions above.
|
||||
2. Make sure you have a Watt42 system set up, and you have an access token for it. (TODO: link on how to do this)
|
||||
3. Set the following environment variables:
|
||||
- `WATT42_SYSTEM_ID`: The ID of your Watt42 system.
|
||||
- `WATT42_API_TOKEN`: Your access token.
|
||||
|
||||
|
||||
### Howtos
|
||||
|
||||
- See above on how to use Viewlib to build your own view.
|
||||
- [How to add a diagram](https://source.c3.uber5.com/watt42-public/watt42_viewlib/src/branch/main/docs/howto_add_diagram.md)
|
||||
- Learn more about how to build views with Panel:
|
||||
- [Panel Tutorials](https://panel.holoviz.org/tutorials/index.html)
|
||||
- [Panel Explanation](https://panel.holoviz.org/explanation/index.html)
|
||||
|
||||
## Reference
|
||||
|
||||
- [Watt42 Viewlib Documentation](https://source.c3.uber5.com/watt42-public/watt42_viewlib/src/branch/main/docs/reference.md)
|
||||
- Visual components:
|
||||
- [Panel Component Gallery](https://panel.holoviz.org/reference/index.html)
|
||||
- [Panel App Gallery](https://panel.holoviz.org/gallery/index.html)
|
||||
- [Panel API Reference](https://panel.holoviz.org/api/index.html)
|
||||
|
||||
Supports building a view for Watt42 systems
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ build-backend = "poetry.core.masonry.api"
|
|||
[tool.pyright]
|
||||
venvPath = "."
|
||||
venv = ".venv"
|
||||
reportAny = false
|
||||
reportExplicitAny = false
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
pythonpath = ["."]
|
||||
|
|
|
|||
69
sample-old.py
Normal file
69
sample-old.py
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import json
|
||||
import panel
|
||||
from random import randint
|
||||
from typing import Any
|
||||
|
||||
from watt42_viewlib import attach_w42_state
|
||||
|
||||
w42_state = panel.rx(None)
|
||||
attach_w42_state(rx_var=w42_state, system_id="fb2b91ce-383e-4356-96b3-b6405dacb353")
|
||||
|
||||
state_as_text = panel.bind(lambda s: f"W42 State:\n\n```\n{json.dumps(s, indent=2)}\n```\n\nReplace this with some awesome visuals", w42_state)
|
||||
|
||||
state_pane = panel.pane.Markdown(state_as_text, sizing_mode='stretch_width')
|
||||
|
||||
value = w42_state.rx.value
|
||||
|
||||
multiplier = panel.widgets.IntSlider(name='Multiplier', start=1, end=10, step=1, value=1)
|
||||
|
||||
def value_display(state: dict[str, Any], multiplier: int) -> str:
|
||||
if state and 'value' in state:
|
||||
return f"Current W42 State Value times multiplier: {state['value'] * multiplier}"
|
||||
return "Current W42 State Value: N/A"
|
||||
|
||||
def value_or_zero(state: dict[str, Any]) -> int:
|
||||
if state and 'value' in state:
|
||||
return state['value']
|
||||
return 0
|
||||
|
||||
def array_from_value(x: int) -> list[int]:
|
||||
return [x * randint(1, 20) for _ in range(25)]
|
||||
|
||||
def times2(x: int) -> int:
|
||||
return x * 2
|
||||
|
||||
times2_rx = panel.rx(times2)(panel.rx(value_or_zero)(w42_state))
|
||||
|
||||
markdown_rx = panel.rx(lambda v: f"## Value times 2 is: {v}, array={array_from_value(v)}")(times2_rx)
|
||||
|
||||
array_rx = panel.rx(array_from_value)(panel.rx(value_or_zero)(w42_state))
|
||||
|
||||
echart_bar_rx = panel.pane.ECharts(
|
||||
panel.rx(lambda arr: {
|
||||
'xAxis': {
|
||||
'type': 'category',
|
||||
'data': [f'Item {i+1}' for i in range(len(arr))]
|
||||
},
|
||||
'yAxis': {
|
||||
'type': 'value'
|
||||
},
|
||||
'series': [{
|
||||
'data': arr,
|
||||
'type': 'bar'
|
||||
}]
|
||||
})(array_rx),
|
||||
sizing_mode='stretch_width',
|
||||
height=400
|
||||
)
|
||||
|
||||
_ = panel.template.FastListTemplate(
|
||||
title="Sample W42 View App",
|
||||
sidebar=[panel.pane.Markdown("This is a sample sidebar.")],
|
||||
main=[
|
||||
panel.pane.Markdown("# Welcome to the Main Content Area"),
|
||||
echart_bar_rx,
|
||||
# state_pane, panel.pane.Markdown(f"Current W42 State Value: {value}"),
|
||||
panel.ReactiveExpr(panel.rx(value_display)(w42_state, multiplier), widget_location='top'),
|
||||
panel.pane.Markdown(markdown_rx),
|
||||
],
|
||||
).servable()
|
||||
75
sample.py
75
sample.py
|
|
@ -1,69 +1,40 @@
|
|||
import json
|
||||
import os
|
||||
import panel
|
||||
from random import randint
|
||||
from typing import Any
|
||||
|
||||
from watt42_viewlib import attach_w42_state
|
||||
|
||||
w42_state = panel.rx(None)
|
||||
attach_w42_state(rx_var=w42_state, system_id="fb2b91ce-383e-4356-96b3-b6405dacb353")
|
||||
panel.extension('echarts', 'ace', 'jsoneditor')
|
||||
|
||||
state_as_text = panel.bind(lambda s: f"W42 State:\n\n```\n{json.dumps(s, indent=2)}\n```\n\nReplace this with some awesome visuals", w42_state)
|
||||
SYSTEM_ID = os.environ.get("WATT42_SYSTEM_ID", "invalid-system-id")
|
||||
API_TOKEN = os.environ.get("WATT42_API_TOKEN", "invalid-api-token")
|
||||
|
||||
w42_state = panel.rx(None)
|
||||
|
||||
attach_w42_state(rx_var=w42_state, system_id=SYSTEM_ID, token=API_TOKEN)
|
||||
|
||||
def state_to_text(state: dict[str, Any]) -> str:
|
||||
return f"W42 State:\n\n```\n{json.dumps(state, indent=2)}\n```\n\nReplace this with some awesome visuals"
|
||||
|
||||
state_as_text = panel.bind(state_to_text, w42_state)
|
||||
|
||||
state_pane = panel.pane.Markdown(state_as_text, sizing_mode='stretch_width')
|
||||
|
||||
value = w42_state.rx.value
|
||||
sidebar_content = """
|
||||
This example shows how to build a front end for a Watt42 system: Watt42 API
|
||||
manages the state of the system, this app visualizes it.
|
||||
|
||||
multiplier = panel.widgets.IntSlider(name='Multiplier', start=1, end=10, step=1, value=1)
|
||||
Find instructions on [how to use this example
|
||||
here](https://source.c3.uber5.com/watt42-public/watt42_viewlib/src/branch/main/README.md#how-to-use).
|
||||
|
||||
def value_display(state: dict[str, Any], multiplier: int) -> str:
|
||||
if state and 'value' in state:
|
||||
return f"Current W42 State Value times multiplier: {state['value'] * multiplier}"
|
||||
return "Current W42 State Value: N/A"
|
||||
|
||||
def value_or_zero(state: dict[str, Any]) -> int:
|
||||
if state and 'value' in state:
|
||||
return state['value']
|
||||
return 0
|
||||
|
||||
def array_from_value(x: int) -> list[int]:
|
||||
return [x * randint(1, 20) for _ in range(25)]
|
||||
|
||||
def times2(x: int) -> int:
|
||||
return x * 2
|
||||
|
||||
times2_rx = panel.rx(times2)(panel.rx(value_or_zero)(w42_state))
|
||||
|
||||
markdown_rx = panel.rx(lambda v: f"## Value times 2 is: {v}, array={array_from_value(v)}")(times2_rx)
|
||||
|
||||
array_rx = panel.rx(array_from_value)(panel.rx(value_or_zero)(w42_state))
|
||||
|
||||
echart_bar_rx = panel.pane.ECharts(
|
||||
panel.rx(lambda arr: {
|
||||
'xAxis': {
|
||||
'type': 'category',
|
||||
'data': [f'Item {i+1}' for i in range(len(arr))]
|
||||
},
|
||||
'yAxis': {
|
||||
'type': 'value'
|
||||
},
|
||||
'series': [{
|
||||
'data': arr,
|
||||
'type': 'bar'
|
||||
}]
|
||||
})(array_rx),
|
||||
sizing_mode='stretch_width',
|
||||
height=400
|
||||
)
|
||||
"""
|
||||
|
||||
_ = panel.template.FastListTemplate(
|
||||
title="Sample W42 View App",
|
||||
sidebar=[panel.pane.Markdown("This is a sample sidebar.")],
|
||||
title="Sample W42 App",
|
||||
sidebar=[panel.pane.Markdown(sidebar_content, sizing_mode='stretch_width')],
|
||||
main=[
|
||||
panel.pane.Markdown("# Welcome to the Main Content Area"),
|
||||
echart_bar_rx,
|
||||
# state_pane, panel.pane.Markdown(f"Current W42 State Value: {value}"),
|
||||
panel.ReactiveExpr(panel.rx(value_display)(w42_state, multiplier), widget_location='top'),
|
||||
panel.pane.Markdown(markdown_rx),
|
||||
state_pane,
|
||||
w42_state,
|
||||
],
|
||||
).servable()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue