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

Simplify solara code #1786

Merged
merged 2 commits into from
Sep 1, 2023
Merged

Simplify solara code #1786

merged 2 commits into from
Sep 1, 2023

Conversation

Corvince
Copy link
Contributor

@Corvince Corvince commented Aug 31, 2023

Over the past weeks, I've had the opportunity to delve into the Solara frontend and experiment with different ideas. A big thank you to @rht for laying the foundation of the Solara frontend.

I'm experimenting with exciting concepts for the frontend and am eager to incorporate my React knowledge.

However, with this PR, my primary aim is to streamline the codebase before introducing any additional modifications.

At present, the frontend code is organized across three functions/classes:

  • JupyterContainer: This contains model control functions, grid plotting features, and logic to segregate model parameters into fixed and user-configurable ones.
  • MesaComponent: This establishes user-configurable controls, sets up the model, contains some model control functions, performs JupyterContainer manipulations, and holds the plotting logic.
  • JupyterViz: This Solara component essentially returns the MesaComponent and initiates the Container.

I've reorganized and simplified the structure. Now, JupyterViz stands as the primary component, managing user input (subject to further enhancement in an upcoming PR), initializing the model, and handling the plotting logic. The model control has been externalized to a separate component named ModelController.

While this PR might seem extensive, it's mainly due to the code repositioning to achieve a more intuitive flow. The actual modifications are minimal. Key changes include:

  • Removal of FigureMatplotlib dependencies. Presently, we're free from unnecessary re-renders, so this optimization isn't required.
  • Elimination of df from the container. Previously, I believe this was used to trigger re-renders. Now, we track the current step to achieve this. This approach also supports models without a data collector and is essential for upcoming enhancements to the model controller.
  • The split_model_params function has been made top-level and devoid of side effects.

I think that sums it up.

@codecov
Copy link

codecov bot commented Aug 31, 2023

Codecov Report

Patch coverage: 11.36% and project coverage change: -0.44% ⚠️

Comparison is base (ea4b213) 80.02% compared to head (0c0b1f1) 79.58%.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1786      +/-   ##
==========================================
- Coverage   80.02%   79.58%   -0.44%     
==========================================
  Files          15       15              
  Lines         881      877       -4     
  Branches      188      188              
==========================================
- Hits          705      698       -7     
- Misses        155      158       +3     
  Partials       21       21              
Files Changed Coverage Δ
mesa/experimental/jupyter_viz.py 15.26% <11.36%> (-4.74%) ⬇️

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@Corvince
Copy link
Contributor Author

Just to give some perspective on what "future improvements" from my side are already locally implemented (for testing, need more polishing)

  • Use more components => All the make_* functions can and should be converted to solara components (reuseability)
  • Run models using use_thread hook - this works on its own, but matplotlib is not thread-safe, so the line-plots crash (much simpler code, but needs some investigating)
  • Move all the input parameter logic into its own component (challenge how to trigger re-initializing of the model)
  • Some layout/styling improvements

self.model_params_fixed[k] = v

@solara.component
def JupyterViz(
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, this is simpler. The reason why I split into JupyterContainer, MesaComponent, and JupyterViz was the answer to these questions on Discord:

The question:

Is it possible to do just

model_params = {
    "N": {
        "type": "SliderInt",
        "value": 50,
        "label": "Number of agents:",
        "min": 10,
        "max": 100,
        "step": 1,
    },
    "width": 10,
    "height": 10,
}
JupyterViz(
    BoltzmannWealthModel, model_params, measures=["Gini"], name="Money Model"
)

The answer,

@rht you can also assign to page = MesaComponent(...) but they you would have to reverse your model, so JupyterViz shouldn't call MesaComponent, but the other way around

This was the reason for the MesaComponent and JupyterViz split. But in hindsight, the split wasn't necessary.

This was the reason for the JupyterContainer split: https://discord.com/channels/1106593685241614489/1106593686223069309/1123583246307954828.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, the power of hindsight... but still quite impressive to make it work with all the necessary basic features! Solara uses quite a different paradigm, so not everything is clear from the beginning


def do_step():
model.step()
set_current_step(model.schedule.steps)

def do_play(self):
Copy link
Contributor

Choose a reason for hiding this comment

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

This still has self.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed

self.model.running = True
while self.model.running:
model.running = True
while model.running:
self.do_step()

def threaded_do_play(self):
Copy link
Contributor

Choose a reason for hiding this comment

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

This shouldn't have self.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, removed

@rht
Copy link
Contributor

rht commented Aug 31, 2023

Removal of FigureMatplotlib dependencies. Presently, we're free from unnecessary re-renders, so this optimization isn't required.
Elimination of df from the container. Previously, I believe this was used to trigger re-renders. Now, we track the current step to achieve this. This approach also supports models without a data collector and is essential for upcoming enhancements to the model controller.

In this PR, only solara.Markdown(md_text=f"**Step:** {current_step}") has a dependency to current_step, but not the FigureMatplotlib's. How are they notified of the step change then?

@@ -9,48 +8,72 @@

import mesa

# Avoid interactive backend
plt.switch_backend("agg")
Copy link
Contributor

Choose a reason for hiding this comment

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

This was added so that user code that does the pyplot interface (plt.plot, etc) can still work, even though not recommended.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ah, makes sense. I reverted the change

@Corvince
Copy link
Contributor Author

Corvince commented Sep 1, 2023

Removal of FigureMatplotlib dependencies. Presently, we're free from unnecessary re-renders, so this optimization isn't required.
Elimination of df from the container. Previously, I believe this was used to trigger re-renders. Now, we track the current step to achieve this. This approach also supports models without a data collector and is essential for upcoming enhancements to the model controller.

In this PR, only solara.Markdown(md_text=f"**Step:** {current_step}") has a dependency to current_step, but not the FigureMatplotlib's. How are they notified of the step change then?

Ah, I think you got the dependency list of FigureMatplotlib backwards. In Solara, when the state changes (here: current_step), the component and every child component is re-rendered. So we don't need to notify FigureMatplotlib explicitly to update the plot. Only if we dont want it to redraw we can add a dependency list and only if the values of the dependency list change a new figure is drawn. But even without a dependency change it technically still re-renders, but uses the old (cached) image.

@rht
Copy link
Contributor

rht commented Sep 1, 2023

I see, that makes sense. I will merge now.

@rht rht merged commit fb81c1a into main Sep 1, 2023
@rht rht deleted the solara-simplify branch September 1, 2023 07:49
@rht
Copy link
Contributor

rht commented Sep 1, 2023

Forgot to mention that the visualization tutorial needs to be updated ASAP before the release (see https://mesa.readthedocs.io/en/stable/tutorials/visualization_tutorial.html). I can't do this within the next few days, and so, @ankitk50, if you have the time to do it, it would be great.

@ankitk50
Copy link
Contributor

Hi all, I started working on updating this tutorial. I get the following error while rendering the page:

Failed to load model class 'SheetModel' from module 'jupyter-vuetify'
makeError@http://localhost:8889/static/components/requirejs/require.js?v=d37b48bb2137faa0ab98157e240c084dd5b1b5e74911723aa1d1f04c928c2a03dedf922d049e4815f7e5a369faa2e6b6a1000aae958b7953b5cc60411154f593:168:26

Are we aware of this issue or I'm missing some config ?

@rht
Copy link
Contributor

rht commented Sep 22, 2023

@ankitk50 I had already fixed the issue (#1792) because we wanted to release sooner. You should look for other issue instead. #1741 seems to be a low-hanging fruit.

@ankitk50
Copy link
Contributor

Thanks @rht, everything looked in order to me. Although I cannot get rid of the Jupyter notebook error. The error does not show on colab, so I use it for now.

@rht
Copy link
Contributor

rht commented Sep 23, 2023

I don't recommend using Colab to develop for long term. You have to fix your local env problem soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants