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

Anywidget #44

Merged
merged 45 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
e186de2
removing cookiecutter code: /js
justinlaughlin Feb 8, 2024
53bca50
removing cookiecutter code: other
justinlaughlin Feb 8, 2024
85958df
removing cookiecutter code: more misc
justinlaughlin Feb 8, 2024
b6896b8
update copyright year
justinlaughlin Feb 8, 2024
734a424
initial widget
justinlaughlin Feb 8, 2024
6ceb59c
fixing bug due to oudated function arguments of 'display' and 'update…
justinlaughlin Feb 8, 2024
31d75c1
initial commit of basic python class
justinlaughlin Feb 8, 2024
f5f14e2
renamed src to glvis
justinlaughlin Feb 9, 2024
47312c5
__init__.py
justinlaughlin Feb 9, 2024
f94e8ac
minimal pyproject.toml
justinlaughlin Feb 9, 2024
cb9fe0b
fixed path for js import into widget.py
justinlaughlin Feb 9, 2024
017bf51
changing glvis->pyglvis and class glvis to class Glvis
justinlaughlin Feb 9, 2024
8309447
update pyproject.toml
justinlaughlin Feb 9, 2024
5638a35
added init to python class. Also created a wrapper class so that API …
justinlaughlin Feb 9, 2024
44accd0
Updating pyproject.toml. Wrapper class uses _repr_mimebundle_ propert…
justinlaughlin Feb 9, 2024
0b17fd5
removing data_type as it is no longer used in display() and update() …
justinlaughlin Feb 9, 2024
dcb3af9
cleanup
justinlaughlin Feb 10, 2024
e763390
moved Glvis.widget to __init__ and made it a private property so that…
justinlaughlin Feb 10, 2024
992201e
adding in plot() and update()
justinlaughlin Feb 10, 2024
6838269
on_msg
justinlaughlin Feb 10, 2024
921f38d
'keys' kwarg in widget
justinlaughlin Mar 5, 2024
c9140e3
removing unnecessary postBuild commands for binder
justinlaughlin Mar 5, 2024
bf0bd63
return module name from pyglvis -> glvis
justinlaughlin Mar 5, 2024
9e62a2a
update module import names
justinlaughlin Mar 5, 2024
ea7365d
update examples to work with new class
justinlaughlin Mar 5, 2024
b1fe9a2
add glvis.render()
justinlaughlin Mar 5, 2024
bf2e5db
update readme, badges (anywidget branch) and api calls
justinlaughlin Mar 5, 2024
c885a09
removing a lot from README since many installation/development phases…
justinlaughlin Mar 5, 2024
690369c
change readme to recommend using simpler pip install for mfem
justinlaughlin Jun 18, 2024
181d772
remove unnecessary white space
justinlaughlin Jun 20, 2024
8436ec3
fix keys (should just append keys directly to string)
justinlaughlin Jun 20, 2024
15b089b
remove more whitespace
justinlaughlin Jun 20, 2024
d4f549b
lots of changes and cleanup in README.md file
justinlaughlin Jun 20, 2024
d890810
Add demo gifs to README.md
justinlaughlin Jun 20, 2024
9a790a1
add copyright statement back into source files
justinlaughlin Jun 24, 2024
22e4247
use different key string if stream vs Mesh/GridFunction object
justinlaughlin Jun 24, 2024
b51df1e
use 'keys' keyword in basic.ipynb
justinlaughlin Jun 24, 2024
1ddd3b5
update docstrings and change glvis() to be an aliased constructor whi…
justinlaughlin Jun 25, 2024
1954aa1
delete package-lock.json
justinlaughlin Jun 25, 2024
86d3051
update anywidget dependency from 0.9.0[dev] to 0.9.9 (need repr_mimeb…
justinlaughlin Jun 25, 2024
872a23a
add try/except to mfem imports, bump version
justinlaughlin Jun 25, 2024
767a12f
more lax import for pymfem
justinlaughlin Jun 25, 2024
6ba5116
use gh instead of npm for esm
justinlaughlin Aug 16, 2024
6b90110
Update README.md
justinlaughlin Aug 20, 2024
f3d4b06
Update __about__.py
justinlaughlin Aug 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .binder/postBuild
Original file line number Diff line number Diff line change
@@ -1,6 +1,2 @@
# install this
pip install .

# install jupyter-lab extension
jupyter labextension install @jupyter-widgets/jupyterlab-manager --no-build
jupyter labextension install glvis-jupyter
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
BSD 3-Clause License

Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC
Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC
All rights reserved.

Redistribution and use in source and binary forms, with or without
Expand Down
2 changes: 0 additions & 2 deletions MANIFEST.in

This file was deleted.

235 changes: 99 additions & 136 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,197 +1,152 @@
# Interactive GLVis Jupyter Widget
# PyGLVis

<!-- Badges generated at https://mybinder.readthedocs.io/en/latest/howto/badges.html -->
[![badge](examples/basic.svg "Basic GLVis + Jupyter Example")](https://mybinder.org/v2/gh/GLVis/pyglvis/HEAD?filepath=examples%2Fbasic.ipynb)
[![badge](examples/plot.svg "Plot grid functions")](https://mybinder.org/v2/gh/GLVis/pyglvis/HEAD?filepath=examples%2Fplot.ipynb)
[![badge](examples/ex1.svg "MFEM's Example 1")](https://mybinder.org/v2/gh/GLVis/pyglvis/HEAD?filepath=examples%2Fex1.ipynb)
[![badge](examples/ex9.svg "MFEM's Example 9")](https://mybinder.org/v2/gh/GLVis/pyglvis/HEAD?filepath=examples%2Fex9.ipynb)
[![badge](examples/basic.svg "Basic GLVis + Jupyter Example")](https://mybinder.org/v2/gh/GLVis/pyglvis/anywidget?filepath=examples%2Fbasic.ipynb)
[![badge](examples/plot.svg "Plot grid functions")](https://mybinder.org/v2/gh/GLVis/pyglvis/anywidget?filepath=examples%2Fplot.ipynb)
[![badge](examples/ex1.svg "MFEM's Example 1")](https://mybinder.org/v2/gh/GLVis/pyglvis/anywidget?filepath=examples%2Fex1.ipynb)
[![badge](examples/ex9.svg "MFEM's Example 9")](https://mybinder.org/v2/gh/GLVis/pyglvis/anywidget?filepath=examples%2Fex9.ipynb)

This repository contains a [Jupyter](https://jupyter.org/) widget for the [GLVis](https://glvis.org/) finite element
visualization tool based on the [glvis-js](https://github.com/GLVis/glvis-js) JavaScript/WebAssembly library.
PyGLVis is an interactive [Jupyter](https://jupyter.org/) widget for visualizing finite element meshes and functions, built on-top of the [GLVis](https://glvis.org/) library.

## Usage
## 📦 Installation

```python
from glvis import glvis
The GLVis Jupyter widget is installed using `pip`. To install the latest version from the repository:

glvis(data[, width=640, height=480])
```bash
git clone https://github.com/GLVis/pyglvis.git
cd pyglvis
pip install .
```

# or assign if you want to update later
g = glvis(data)
# run a cell with `g` to show it
g
Or, install directly from PyPi,
```bash
pip install glvis
```

The `data` object and be one of:
PyGLVis requires the Python wrapper for MFEM, [PyMFEM](https://github.com/mfem/pymfem), which can be installed with
```bash
pip install mfem
```

- a `str`, in the format of `*.saved` files
- a `Mesh`, defined in [PyMFEM](https://github.com/mfem/pymfem)
- a `(Mesh, GridFunction)` tuple, defined in [PyMFEM](https://github.com/mfem/pymfem)

[PyMFEM](https://github.com/mfem/pymfem) can be installed with `pip install mfem --no-binary mfem`.

## 🚀 Usage

### Basic usage

Once you have a `glvis` object there are a few methods that can used to update the
visualization:
```python
# show a new Mesh/GridFunction, resets keys
g.plot(data)
# show an updated visualization with the same `Mesh` and `GridFunction`
# dimensions, preserves keys
g.update(data)
# change the image size
g.set_size(width, height)
# force the widget to render. if the widget isn't the last statement in a cell it
# will not be shown without this. see ex9.ipynb
g.render()
```
from glvis import glvis

See the [examples](examples/) directory for additional examples. To test those locally, start a Jupyter notebook server with
# Create a `glvis` object
g = glvis(data, width=640, height=480)

# Run a cell with `g` as the last statement to display the widget
g
```
jupyter notebook
```

## Installation

The GLVis Jupyter widget can be simply installed with `pip`:

```
pip install glvis
```
The `data` object can be one of:

It order for the installation to be useful you must enable the extension for one or both
of the [Classic Notebook](https://jupyter-notebook.readthedocs.io/en/stable/) and
[Jupyter Lab](https://jupyterlab.readthedocs.io/en/stable/), see the next two sections:
- `Mesh`, defined in [PyMFEM](https://github.com/mfem/pymfem)
- `(Mesh, GridFunction)` tuple, defined in [PyMFEM](https://github.com/mfem/pymfem)
- `str`, in the format of `*.saved` files [used by MFEM and GLVis](https://mfem.org/mesh-format-v1.0/). See [examples/basic.ipynb](examples/basic.ipynb) for an example.

### Jupyter Notebook
### Customization with key commands

To use the widget with the basic Notebook enable it with `jupyter nbextension enable`:
GLVis has many keyboard commands that can be used to customize the visualization.
A few of the most common are listed below. See the [GLVis README](https://github.com/GLVis/glvis?tab=readme-ov-file#key-commands) for a full list.
- `r` - reset the view
- `c` - toggle the colorbar
- `j` - toggle perspective
- `l` - toggle the light
- `g` - toggle the background color (white/black)
- `a` - cycle through bounding box axes states
- `m` - cycle through mesh states
- `p` - cycle through color palettes
- `t` - cycle through materials and lights
- `0` - begin rotating around z-axis
- `.` - pause rotation
- `*`/`/` - zoom in/out

These can be set using the `keys` argument when creating a `glvis` object.
```python
glvis(data, keys='rljgac//0')
```
jupyter nbextension enable --py glvis
```

After enabling the extension you can verify you're good to go with:
This combination of keys would: `r` reset the view, `l` toggle the light, `j` toggle perspective, `g` toggle the background color to black (default is white), `a` show the bounding box, `c` show the colorbar, `//` zoom out twice, and `0` begin rotating around the z-axis:

```
jupyter nbextension list
```
![pyglvis_preset_keys](https://github.com/GLVis/pyglvis/assets/27717785/de0e0a99-72ac-4a88-8369-708515600b09)

The output should be something like:
Alternatively, keys can be typed directly into the widget after it has been created:

```
Known nbextensions:
config dir: path/to/nbconfig
notebook section
glvis-jupyter/extension enabled
- Validating: OK
<possibly a different config dir>
jupyter-js-widgets/extension enabled
- Validating: OK
```
![pyglvis_using_keys](https://github.com/GLVis/pyglvis/assets/27717785/625f4f06-8f99-4390-94d7-4d317fd11e7f)

If `glvis-jupyter` and `jupyter-js-widgets` are not both listed, try the following:
### Other methods

Once you have a `glvis` object there are a few methods that can used to update the
visualization, besides using keys:
```python
# Show a new Mesh/GridFunction, resets keys
g.plot(data)
# Show an updated visualization with the same data, preserving keys
g.update(data)
# Change the image size
g.set_size(width, height)
# Force the widget to render. If the widget isn't the last statement in a cell it
# will not be shown without this. See ex9.ipynb
g.render()
```
jupyter nbextension install --user --py glvis
jupyter nbextension enable --user --py glvis
jupyter nbextension install --user --py widgetsnbextension
jupyter nbextension enable --user --py widgetsnbextension
```
You may also need to run these if you have upgraded to a newer version of the GLVis Jupyter widget.

### Jupyter Lab

[JupyterLab](https://jupyterlab.readthedocs.io) requires another set of install commands:
See the [examples](examples/) directory for additional examples. To test those locally, start a Jupyter lab server with

```
jupyter labextension install @jupyter-widgets/jupyterlab-manager --no-build
jupyter labextension install glvis-jupyter
jupyter lab
```

## Development

Development installation requires `npm`.
## 🐛 Troubleshooting

If you want to test a new version of `glvis`:
This widget was originally developed using the [jupyter widget cookiecutter](https://github.com/jupyter-widgets/widget-cookiecutter); however, [recent changes to the Jupyter ecosystem](https://jupyter-notebook.readthedocs.io/en/latest/migrate_to_notebook7.html#why-a-new-version) have broken a lot of functionality, leading to a rewrite using [anywidget](https://anywidget.dev/). If you encounter any problems, please consider supporting development by opening an [issue](https://github.com/GLVis/pyglvis/issues).

1. Bump the version in _pyglvis/js/package.json_ and _glvis-js/package.json_
2. `npm install path/to/glvis-js`


Each time you update stuff in _pyglvis/js/src_:
## 🤖 Development

1. `npm install`
2. `npx webpack`


Once:
### PyGLVis dependencies

```mermaid
graph TD;
A[mfem] --> B[pymfem];
A --> C[glvis];
C --> D[glvis-js];
Ext1[emscripten] --> D;
D-.-E["glvis-js\n(npm/esm mirror)"]
B & E --> G[pyglvis];
Ext2[jupyter] --> G;
```
git clone https://github.com/glvis/pyglvis.git
cd pyglvis
pip install -e .
```

### Developing in Jupyter Notebook
`pyglvis` is most directly depednent on `PyMFEM` and `glvis-js`. [PyMFEM](https://github.com/mfem/pymfem) is a Python wrapper of the finite element library, `MFEM`, while `glvis-js` is a JavaScript/WebAssembly port of `glvis`.

`glvis-js` is hosted on [github](https://github.com/glvis/glvis-js) and mirrored on [npm](https://www.npmjs.com/package/glvis). [esm.sh](https://esm.sh/glvis) allows `pyglvis` to pull the latest version of `glvis-js` directly from npm. This can be seen in the first line of [glvis/widget.js](glvis/widget.js):

```
jupyter nbextension install --py --symlink --sys-prefix glvis
jupyter nbextension enable --py --sys-prefix glvis
import glvis from "https://esm.sh/glvis";
```

### Developing in Jupyter Lab
You can specify a different version of `glvis-js` by adding `@x.y.z` to the end of this import statement, where `x.y.z` matches a version number available on `npm`, e.g.

```bash
jupyter labextension install @jupyter-widgets/jupyterlab-manager --no-build
# I believe you need node in the path Lab uses for this to work, I see an extension load error
# in a context where I don't have it:
# Failed to load resource: the server responded with a status of 500 (Internal Server Error)
# lab/api/extensions?1610138347763
# Which is just a python stacktrace, ending with:
# raise ValueError(msg)
# ValueError: Please install Node.js and npm before continuing installation.
jupyter labextension link ./js
```


### Troubleshooting

If you run into errors related to node/npm that aren't helpful try:

```bash
cd pyglvis
make clean
cd js
# fix errors in these steps, run `make -C .. clean` each time
npm install
npx webpack
import glvis from "https://esm.sh/glvis@0.6.3";
```

## Releasing

### Releasing a new version of glvis-jupyter on NPM:
### Releasing a new version of glvis on NPM:

- Update the required version of `glvis` in `js/package.json`
To publish a new version of `glvis-js`, follow the instructions on the [repo](https://github.com/GLVis/glvis-js/tree/master).

- Update the version in `js/package.json`

```bash
# clean out the `dist` and `node_modules` directories
git clean -fdx
npm install
npm publish
```

### Releasing a new version of glvis on PyPI:

- Update `glvis/_version.py`
- Set release version
- Update `extension_version` to match `js/package.json`
- Update `__version__` in `glvis/__about__.py`

- `git add` and `git commit` changes
- `glvis/_version.py`, `js/package.json`, and `js/package-lock.js`


You will need [twine](https://pypi.org/project/twine/) to publish to PyPI, install with `pip`.
Expand All @@ -202,3 +157,11 @@ twine upload dist/*
git tag -a X.X.X -m 'comment'
git push --tags
```


## 🌐 Links
- MFEM ([website](https://mfem.org/), [github](https://github.com/mfem/mfem))
- PyMFEM ([github](https://github.com/mfem/pymfem), [pypi](https://pypi.org/project/mfem/))
- GLVis ([website](https://glvis.org/), [github](https://github.com/glvis/glvis))
- glvis-js ([github](https://github.com/glvis/glvis-js), [npm](https://www.npmjs.com/package/glvis), [esm](https://esm.sh/glvis))
- pyglvis ([github](https://github.com/GLVis/pyglvis), [pypi]())
2 changes: 1 addition & 1 deletion examples/basic.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"outputs": [],
"source": [
"# Another vsualization instance of the same stream\n",
"glvis(stream + 'rljg****tttac0', 300, 300)"
"glvis(stream, 300, 300, keys='rljg****tttac0')"
]
}
],
Expand Down
24 changes: 15 additions & 9 deletions examples/ex1.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"metadata": {
"tags": []
},
"source": [
"## MFEM Example 1\n",
"\n",
Expand Down Expand Up @@ -39,12 +41,14 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"# Requires PyMFEM, see https://github.com/mfem/PyMFEM\n",
"import mfem.ser as mfem\n",
"from glvis import glvis, to_stream"
"from glvis import glvis"
]
},
{
Expand Down Expand Up @@ -107,11 +111,14 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"# Plot the mesh + solution (all GLVis keys and mouse commands work)\n",
"glvis((mesh, x), 400, 400)"
"g=glvis((mesh, x))\n",
"g"
]
},
{
Expand All @@ -131,15 +138,14 @@
"outputs": [],
"source": [
"# Visualization with additional GLVis keys\n",
"g = glvis(to_stream(mesh,x) + 'keys ARjlmcbp*******')\n",
"g.set_size(600, 400)\n",
"g = glvis((mesh,x), keys='ARjlmcbp*******')\n",
"g"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
Expand All @@ -153,7 +159,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.1"
"version": "3.10.12"
}
},
"nbformat": 4,
Expand Down
Loading