Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add render interval slider to control visualization update frequency #2596

Merged
merged 12 commits into from
Jan 10, 2025
5 changes: 5 additions & 0 deletions docs/tutorials/intro_tutorial.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -1255,6 +1255,11 @@
"We now run the model, collect the data, and plot the results."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
EwoutH marked this conversation as resolved.
Show resolved Hide resolved
{
"cell_type": "code",
"execution_count": null,
Expand Down
7 changes: 6 additions & 1 deletion mesa/examples/advanced/pd_grid/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ class PdGrid(mesa.Model):
payoff = {("C", "C"): 1, ("C", "D"): 0, ("D", "C"): 1.6, ("D", "D"): 0}

def __init__(
self, width=50, height=50, activation_order="Random", payoffs=None, seed=None
self,
width=50,
height=50,
activation_order="Random",
payoffs=None,
seed=None,
EwoutH marked this conversation as resolved.
Show resolved Hide resolved
):
"""
Create a new Spatial Prisoners' Dilemma Model.
Expand Down
38 changes: 31 additions & 7 deletions mesa/visualization/solara_viz.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def SolaraViz(
| Literal["default"] = "default",
*,
play_interval: int = 100,
render_interval: int = 1,
simulator: Simulator | None = None,
model_params=None,
name: str | None = None,
Expand All @@ -72,6 +73,8 @@ def SolaraViz(
Defaults to "default", which uses the default Altair space visualization.
play_interval (int, optional): Interval for playing the model steps in milliseconds.
This controls the speed of the model's automatic stepping. Defaults to 100 ms.
render_interval (int, optional): Controls how often plots are updated during a simulation,
allowing users to skip intermediate steps and update graphs less frequently.
simulator: A simulator that controls the model (optional)
model_params (dict, optional): Parameters for (re-)instantiating a model.
Can include user-adjustable parameters and fixed parameters. Defaults to None.
Expand All @@ -90,6 +93,8 @@ def SolaraViz(
model instance is provided, it will be converted to a reactive model using `solara.use_reactive`.
- The `play_interval` argument controls the speed of the model's automatic stepping. A lower
value results in faster stepping, while a higher value results in slower stepping.
- The `render_interval` argument determines how often plots are updated during simulation. Higher values
reduce update frequency,resulting in faster execution.
"""
if components == "default":
components = [components_altair.make_altair_space()]
Expand All @@ -103,7 +108,7 @@ def SolaraViz(
# set up reactive model_parameters shared by ModelCreator and ModelController
reactive_model_parameters = solara.use_reactive({})
reactive_play_interval = solara.use_reactive(play_interval)

reactive_render_interval = solara.use_reactive(render_interval)
with solara.AppBar():
solara.AppBarTitle(name if name else model.value.__class__.__name__)

Expand All @@ -117,18 +122,28 @@ def SolaraViz(
max=500,
step=10,
)
solara.SliderInt(
label="Render Interval",
value=reactive_render_interval,
on_value=lambda v: reactive_render_interval.set(v),
min=1,
max=100,
step=2,
)
if not isinstance(simulator, Simulator):
ModelController(
model,
model_parameters=reactive_model_parameters,
play_interval=reactive_play_interval,
render_interval=reactive_render_interval,
)
else:
SimulatorController(
model,
simulator,
model_parameters=reactive_model_parameters,
play_interval=reactive_play_interval,
render_interval=reactive_render_interval,
)
with solara.Card("Model Parameters"):
ModelCreator(
Expand Down Expand Up @@ -189,14 +204,15 @@ def ModelController(
*,
model_parameters: dict | solara.Reactive[dict] = None,
play_interval: int | solara.Reactive[int] = 100,
render_interval: int | solara.Reactive[int] = 1,
):
"""Create controls for model execution (step, play, pause, reset).

Args:
model: Reactive model instance
model_parameters: Reactive parameters for (re-)instantiating a model.
play_interval: Interval for playing the model steps in milliseconds.

render_interval: Controls how often the plots are updated during simulation steps.Higher value reduce update frequency.
"""
playing = solara.use_reactive(False)
running = solara.use_reactive(True)
Expand All @@ -215,9 +231,12 @@ async def step():

@function_logger(__name__)
def do_step():
"""Advance the model by one step."""
model.value.step()
"""Advance the model by the number of steps specified by the render_interval slider."""
for _ in range(render_interval.value):
model.value.step()

running.value = model.value.running

force_update()

@function_logger(__name__)
Expand Down Expand Up @@ -259,6 +278,7 @@ def SimulatorController(
*,
model_parameters: dict | solara.Reactive[dict] = None,
play_interval: int | solara.Reactive[int] = 100,
render_interval: int | solara.Reactive[int] = 1,
):
"""Create controls for model execution (step, play, pause, reset).

Expand All @@ -267,7 +287,11 @@ def SimulatorController(
simulator: Simulator instance
model_parameters: Reactive parameters for (re-)instantiating a model.
play_interval: Interval for playing the model steps in milliseconds.
render_interval: Controls how often the plots are updated during simulation steps.Higher values reduce update frequency.

Notes:
The `step button` increments the step by the value specified in the `render_interval` slider.
This behavior ensures synchronization between simulation steps and plot updates.
"""
playing = solara.use_reactive(False)
running = solara.use_reactive(True)
Expand All @@ -285,8 +309,8 @@ async def step():
)

def do_step():
"""Advance the model by one step."""
simulator.run_for(1)
"""Advance the model by the number of steps specified by the render_interval slider."""
simulator.run_for(render_interval.value)
running.value = model.value.running
force_update()

Expand Down Expand Up @@ -390,7 +414,7 @@ def ModelCreator(
or are dictionaries containing parameter details such as type, value, min, and max.
- The `seed` argument ensures reproducibility by setting the initial seed for the model's random number generator.
- The component provides an interface for adjusting user-defined parameters and reseeding the model.

-
EwoutH marked this conversation as resolved.
Show resolved Hide resolved
"""
if model_parameters is None:
model_parameters = {}
Expand Down
Loading