Skip to content

Commit

Permalink
add cameraSetting (#34)
Browse files Browse the repository at this point in the history
viewer.cameraSetting = {"direction": [0, 2, 1], "zoom": 0.8}
  • Loading branch information
superstar54 committed Mar 4, 2024
1 parent b138419 commit 5390c05
Show file tree
Hide file tree
Showing 17 changed files with 158 additions and 92 deletions.
4 changes: 2 additions & 2 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
sphinx_rtd_theme==1.2.2
nbsphinx==0.9.2
sphinx_rtd_theme==2.0.0
nbsphinx==0.9.3
ipython
ase
2 changes: 1 addition & 1 deletion docs/source/color.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Supported style are:


Color by attribute
----------------
----------------------
Coloring based on the attribute of the atoms. The attribute can be: charge, magmom, or any other attribute in the structure.

Here we show how to color the atoms by their forces.
Expand Down
9 changes: 4 additions & 5 deletions js/widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// clone the weas repo and import the weas module
// import * as weas from "../../weas/src/index.js";
// if not, then use the release version from unpkg
import * as weas from "https://unpkg.com/[email protected]a/dist/weas.mjs";
import * as weas from "https://unpkg.com/[email protected]b/dist/weas.mjs";
import "./widget.css";


Expand Down Expand Up @@ -60,7 +60,9 @@ function render({ model, el }) {
avr.showVectorField = model.get("showVectorField")
// mesh primitives
avr.meshPrimitive.fromSettings(model.get("meshPrimitives"));

// camera settings
const cameraSetting = model.get("cameraSetting");
avr.tjs.updateCameraAndControls(cameraSetting);
avr.drawModels();
avr.render();
return avr;
Expand All @@ -86,9 +88,6 @@ function render({ model, el }) {
case "downloadImage":
avr.tjs.downloadImage(task.kwargs.filename);
break;
case "setCameraPosition":
avr.tjs.updateCameraAndControls(avr.atoms.getCenterOfGeometry(), task.kwargs.position);
break;
}
}
run_task(task);
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "weas_widget"
version = "0.0.13"
version = "0.0.14"
description = "A widget to visualize and interact with atomistic structures in Jupyter Notebook."
authors = [{name = "Xing Wang", email = "[email protected]"}]
readme = "README.md"
Expand Down
16 changes: 3 additions & 13 deletions src/weas_widget/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class WeasWidget(anywidget.AnyWidget):
meshPrimitives = tl.List(tl.Dict({})).tag(sync=True)
# viewer
viewerStyle = tl.Dict({}).tag(sync=True)
# camera
cameraSetting = tl.Dict({}).tag(sync=True)
# task
js_task = tl.Dict({}).tag(sync=True)
debug = tl.Bool(False).tag(sync=True)
Expand Down Expand Up @@ -147,16 +149,12 @@ def download_image(self, filename="weas-model.png"):
}
)

def save_image(
self, filename="weas-model.png", resolutionScale=5, camera_position=None
):
def save_image(self, filename="weas-model.png", resolutionScale=5):
import base64

def _save_image():
while not self.ready:
time.sleep(0.1)
if camera_position is not None:
self.camera_position = camera_position
self.export_image(resolutionScale)
# polling mechanism to check if the image data is available
while not self.imageData:
Expand All @@ -169,11 +167,3 @@ def _save_image():

thread = threading.Thread(target=_save_image, args=(), daemon=False)
thread.start()

@property
def camera_position(self):
return self._camera_position

@camera_position.setter
def camera_position(self, value):
self.send_js_task({"name": "setCameraPosition", "kwargs": {"position": value}})
2 changes: 1 addition & 1 deletion tests/notebooks/playwright.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const baseConfig = require('@jupyterlab/galata/lib/playwright-config');

module.exports = {
...baseConfig,
timeout: 120000,
timeout: 180000,
webServer: {
command: 'jlpm start',
url: 'http://localhost:8888/lab',
Expand Down
211 changes: 144 additions & 67 deletions tests/notebooks/tests/notebooks/widgets.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -2,80 +2,100 @@
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "07e050d2d9f44bd6bbeaaf477a1891ef",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"WeasWidget(atomScales=[1, 1, 1, 1, 1, 1, 1, 1, 1, 1], atoms={'species': {'S': ['S', 16], 'O': ['O', 8], 'C': […"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"outputs": [],
"source": [
"# guiConfig and viewerStyle\n",
"# Disable the GUI entirely.\n",
"import warnings\n",
"warnings.filterwarnings('ignore')\n",
"# load a molecule from ASE and display it in the weas widget\n",
"from ase.build import molecule\n",
"from weas_widget import WeasWidget\n",
"atoms = molecule(\"C2H6SO\")\n",
"viewer = WeasWidget(guiConfig={\"enabled\": False}, viewerStyle = {\"width\": \"800px\", \"hight\": \"600px\"})\n",
"viewer.from_ase(atoms)\n",
"viewer.modelStyle = 1\n",
"viewer\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Select specific components\n",
"# load a molecule from ASE and display it in the weas widget\n",
"from ase.build import molecule\n",
"from weas_widget import WeasWidget\n",
"atoms = molecule(\"C2H6SO\")\n",
"guiConfig={\"enabled\": True,\n",
" \"components\": {\"atomsControl\": True,\n",
" \"buttons\": True},\n",
" \"buttons\": {\"fullscreen\": True,\n",
" \"download\": True,\n",
" \"measurement\": True,\n",
" }\n",
" }\n",
"viewer = WeasWidget(guiConfig=guiConfig)\n",
"viewer.from_ase(atoms)\n",
"viewer.modelStyle = 1\n",
"viewer\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Camera settings\n",
"from ase.build import molecule\n",
"from weas_widget import WeasWidget\n",
"atoms = molecule(\"C2H6SO\")\n",
"viewer = WeasWidget()\n",
"viewer.from_ase(atoms)\n",
"viewer.modelStyle = 1\n",
"viewer.cameraSetting = {\"center\": [5, 1, 1], \"direction\": [0, 2, 1], \"zoom\": 0.8}\n",
"viewer\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Color settings\n",
"# ColorBy attribute\n",
"from ase.build import molecule\n",
"from weas_widget import WeasWidget\n",
"atoms = molecule(\"C2H6SO\")\n",
"viewer = WeasWidget()\n",
"viewer.from_ase(atoms)\n",
"viewer.modelStyle = 1\n",
"viewer.colorBy = \"Index\"\n",
"viewer.colorRamp = [\"red\", \"yellow\", \"blue\"]\n",
"viewer\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Atoms(symbols='SOC2H6', pbc=False)"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"outputs": [],
"source": [
"# export the structure to a ASE atoms object\n",
"viewer.to_ase()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "7d14f0ab0233415ebeefa11ba6ce23d8",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"WeasWidget(atomScales=[1, 1, 1, 1, 1, 1], atoms={'species': {'Ti': ['Ti', 22], 'O': ['O', 8]}, 'cell': [4.6532…"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"outputs": [],
"source": [
"# Crystal\n",
"# For a nice visualization of a crystal, one usually shows the polyhedra and the atoms on the unit cell boundary, as well as the bonded atoms outside the cell.\n",
Expand All @@ -96,25 +116,33 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "3125928d3347407bbec7a395d5ea5ede",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"WeasWidget(atomScales=[1, 1, 1, 1, 1, 1, 1, 1], atoms={'species': {'Fe': ['Fe', 26]}, 'cell': [5.74, 0.0, 0.0,…"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"outputs": [],
"source": [
"# Isurface\n",
"from weas_widget import WeasWidget\n",
"import requests\n",
"from io import StringIO\n",
"from ase.io.cube import read_cube_data\n",
"url = \"https://raw.githubusercontent.com/superstar54/weas/main/demo/datas/h2o-homo.cube\"\n",
"response = requests.get(url)\n",
"file_content = response.text\n",
"# Use StringIO to simulate a file-like object for ASE to read from\n",
"file_like_object = StringIO(file_content)\n",
"volume, atoms = read_cube_data(file_like_object)\n",
"viewer = WeasWidget()\n",
"viewer.from_ase(atoms)\n",
"viewer.volumetricData = {\"values\": volume}\n",
"viewer.isoSettings = [{\"isovalue\": 0.0001, \"mode\": 0}]\n",
"viewer"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Vector Field\n",
"# Magnetic moment\n",
Expand All @@ -128,9 +156,58 @@
"atoms.set_array(\"moment\", np.ones(len(atoms)))\n",
"viewer = WeasWidget()\n",
"viewer.from_ase(atoms)\n",
"viewer.cameraSetting = {\"direction\": [0, -1, 0]}\n",
"viewer.modelStyle = 1\n",
"viewer"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Mesh Primitive\n",
"from weas_widget import WeasWidget\n",
"viewer = WeasWidget()\n",
"data = [\n",
" {\n",
" \"type\": \"cube\",\n",
" \"data\": [\n",
" {\n",
" \"position\": [-5, 0, 0],\n",
" \"size\": 2,\n",
" \"scale\": [1, 0.5, 1],\n",
" \"rotation\": [0, 0, 0]\n",
" },\n",
" {\n",
" \"position\": [5, 0, 1],\n",
" \"size\": 1,\n",
" \"scale\": [1, 0.5, 1],\n",
" \"rotation\": [1, 1, 0],\n",
" \"color\": \"#bd0d87\"\n",
" }\n",
" ]\n",
" },\n",
" {\n",
" \"type\": \"cylinder\",\n",
" \"data\": [\n",
" {\n",
" \"position\": [0, 0, 0],\n",
" \"segments\": 12,\n",
" \"radius\": 1,\n",
" \"depth\": 5,\n",
" \"scale\": [1, 1, 1],\n",
" \"rotation\": [0, 0, 0],\n",
" \"color\": \"#0d87bd\"\n",
" }\n",
" ]\n",
" },\n",
"]\n",
"\n",
"viewer.meshPrimitives = data\n",
"viewer"
]
}
],
"metadata": {
Expand Down
4 changes: 2 additions & 2 deletions tests/notebooks/tests/widgets.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ test.describe('Widget Visual Regression', () => {

await page.notebook.runCellByCell({
onAfterCellRun: async (cellIndex: number) => {
// wait 2 seconds for the widget to render
await page.waitForTimeout(2000);
// wait 3 seconds for the widget to render
await page.waitForTimeout(3000);
const cell = await page.notebook.getCellOutput(cellIndex);
if (cell) {
captures.push(await cell.screenshot());
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 5390c05

Please sign in to comment.