Skip to content

Support Scenarios in SolaraViz visualization#3178

Merged
quaquel merged 66 commits intomesa:mainfrom
falloficarus22:solara-viz-scenarios
Feb 14, 2026
Merged

Support Scenarios in SolaraViz visualization#3178
quaquel merged 66 commits intomesa:mainfrom
falloficarus22:solara-viz-scenarios

Conversation

@falloficarus22
Copy link
Copy Markdown
Contributor

@falloficarus22 falloficarus22 commented Jan 19, 2026

Summary

This PR adds first-class support for Scenarios in SolaraViz. It allows users to visualize and interact with models that utilize the new Mesa Scenario system, ensuring that parameters are correctly routed to either the Model or the Scenario during instantiation and resets.

Motive

With the introduction of Scenarios in Mesa (#3103, #3168), there was a disconnect in the visualization layer.
SolaraViz previously tried to pass all user-defined sliders and parameters directly into Model.__init__. This caused a TypeError when a model used a Scenario, because parameters intended for the Scenario were rejected by the Model's initialization function. This PR solves the routing problem and provides a clear UI separation between Model and Scenario parameters.

Implementation

The implementation follows the "Option 1" (Explicit API) and "Option 2" (Auto-detection) suggestions from the issue:

  • SolaraViz Parameter Routing: Enhanced SolaraViz to automatically introspect the model's scenario attribute and intelligently split parameters between Model and Scenario based on their respective signatures.
  • Scenario Reconstruction on Reset: Updated ModelController and SimulatorController. When the "Reset" button is clicked, it now captures the current values of scenario sliders, reconstructs the specific Scenario subclass instance, and passes it into the Model constructor via the scenario keyword argument.
  • UI Enhancements: Updated ModelCreator to render Scenario-bound sliders in a dedicated "Scenario Parameters" section beneath the main Model parameters, providing visual clarity on parameter ownership.
  • Tests: Added comprehensive test coverage in both tests/visualization/test_solara_viz.py (testing core functionality like parameter splitting logic, ModelCreator with scenarios, and SolaraViz integration) and tests/visualization/test_solara_viz_scenarios.py (testing scenario-specific edge cases and type hints).

Usage Examples

Auto Detection:
If your sliders match field names in your Scenario class, SolaraViz handles the routing automatically:

class MyScenario(Scenario):
    density: float = 0.7

class MyModel(Model):
    def __init__(self, height=40, width=40, scenario=None):
        super().__init__(scenario=scenario)

# 'density' is auto-detected as a Scenario parameter
page = SolaraViz(
    MyModel(),
    model_params={
        "height": 40,
        "density": Slider("Density", 0.7, 0, 1, 0.1)
    }
)

Additional Notes

This change is fully backward compatible. Models not using Scenarios will function exactly as before.
Fixes: #3176

falloficarus22 and others added 2 commits January 19, 2026 15:35
Mesa's Scenario support was previously not integrated with SolaraViz,
causing model reset failures when parameters belonging to a Scenario
were passed directly to the Model's __init__.

This change adds first-class support for Scenarios in the visualization
pipeline. SolaraViz now accepts a [scenario_params](cci:1://file://wsl.localhost/Ubuntu/root/mesa/tests/visualization/test_solara_viz_scenarios.py:31:4-37:119) argument and can
also auto-detect which parameters belong to a Scenario by inspecting
the model instance and class signatures.

When the model is reset, SolaraViz correctly reconstructs the Scenario
object from the updated parameters before instantiating the Model. This
ensures that Scenario-owned variables are correctly routed and do not
cause initialization errors.

The UI is also updated to show Scenario parameters in their own section
within the sidebar.
@github-actions
Copy link
Copy Markdown

Performance benchmarks:

Model Size Init time [95% CI] Run time [95% CI]
BoltzmannWealth small 🔵 -3.1% [-3.5%, -2.7%] 🔵 +0.8% [+0.7%, +1.0%]
BoltzmannWealth large 🔵 -2.9% [-3.4%, -2.4%] 🔵 +0.2% [-0.4%, +0.8%]
Schelling small 🟢 -3.3% [-3.5%, -3.1%] 🔵 +0.9% [+0.8%, +1.0%]
Schelling large 🔵 -2.1% [-2.4%, -1.8%] 🔵 -0.3% [-0.9%, +0.3%]
WolfSheep small 🔵 -0.2% [-0.5%, +0.1%] 🔵 +1.2% [+1.0%, +1.4%]
WolfSheep large 🔵 +0.2% [-0.5%, +1.0%] 🔵 -0.8% [-1.6%, -0.0%]
BoidFlockers small 🔵 +0.4% [-0.2%, +1.0%] 🔵 -0.5% [-0.7%, -0.3%]
BoidFlockers large 🔵 +1.2% [+0.8%, +1.6%] 🔵 -0.6% [-0.8%, -0.4%]

Mesa's Scenario support was previously not integrated with SolaraViz,
causing model reset failures when parameters belonging to a Scenario
were passed directly to the Model's __init__.

This change adds first-class support for Scenarios in the visualization
pipeline. SolaraViz now accepts a [scenario_params](cci:1://file://wsl.localhost/Ubuntu/root/mesa/tests/visualization/test_solara_viz_scenarios.py:31:4-37:119) argument and can
also auto-detect which parameters belong to a Scenario by inspecting
the model instance and class signatures.

When the model is reset, SolaraViz correctly reconstructs the Scenario
object from the updated parameters before instantiating the Model. This
ensures that Scenario-owned variables are correctly routed and do not
cause initialization errors.

The UI is also updated to show Scenario parameters in their own section
within the sidebar.
Mesa's Scenario support was previously not integrated with SolaraViz,
causing model reset failures when parameters belonging to a Scenario
were passed directly to the Model's __init__.

This change adds first-class support for Scenarios in the visualization
pipeline. SolaraViz now accepts a [scenario_params](cci:1://file://wsl.localhost/Ubuntu/root/mesa/tests/visualization/test_solara_viz_scenarios.py:31:4-37:119) argument and can
also auto-detect which parameters belong to a Scenario by inspecting
the model instance and class signatures.

When the model is reset, SolaraViz correctly reconstructs the Scenario
object from the updated parameters before instantiating the Model. This
ensures that Scenario-owned variables are correctly routed and do not
cause initialization errors.

The UI is also updated to show Scenario parameters in their own section
within the sidebar.
Mesa's Scenario support was previously not integrated with SolaraViz,
causing model reset failures when parameters belonging to a Scenario
were passed directly to the Model's __init__.

This change adds first-class support for Scenarios in the visualization
pipeline. SolaraViz now accepts a [scenario_params](cci:1://file://wsl.localhost/Ubuntu/root/mesa/tests/visualization/test_solara_viz_scenarios.py:31:4-37:119) argument and can
also auto-detect which parameters belong to a Scenario by inspecting
the model instance and class signatures.

When the model is reset, SolaraViz correctly reconstructs the Scenario
object from the updated parameters before instantiating the Model. This
ensures that Scenario-owned variables are correctly routed and do not
cause initialization errors.

The UI is also updated to show Scenario parameters in their own section
within the sidebar.
@EwoutH
Copy link
Copy Markdown
Member

EwoutH commented Jan 19, 2026

Thanks for the PR. However, I feel we didn’t completere finish the discussion in #3176 on how we would integrate scenario variables exactly. Let’s get full consensus on the design first.

API design is important, since once we commit to it, we have to support it for a long time.

See also https://github.com/mesa/mesa/blob/main/CONTRIBUTING.md#mesa-development-process

@EwoutH EwoutH marked this pull request as draft January 19, 2026 21:29
@quaquel
Copy link
Copy Markdown
Member

quaquel commented Jan 22, 2026

I suggest simplifying this by only solving the current scenario problem. That is, keep the reflection stuff to figure out what is in the scenario object and what is on the model init, and use that for the ModelController. Leave the slider stuff untouched.

falloficarus22 and others added 5 commits January 23, 2026 09:16
Mesa's Scenario support was previously not integrated with SolaraViz,
causing model reset failures when parameters belonging to a Scenario
were passed directly to the Model's __init__.

This change adds first-class support for Scenarios in the visualization
pipeline. SolaraViz now accepts a [scenario_params](cci:1://file://wsl.localhost/Ubuntu/root/mesa/tests/visualization/test_solara_viz_scenarios.py:31:4-37:119) argument and can
also auto-detect which parameters belong to a Scenario by inspecting
the model instance and class signatures.

When the model is reset, SolaraViz correctly reconstructs the Scenario
object from the updated parameters before instantiating the Model. This
ensures that Scenario-owned variables are correctly routed and do not
cause initialization errors.

The UI is also updated to show Scenario parameters in their own section
within the sidebar.
Removes the explicit 'scenario_params' argument from SolaraViz and related components.
Scenario parameters are now automatically detected and seperated from 'model_params'during model reset, simplifying the public API.
Removes the explicit 'scenario_params' argument from SolaraViz and related components.
Scenario parameters are now automatically detected and seperated from 'model_params'during model reset, simplifying the public API.
@falloficarus22
Copy link
Copy Markdown
Contributor Author

@quaquel Any thoughts here?

@quaquel
Copy link
Copy Markdown
Member

quaquel commented Jan 23, 2026

Please include test code in the existing test files. @Sahil-Chhoker, I would appreciate your input here as well.

Basically, for now, I just want to ensure that solara-viz is compatible with scenarios.

Integrate Mesa's Scenario system with SolaraViz to enable proper
parameter routing between Model and Scenario during visualization
and model resets.

Previously, SolaraViz would fail when models used Scenarios because
scenario parameters were incorrectly passed to Model.__init__, causing
TypeError exceptions.

This change adds intelligent parameter splitting that automatically
detects which parameters belong to the Scenario vs the Model by
inspecting their respective signatures. When a model is reset, the
Scenario is correctly reconstructed with the updated parameters.

The implementation updates ModelController, SimulatorController, and
ModelCreator components to handle scenario-aware parameter routing
while maintaining full backward compatibility.

Tests are added to both test_solara_viz.py (core functionality) and
test_solara_viz_scenarios.py (scenario-specific edge cases).
@falloficarus22 falloficarus22 marked this pull request as ready for review January 23, 2026 11:36
@github-actions
Copy link
Copy Markdown

Performance benchmarks:

Model Size Init time [95% CI] Run time [95% CI]
BoltzmannWealth small 🔴 +59.0% [+57.5%, +60.7%] 🔴 +47.1% [+46.9%, +47.3%]
BoltzmannWealth large 🔴 +78.7% [+63.7%, +93.6%] 🔴 +41.3% [+36.0%, +46.3%]
Schelling small 🔴 +79.8% [+79.0%, +80.6%] 🔴 +84.1% [+83.6%, +84.7%]
Schelling large 🔴 +70.2% [+61.0%, +79.5%] 🔴 +59.1% [+55.7%, +63.6%]
WolfSheep small 🔴 +56.9% [+53.5%, +60.1%] 🔴 +50.2% [+49.5%, +50.8%]
WolfSheep large 🔴 +49.7% [+32.8%, +66.1%] 🔴 +44.8% [+42.3%, +47.1%]
BoidFlockers small 🔴 +30.8% [+30.2%, +31.5%] 🔴 +21.8% [+21.3%, +22.2%]
BoidFlockers large 🔴 +38.6% [+35.0%, +43.2%] 🔴 +21.6% [+20.6%, +22.5%]

@falloficarus22 falloficarus22 marked this pull request as draft January 23, 2026 11:45
@falloficarus22 falloficarus22 marked this pull request as ready for review January 23, 2026 11:49
@github-actions
Copy link
Copy Markdown

Performance benchmarks:

Model Size Init time [95% CI] Run time [95% CI]
BoltzmannWealth small 🔵 -0.4% [-2.1%, +1.4%] 🔵 +1.4% [+1.2%, +1.5%]
BoltzmannWealth large 🔵 +4.4% [-6.1%, +15.2%] 🔵 +1.3% [-3.1%, +6.9%]
Schelling small 🔵 -0.8% [-1.5%, +0.0%] 🔵 +0.7% [+0.3%, +1.1%]
Schelling large 🔵 +4.6% [-2.0%, +11.5%] 🔴 +8.6% [+3.8%, +16.0%]
WolfSheep small 🔵 +1.9% [-0.9%, +4.6%] 🔵 +1.7% [+1.2%, +2.3%]
WolfSheep large 🔵 +0.8% [-11.6%, +12.7%] 🔵 +2.9% [+0.8%, +4.8%]
BoidFlockers small 🔵 +0.8% [+0.1%, +1.4%] 🔵 +1.4% [+1.1%, +1.7%]
BoidFlockers large 🔵 +4.5% [+2.2%, +7.0%] 🔵 +1.9% [+1.4%, +2.3%]

@falloficarus22
Copy link
Copy Markdown
Contributor Author

I now get asyncio.exceptions.CancelledError. Does it run locally for you, and, if so, can you elaborate on how you are testing it?

I am currently testing the visualization using pytest combined with solara.render.
In Solara and Reacton, asyncio.CancelledError should actually be normal and expected behavior. When a user clicks "Reset" or "Pause," Solara cancels the previous simulation task and (if resetting) starts a new one. I'm not totally sure about this and I would like to get some help on this.
For now I will explicitly catch and handle these silently.

@quaquel
Copy link
Copy Markdown
Member

quaquel commented Feb 12, 2026

I had a closer look at this and I know what is going on. First, revert your last commit. Errors should never be past over in silence. Also, it is not the root cause of the problem

My problem now happens when I hit reset. This trigger indirectly solara_viz._get_scenario_defaults. Here , we try to reconstruct the Scenario instance partly based on model_parameters. This dict is populated based on the UI sliders. And so includes the rng slider. However, rng is not included in _scenario_defaults, so it is not included when creating the scenario instance and instead is kept as part of model_parameters.

The solution is to change how we recreate the scenario instance in _build_model_init_kwargs.

for example

        for key, value in model_parameters.items():
            if key == 'rng':
                scenario_kwargs['key'] = value
            elif key in scenario_defaults and key not in model_init_params:
                scenario_kwargs[key] = value
            else:
                kwargs[key] = value

fixes the problem. This is clearly hacky, but it shows that my diagnosis is correct. A slightly more elabore solution is to change _get_scenario_defaults:

def _get_scenario_defaults(scenario: Scenario) -> dict[str, Any]:
    """Return defaults for a scenario instance, validating scenario type."""
    scenario_class = type(scenario)
    if not issubclass(scenario_class, Scenario):
        raise ValueError(
            "Expected model.scenario to be a subclass instance of mesa.experimental.scenarios.Scenario."
        )
    defaults = getattr(scenario, "_scenario_defaults", {})
    defaults['rng'] = None

    return defaults

)


def _screenshot_first_image(page, attempts=3, wait_ms=100):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is going on with these new functions? How is this relevant to the scenario issue? If it is not relevant, please consider submitting it as a separate pr

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry these were not meant to be pushed (Might have messed up while checking out with uncommitted changes)

@quaquel
Copy link
Copy Markdown
Member

quaquel commented Feb 12, 2026

It works now on my end. I will give the code another quick check, but it seems we are almost there.

@pytest.mark.skip(
reason="Requires interactive Solara state handling; covered indirectly."
)
def test_reset_with_scenario():
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that you skip this, but you might want to test _build_model_init_kwargs. It would have helped in finding the bug.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay I'll replace the skipped test with a concrete _build_model_init_kwargs test

@falloficarus22
Copy link
Copy Markdown
Contributor Author

It works now on my end. I will give the code another quick check, but it seems we are almost there.

Thank you for the help!

@EwoutH
Copy link
Copy Markdown
Member

EwoutH commented Feb 12, 2026

Great to see the progress!

I would like to also have @Sahil-Chhoker’s take on it.

@quaquel
Copy link
Copy Markdown
Member

quaquel commented Feb 14, 2026

I have tested this locally and can confirm it works. I am merging this PR, and we'll see if #3167 also works. @Sahil-Chhoker, I would still appreciate your thoughts even post-merge.

@quaquel quaquel merged commit c3efc86 into mesa:main Feb 14, 2026
13 of 14 checks passed
@EwoutH EwoutH added enhancement Release notes label visualisation and removed bug Release notes label labels Feb 14, 2026
@EwoutH
Copy link
Copy Markdown
Member

EwoutH commented Feb 14, 2026

Thanks for this effort, glad to see it merged!

@EwoutH EwoutH added the experimental Release notes label label Feb 14, 2026
@falloficarus22 falloficarus22 deleted the solara-viz-scenarios branch February 15, 2026 02:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Release notes label experimental Release notes label visualisation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Scenarios in Visualization

3 participants