From df5a45a8bcc8e2a572ff0f6428dd73065f14c4cc Mon Sep 17 00:00:00 2001 From: Ewout ter Hoeven Date: Wed, 3 Jul 2024 13:41:39 +0200 Subject: [PATCH 1/7] Update visualisation docs --- docs/apis/visualization.md | 31 +++---------------------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/docs/apis/visualization.md b/docs/apis/visualization.md index fde799e0f54..2e8f4cdcf47 100644 --- a/docs/apis/visualization.md +++ b/docs/apis/visualization.md @@ -1,38 +1,13 @@ # Visualization -```{eval-rst} -.. automodule:: visualization.__init__ - :members: -``` - -```{eval-rst} -.. automodule:: visualization.ModularVisualization - :members: -``` - -```{eval-rst} -.. automodule:: visualization.TextVisualization - :members: -``` - -## Modules - -```{eval-rst} -.. automodule:: visualization.modules.__init__ - :members: -``` - -```{eval-rst} -.. automodule:: visualization.modules.CanvasGridVisualization - :members: -``` +For a detailed tutorial, please refer to our [Visualization Tutorial](../tutorials/visualization_tutorial.ipynb). ```{eval-rst} -.. automodule:: visualization.modules.ChartVisualization +.. automodule:: mesa.visualization.jupyter_viz :members: ``` ```{eval-rst} -.. automodule:: visualization.modules.TextVisualization +.. automodule:: mesa.visualization.UserParam :members: ``` From f646a007cc3c25a934d3236c9cb25df0d237962f Mon Sep 17 00:00:00 2001 From: Ewout ter Hoeven Date: Wed, 3 Jul 2024 13:50:04 +0200 Subject: [PATCH 2/7] Try to include all function :undoc-members: :show-inheritance: --- docs/apis/visualization.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/apis/visualization.md b/docs/apis/visualization.md index 2e8f4cdcf47..29b81456c7b 100644 --- a/docs/apis/visualization.md +++ b/docs/apis/visualization.md @@ -5,9 +5,13 @@ For a detailed tutorial, please refer to our [Visualization Tutorial](../tutoria ```{eval-rst} .. automodule:: mesa.visualization.jupyter_viz :members: + :undoc-members: + :show-inheritance: ``` ```{eval-rst} .. automodule:: mesa.visualization.UserParam :members: + :undoc-members: + :show-inheritance: ``` From ccb69c9ac5e973a7cc15198d0b6c35951a37e242 Mon Sep 17 00:00:00 2001 From: Ewout ter Hoeven Date: Wed, 3 Jul 2024 14:16:26 +0200 Subject: [PATCH 3/7] viz docs: Add headings --- docs/apis/visualization.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/apis/visualization.md b/docs/apis/visualization.md index 29b81456c7b..fd558041e86 100644 --- a/docs/apis/visualization.md +++ b/docs/apis/visualization.md @@ -2,6 +2,8 @@ For a detailed tutorial, please refer to our [Visualization Tutorial](../tutorials/visualization_tutorial.ipynb). +## Jupyter Visualization + ```{eval-rst} .. automodule:: mesa.visualization.jupyter_viz :members: @@ -9,6 +11,8 @@ For a detailed tutorial, please refer to our [Visualization Tutorial](../tutoria :show-inheritance: ``` +## User Parameters + ```{eval-rst} .. automodule:: mesa.visualization.UserParam :members: From dec05e0fa60be1d5b50f6609246ccb5082402fe7 Mon Sep 17 00:00:00 2001 From: Ewout ter Hoeven Date: Wed, 3 Jul 2024 14:30:00 +0200 Subject: [PATCH 4/7] Add docstring to Jupyter viz module and functions --- mesa/visualization/jupyter_viz.py | 126 +++++++++++++++++++++++++++--- 1 file changed, 113 insertions(+), 13 deletions(-) diff --git a/mesa/visualization/jupyter_viz.py b/mesa/visualization/jupyter_viz.py index 2067dcfd88c..a8520828644 100644 --- a/mesa/visualization/jupyter_viz.py +++ b/mesa/visualization/jupyter_viz.py @@ -1,3 +1,28 @@ +""" +Mesa visualization module for creating interactive model visualizations. + +This module provides components to create browser-based visualizations of Mesa models, +allowing users to watch models run step-by-step and interact with model parameters. + +Key features: +- JupyterViz: Main component for creating visualizations, supporting grid displays and plots +- ModelController: Handles model execution controls (step, play, pause, reset) +- UserInputs: Generates UI elements for adjusting model parameters +- Card: Renders individual visualization elements (space, measures) + +The module uses Solara for rendering in Jupyter notebooks or as standalone web applications. +It supports various types of visualizations including matplotlib plots, agent grids, and +custom visualization components. + +Usage: +1. Define an agent_portrayal function to specify how agents should be displayed +2. Set up model_params to define adjustable parameters +3. Create a JupyterViz instance with your model, parameters, and desired measures +4. Display the visualization in a Jupyter notebook or run as a Solara app + +See the Mesa documentation for more detailed usage instructions and examples. +""" + import sys import threading @@ -19,6 +44,21 @@ def Card( model, measures, agent_portrayal, space_drawer, dependencies, color, layout_type ): + """ + Create a card component for visualizing model space or measures. + + Args: + model: The Mesa model instance + measures: List of measures to be plotted + agent_portrayal: Function to define agent appearance + space_drawer: Method to render agent space + dependencies: List of dependencies for updating the visualization + color: Background color of the card + layout_type: Type of layout (Space or Measure) + + Returns: + rv.Card: A card component containing the visualization + """ with rv.Card( style_=f"background-color: {color}; width: 100%; height: 100%" ) as main: @@ -60,19 +100,21 @@ def JupyterViz( play_interval=150, seed=None, ): - """Initialize a component to visualize a model. + """ + Initialize a component to visualize a model. + Args: - model_class: class of the model to instantiate - model_params: parameters for initializing the model - measures: list of callables or data attributes to plot - name: name for display - agent_portrayal: options for rendering agents (dictionary) - space_drawer: method to render the agent space for + model_class: Class of the model to instantiate + model_params: Parameters for initializing the model + measures: List of callables or data attributes to plot + name: Name for display + agent_portrayal: Options for rendering agents (dictionary) + space_drawer: Method to render the agent space for the model; default implementation is the `SpaceMatplotlib` component; simulations with no space to visualize should specify `space_drawer=False` - play_interval: play interval (default: 150) - seed: the random seed used to initialize the model + play_interval: Play interval (default: 150) + seed: The random seed used to initialize the model """ if name is None: name = model_class.__name__ @@ -88,6 +130,7 @@ def JupyterViz( # 2. Set up Model def make_model(): + """Create a new model instance with current parameters and seed.""" model = model_class.__new__( model_class, **model_parameters, seed=reactive_seed.value ) @@ -106,6 +149,7 @@ def make_model(): ) def handle_change_model_params(name: str, value: any): + """Update model parameters when user input changes.""" set_model_parameters({**model_parameters, name: value}) # 3. Set up UI @@ -115,12 +159,14 @@ def handle_change_model_params(name: str, value: any): # render layout and plot def do_reseed(): + """Update the random seed for the model.""" reactive_seed.value = model.random.random() # jupyter dependencies = [current_step.value, reactive_seed.value] def render_in_jupyter(): + """Render the visualization components in Jupyter notebook.""" with solara.GridFixed(columns=2): UserInputs(user_params, on_change=handle_change_model_params) ModelController(model, play_interval, current_step, reset_counter) @@ -153,6 +199,7 @@ def render_in_jupyter(): ) def render_in_browser(): + """Render the visualization components in a web browser.""" # if space drawer is disabled, do not include it layout_types = [{"Space": "default"}] if space_drawer else [] @@ -204,6 +251,15 @@ def render_in_browser(): @solara.component def ModelController(model, play_interval, current_step, reset_counter): + """ + Create controls for model execution (step, play, pause, reset). + + Args: + model: The model being visualized + play_interval: Interval between steps during play + current_step: Reactive value for the current step + reset_counter: Counter to trigger model reset + """ playing = solara.use_reactive(False) thread = solara.use_reactive(None) # We track the previous step to detect if user resets the model via @@ -213,6 +269,7 @@ def ModelController(model, play_interval, current_step, reset_counter): previous_step = solara.use_reactive(0) def on_value_play(change): + """Handle play/pause state changes.""" if previous_step.value > current_step.value and current_step.value == 0: # We add extra checks for current_step.value == 0, just to be sure. # We automatically stop the playing if a model is reset. @@ -223,31 +280,37 @@ def on_value_play(change): playing.value = False def do_step(): + """Advance the model by one step.""" model.step() previous_step.value = current_step.value current_step.value = model._steps def do_play(): + """Run the model continuously.""" model.running = True while model.running: do_step() def threaded_do_play(): + """Start a new thread for continuous model execution.""" if thread is not None and thread.is_alive(): return thread.value = threading.Thread(target=do_play) thread.start() def do_pause(): + """Pause the model execution.""" if (thread is None) or (not thread.is_alive()): return model.running = False thread.join() def do_reset(): + """Reset the model.""" reset_counter.value += 1 def do_set_playing(value): + """Set the playing state.""" if current_step.value == 0: # This means the model has been recreated, and the step resets to # 0. We want to avoid triggering the playing.value = False in the @@ -291,6 +354,15 @@ def do_set_playing(value): def split_model_params(model_params): + """ + Split model parameters into user-adjustable and fixed parameters. + + Args: + model_params: Dictionary of all model parameters + + Returns: + tuple: (user_adjustable_params, fixed_params) + """ model_params_input = {} model_params_fixed = {} for k, v in model_params.items(): @@ -302,6 +374,15 @@ def split_model_params(model_params): def check_param_is_fixed(param): + """ + Check if a parameter is fixed (not user-adjustable). + + Args: + param: Parameter to check + + Returns: + bool: True if parameter is fixed, False otherwise + """ if isinstance(param, Slider): return False if not isinstance(param, dict): @@ -312,14 +393,15 @@ def check_param_is_fixed(param): @solara.component def UserInputs(user_params, on_change=None): - """Initialize user inputs for configurable model parameters. + """ + Initialize user inputs for configurable model parameters. Currently supports :class:`solara.SliderInt`, :class:`solara.SliderFloat`, :class:`solara.Select`, and :class:`solara.Checkbox`. - Props: - user_params: dictionary with options for the input, including label, + Args: + user_params: Dictionary with options for the input, including label, min and max values, and other fields specific to the input type. - on_change: function to be called with (name, value) when the value of an input changes. + on_change: Function to be called with (name, value) when the value of an input changes. """ for name, options in user_params.items(): @@ -380,6 +462,15 @@ def change_handler(value, name=name): def make_text(renderer): + """ + Create a function that renders text using Markdown. + + Args: + renderer: Function that takes a model and returns a string + + Returns: + function: A function that renders the text as Markdown + """ def function(model): solara.Markdown(renderer(model)) @@ -387,6 +478,15 @@ def function(model): def make_initial_grid_layout(layout_types): + """ + Create an initial grid layout for visualization components. + + Args: + layout_types: List of layout types (Space or Measure) + + Returns: + list: Initial grid layout configuration + """ return [ { "i": i, From a07490b4a35796534524309f4838b146e5a964f2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 3 Jul 2024 12:30:16 +0000 Subject: [PATCH 5/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mesa/visualization/jupyter_viz.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mesa/visualization/jupyter_viz.py b/mesa/visualization/jupyter_viz.py index a8520828644..e555f0d20c0 100644 --- a/mesa/visualization/jupyter_viz.py +++ b/mesa/visualization/jupyter_viz.py @@ -471,6 +471,7 @@ def make_text(renderer): Returns: function: A function that renders the text as Markdown """ + def function(model): solara.Markdown(renderer(model)) From 67ac81c2e9e5296c9a1721df5bf28d2cda8d6a0c Mon Sep 17 00:00:00 2001 From: Ewout ter Hoeven Date: Wed, 3 Jul 2024 14:43:34 +0200 Subject: [PATCH 6/7] Add indentation --- mesa/visualization/jupyter_viz.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/mesa/visualization/jupyter_viz.py b/mesa/visualization/jupyter_viz.py index e555f0d20c0..761bc78aff2 100644 --- a/mesa/visualization/jupyter_viz.py +++ b/mesa/visualization/jupyter_viz.py @@ -5,22 +5,22 @@ allowing users to watch models run step-by-step and interact with model parameters. Key features: -- JupyterViz: Main component for creating visualizations, supporting grid displays and plots -- ModelController: Handles model execution controls (step, play, pause, reset) -- UserInputs: Generates UI elements for adjusting model parameters -- Card: Renders individual visualization elements (space, measures) + - JupyterViz: Main component for creating visualizations, supporting grid displays and plots + - ModelController: Handles model execution controls (step, play, pause, reset) + - UserInputs: Generates UI elements for adjusting model parameters + - Card: Renders individual visualization elements (space, measures) The module uses Solara for rendering in Jupyter notebooks or as standalone web applications. It supports various types of visualizations including matplotlib plots, agent grids, and custom visualization components. Usage: -1. Define an agent_portrayal function to specify how agents should be displayed -2. Set up model_params to define adjustable parameters -3. Create a JupyterViz instance with your model, parameters, and desired measures -4. Display the visualization in a Jupyter notebook or run as a Solara app + 1. Define an agent_portrayal function to specify how agents should be displayed + 2. Set up model_params to define adjustable parameters + 3. Create a JupyterViz instance with your model, parameters, and desired measures + 4. Display the visualization in a Jupyter notebook or run as a Solara app -See the Mesa documentation for more detailed usage instructions and examples. +See the Visualization Tutorial and example models for more details. """ import sys From d0ae6b2d6356f5f7139fe98dc09e66413f1d5c37 Mon Sep 17 00:00:00 2001 From: Ewout ter Hoeven Date: Wed, 3 Jul 2024 15:46:05 +0200 Subject: [PATCH 7/7] browser and notebooks based --- mesa/visualization/jupyter_viz.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mesa/visualization/jupyter_viz.py b/mesa/visualization/jupyter_viz.py index 761bc78aff2..99a427da2b9 100644 --- a/mesa/visualization/jupyter_viz.py +++ b/mesa/visualization/jupyter_viz.py @@ -1,8 +1,8 @@ """ Mesa visualization module for creating interactive model visualizations. -This module provides components to create browser-based visualizations of Mesa models, -allowing users to watch models run step-by-step and interact with model parameters. +This module provides components to create browser- and Jupyter notebook-based visualizations of +Mesa models, allowing users to watch models run step-by-step and interact with model parameters. Key features: - JupyterViz: Main component for creating visualizations, supporting grid displays and plots