Application state
Streamsync assigns each session its own application state.
Initialising state
The initial application state can be set by calling ss.init_state()
and passing a Dict
as argument. All session states will kick off as a copy of the initial state.
import streamsync as ss
initial_state = ss.init_state({
"counter": 0,
})
# Event handler
# It receives the session state as an argument and mutates it
def increment(state):
state["counter"] += 1
import streamsync as ss
initial_state = ss.init_state({
"counter": 0,
})
# Event handler
# It receives the session state as an argument and mutates it
def increment(state):
state["counter"] += 1
In the example above, everyone starts with counter
set to 0. But after users start interacting with the app and triggering event handlers, the value of counter
will be different across sessions. Some users will trigger increment
three times, making it 3. Some will trigger increment
ten times, making it 10.
To reference counter
from Builder, use @{counter}
.
Nested elements
Use dictionaries to set nested elements.
ss.init_state({
"counter": 0,
"my_app": {
"title": "Nested value"
}
})
ss.init_state({
"counter": 0,
"my_app": {
"title": "Nested value"
}
})
From Builder, you can reference the element above as @{my_app.title}
.
Backend-only elements
By default, all of the elements in the session state are sent to the frontend.
State elements are sent to the frontend by default
Even if they aren't actively being shown in the user interface, they're sent to the user's browser.
Prefix a state element with _
(underscore) to make them private (backend-only). This can be very useful in some scenarios.
- When synchronisation is not necessary. In some cases, we'll only need the data in the backend.
- When synchronisation is not possible, because the object can't be serialised / shown in the browser. For example, a database connection.
- When data is relevant to a specific session, but shouldn't be disclosed.
Since these elements stay in the backend and aren't synced, you cannot reference them from Builder.
Non-standard types
The frontend cannot directly show objects such as a Pandas dataframe or a Matplotlib figure. Therefore, these objects need to be serialised before being sent to the browser. The following types of objects are automatically serialised.
Matplotlib figures
They're converted to PNG data URLs, which can be shown using a standard Image component.
ss.init_state({
"my_matplotlib_fig": fig,
})
ss.init_state({
"my_matplotlib_fig": fig,
})
The element can be used in an Image component in Builder by setting the source to @{my_matplotlib_fig}
. Alternatively, as data inside a File Download component.
Plotly graphs
They're converted to Plotly JS specifications, using JSON. They can be used in Plotly Graph components.
Altair charts
They're converted to Vega Lite specification, based on JSON. They can be used in Vega Lite Chart components.
Pandas dataframes
They're converted to JSON; they can be used in Dataframe components.
Files and binary data
In some components, Builder expects a data URL. The source of an Image component can be a standard URL or a data URL.
You can pack files and binary data and they'll be converted to data URLs before they reach the frontend. For this purpose, you can use ss.pack_file()
and ss.pack_bytes()
as shown below. The mime_type
argument is optional for both functions —it helps the browser determine how to handle the data, by specifying the media type.
You can also directly assign bytes, but this won't allow you to specify the media type.
import streamsync as ss
ss.init_state({
# Use a string to reference a filesystem path
"sales_spreadsheet": ss.pack_file("sales_spreadsheet.xlsx")
# Use any file-like object with a .read() method
"main_image": ss.pack_file(image_file, mime_type="image/jpeg"),
# Work with raw bytes
"my_bytes": ss.pack_bytes(b"\x31\x33\x33\x37", mime_type="text/plain"),
# Send raw bytes, without specifying a MIME type
"my_raw_bytes": b"\x31\x33\x33\x37"
})
import streamsync as ss
ss.init_state({
# Use a string to reference a filesystem path
"sales_spreadsheet": ss.pack_file("sales_spreadsheet.xlsx")
# Use any file-like object with a .read() method
"main_image": ss.pack_file(image_file, mime_type="image/jpeg"),
# Work with raw bytes
"my_bytes": ss.pack_bytes(b"\x31\x33\x33\x37", mime_type="text/plain"),
# Send raw bytes, without specifying a MIME type
"my_raw_bytes": b"\x31\x33\x33\x37"
})