Skip to content

pwinston/webmon

Repository files navigation

webmon

Written in December 2020 for the Octree/Async work in napari.

Webmon is three things:

  1. An experimental napari shared memory client.
  2. A proof of concept Flask-SocketIO webserver.
  3. An example web app that contains two pages:
    • /viewer a three.js (WebGL) display of what tiles are visible in napari.
    • /loader with three Vega-Lite graphs related to the ChunkLoader.

See the lengthy napari PR 1909 for more information.

Screenshots

Web app has two pages Tile Viewer and Loader Stats:

Tile Viewer

The Tile Viewer is shown on left. On right is napari. The tile viewer shows which Octree/Quadtree tiles are currently being viewed by napari. The yellow rectangle is the view frustum, and the red tiles are the ones napari is drawing.

tiles

Loader Stats

The Loader Stats are three 2D Vega-Lite graphs:

graphs

Overview

There is a shared memory connection between napari (Python) and the small webmon process (Python). And there is an always-on WebSocket connection between webmon (Python) and the web app (Javascript). Messages can flow through both hops at 30-60Hz. Obviously there is some limit to the message size before things bog down. Limit is TBD.

Requirements

Python

  • Python 3.9
    • Newest shared memory features were first added in Python 3.8.
    • However 3.8 seemed to have bugs, where 3.9 works.
  • In webmon directory: pip3 install -r requirements.txt

Javascript

  • Install node/npm
    • Not sure of min req but on MacOS I've been using:
    • node -v -> v14.3.0
    • npm -v -> 6.14.4
  • In webmon directory: make build

socket io version

Something we are using is not compatible with latest socketio version. So we need to stay in this red box. Our npm and Python requirements.txt should configure this for you. However, if you get this error The client is using an unsupported version of the Socket.IO or Engine.IO protocols the WebUI will not talk to webmon until you fix the dependencies.

socketio

Making Changes

Python

  • webmon.py and napari_client.py are pretty immature and need work.

Long term it would be nice if the Python part was pretty generic. So to add new WebUI you only had to modify napari to share the data and then modify the WebUI to show the data. And the Python parts just pass data around without caring what the data is about. We are heading in that direction, but not there yet.

HTML

Javascript

  • Do not edit .js files under static.
    • .json files in static are fair game.
  • Edit .js files under js then build as above.
  • If you made a Javascript-only change:
    • make build
    • Typically hard reload (shift-command-R) in Chrome is enough.
    • Typically do not need to restart napari/webmon unless you changed those.

Vega-Lite

  • We are using Vega-Lite for viz.
  • You can modify the .json files in static/specs.

What Can I Do?

  • Issues and PR's needed.
    • Update this README if you were stuck on something.
    • Or if you found useful resources for learning.
  • Modify existing pages or create new ones.
    • Use tailwindcss and Vega-Lite more fully.
    • Use other styles/packages/modules beyond those.
  • Modify napari to share more things.
    • Try sharing numpy data backed by a shared memory buffer.
    • Create a system so we only share data if a client is asking for it.
  • Modify napari so the WebUI can control more things.

How To Add A Page

  1. In webmon.py add an entry to the pages list like:

    pages = [ "viewer", "loader", "my_new_page" ]

  2. In build.js add your .js file for the page:

    entryPoints: [ 'src/viewer.js', 'src/loader.js', 'src/my_new_page.js' ],

  3. Add your new js/src/my_new_page.js and templates/my_new_page.html.

FAQ

NAPARI_MON is starting two copies of napari?

If you are using your own script to launch napari, make sure you are using the convention:

if __name__ == "__main__":
    main()

By default SharedMemoryManager uses fork(). Fork will start your process a second time. Only this time __name__ will not be set to "__main__".

Your code and napari's code should not do anything on import-time that it's not safe do a second time. The main flow the application should only come from a guarded main() call.

The SharedMemoryManager forks the main process so it can start a little manager process that will talk to remote clients. This second process wants the same overall context of the first process, but it runs a little server of some sort, it does not want to run napari itself.

What is this error:

An attempt has been made to start a new process before the
current process has finished its bootstrapping phase.

Probably the same __main__ problem as above. Napari ran a second time, which created SharedMemoryMonitor a second time, which forked a second time. A fork loop basically.

Dask Dashboard

The Dask Dashboard design is very similar to webmon. It's also a localhost website that you connect to, which has tabs along the top, and the tabs show graphs and other visualizations. Theirs is much more advanced. Here is Dask Dashboard on the left from this video and webmon on the right:

Dask Dashboard

They use Bokeh where we use Vega-Lite. It looks like Bokeh might be better for streaming data. There is a Python server you can get which talks to the Javscript front end.

Future Work

Beyond messages, the Big Kahuna would be using shared memory buffers to back numpy arrays and recarrays. Then we could share large chunks of binary data. Throughput limits are not known yet. Particularly the Websocket hop might be the slow part. This has not been attempted yet. If the websocket hop is the slow part, could an Electron process be a shared memory client, and then directly render the data? TBD.

References

Please add more references if you found them useful.

Tailwind CSS

Vega-Lite

Python Shared Memory

tweet

Webmon was originally derived from

  • FlaskTest
    • A simple demo that combines Flask, Socket-IO, and three.js/WebGL

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors