{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import panel as pn\n", "import pyvista as pv\n", "from pyvista import examples\n", "pn.extension('vtk', sizing_mode=\"stretch_width\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For this example we use the pyvista library to load a dataset and generate easily a VTK scene" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m = examples.download_st_helens().warp_by_scalar()\n", "\n", "# default camera position\n", "cpos = [(567000.9232163235, 5119147.423216323, 6460.423216322832),\n", " (562835.0, 5114981.5, 2294.5),\n", " (-0.4082482904638299, -0.40824829046381844, 0.8164965809277649)]\n", "\n", "# pyvista plotter\n", "pl = pv.Plotter(notebook=True);\n", "actor = pl.add_mesh(m, smooth_shading=True, lighting=True)\n", "pl.camera_position = cpos #set camera position\n", "\n", "# save initial camera properties\n", "renderer = list(pl.ren_win.GetRenderers())[0]\n", "initial_camera = renderer.GetActiveCamera()\n", "initial_camera_pos = {\"focalPoint\": initial_camera.GetFocalPoint(),\n", " \"position\": initial_camera.GetPosition(),\n", " \"viewUp\": initial_camera.GetViewUp()}\n", "\n", "# Panel creation using the VTK Scene created by the plotter pyvista\n", "orientation_widget = True\n", "enable_keybindings = True\n", "vtkpan = pn.panel(pl.ren_win, sizing_mode='stretch_both', orientation_widget=orientation_widget,\n", " enable_keybindings=enable_keybindings, height=600)\n", "vtkpan" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "WidgetBox with colorbars and actor selection" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Creation of a mapping between Custom name and the VTK object reference\n", "actor_ref = [\"None\", actor.__this__]\n", "actor_names = [\"None\", 'St Helen']\n", "actor_opts = {k:v for k,v in zip(actor_names, actor_ref)}\n", "\n", "options = {}\n", "actor_selection = pn.widgets.Select(value=None, options = actor_opts , name=\"Actor Selection\")\n", "actor_selection" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "WidgetBoxes with general parameters of the vtk Scene (Widgets, Background, Lights,...)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Scene Layout\n", "scene_props = pn.WidgetBox()\n", "bind_and_orient = pn.widgets.CheckBoxGroup(value=['Orientation Widget', 'Key Bindings'], options=['Orientation Widget', 'Key Bindings']) #initialisation => coherence with panel params\n", "reset_camera = pn.widgets.Button(name='Reset Camera')\n", "background_color = pn.widgets.ColorPicker(value=''.join(['#'] + ['{:02x}'.format(int(v*255)) for v in pl.background_color]),\n", " name='Background Color')\n", "[scene_props.append(w) for w in [bind_and_orient, reset_camera, background_color]]\n", "\n", "# Light properties\n", "light_props = pn.WidgetBox()\n", "light_box_title = pn.widgets.StaticText(value='Light properties')\n", "light_type = pn.widgets.Select(value='HeadLight', options=['HeadLight','SceneLight','CameraLight'])\n", "light_intensity = pn.widgets.FloatSlider(start=0, end=1, value=1, name=\"Intensity\")\n", "\n", "\n", "[light_props.append(w) for w in [light_box_title, light_type, light_intensity]]\n", "pn.Row(scene_props, light_props)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "WidgetBox with properties of the Actors" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#layout actor props\n", "actor_props = pn.WidgetBox()\n", "opacity = pn.widgets.FloatSlider(value=1, start=0, end=1, name='Opacity', disabled=True)\n", "lighting = pn.widgets.Toggle(value=True, name='Lighting', disabled=True)\n", "interpolation = pn.widgets.Select(value='Phong', options=['Flat','Phong'], name='Interpolation', disabled=True)\n", "edges = pn.widgets.Toggle(value=False, name='Show Edges', disabled=True)\n", "edges_color = pn.widgets.ColorPicker(value='#ffffff', name='Edges Color', disabled=True)\n", "representation = pn.widgets.Select(value='Surface', options=['Points','Wireframe','Surface'], name='Representation', disabled=True)\n", "frontface_culling = pn.widgets.Toggle(value=False, name='Frontface Culling', disabled=True)\n", "backface_culling = pn.widgets.Toggle(value=False, name='Backface Culling', disabled=True)\n", "ambient = pn.widgets.FloatSlider(value=0, start=-1, end=1, name='Ambient', disabled=True)\n", "diffuse = pn.widgets.FloatSlider(value=1, start=0, end=2, name='Diffuse', disabled=True)\n", "specular = pn.widgets.FloatSlider(value=0, start=0, end=10, name='Specular', disabled=True)\n", "specular_power = pn.widgets.FloatSlider(value=100, start=0, end=100, name='Specular Power', disabled=True)\n", "[actor_props.append(w) for w in [opacity, lighting, interpolation, edges, edges_color,\n", " representation,frontface_culling,backface_culling, ambient,\n", " diffuse, specular, specular_power]]\n", "actor_props" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Linking all widgets together using jslinks" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Linking\n", "light_type.jslink(vtkpan, code={'value':\"\"\"\n", "const light = target.renderer_el.getRenderer().getLights()[0]\n", "if (source.value == 'HeadLight')\n", " light.setLightTypeToHeadLight()\n", "else if (source.value == 'CameraLight')\n", " light.setLightTypeToCameraLight()\n", "else if (source.value == 'SceneLight')\n", " light.setLightTypeToSceneLight()\n", "target.renderer_el.getRenderWindow().render()\n", "\"\"\"})\n", "\n", "light_intensity.jslink(vtkpan, code={'value':\"\"\"\n", "const light = target.renderer_el.getRenderer().getLights()[0]\n", "light.setIntensity(source.value)\n", "target.renderer_el.getRenderWindow().render()\n", "\"\"\"})\n", "\n", "\n", "bind_and_orient.jslink(vtkpan, code = {'active':\"\"\"\n", "target.orientation_widget = source.active.includes(0)\n", "target.enable_keybindings = source.active.includes(1)\n", "\"\"\"})\n", "\n", "reset_camera.js_on_click(args={'target': vtkpan, 'initial_camera':initial_camera_pos},\n", " code=\"target.camera = initial_camera\");\n", "\n", "background_color.jslink(vtkpan, code={'value':\"\"\"\n", "const hextoarr = (color) => {return [parseInt(color.slice(1,3),16)/255, parseInt(color.slice(3,5),16)/255, parseInt(color.slice(5,7),16)/255]}\n", "target.renderer_el.getRenderer().setBackground(hextoarr(source.color))\n", "target.renderer_el.getRenderWindow().render()\n", "\"\"\"});\n", "\n", "opacity.jscallback(args={\"target\":vtkpan, \"actor_selection\":actor_selection}, value=\"\"\"\n", "if (actor_selection.value!=\"None\"){\n", " const actor = target.getActors(actor_selection.value)[0]\n", " actor.getProperty().setOpacity(source.value)\n", " target.renderer_el.getRenderWindow().render()\n", "}\n", "\"\"\")\n", "\n", "lighting.jscallback(args={\"target\":vtkpan, \"actor_selection\":actor_selection}, value=\"\"\"\n", "if (actor_selection.value!=\"None\"){\n", " const actor = target.getActors(actor_selection.value)[0]\n", " actor.getProperty().setLighting(source.active)\n", " target.renderer_el.getRenderWindow().render()\n", "}\n", "\"\"\")\n", "\n", "edges.jscallback(args={\"target\":vtkpan, \"actor_selection\":actor_selection}, value=\"\"\"\n", "if (actor_selection.value!=\"None\"){\n", " const actor = target.getActors(actor_selection.value)[0]\n", " actor.getProperty().setEdgeVisibility(source.active)\n", " target.renderer_el.getRenderWindow().render()\n", "}\n", "\"\"\")\n", "\n", "interpolation.jscallback(args={\"target\":vtkpan, \"actor_selection\":actor_selection}, value=\"\"\"\n", "if (actor_selection.value!=\"None\"){\n", " const actor = target.getActors(actor_selection.value)[0]\n", " if(source.value==\"Flat\"){\n", " actor.getProperty().setInterpolationToFlat()\n", " }else{\n", " actor.getProperty().setInterpolationToPhong()\n", " }\n", " target.renderer_el.getRenderWindow().render()\n", "}\n", "\"\"\")\n", "\n", "edges_color.jscallback(args={\"target\":vtkpan, \"actor_selection\":actor_selection}, value=\"\"\"\n", "if (actor_selection.value!=\"None\"){\n", " const hextoarr = (color) => {return [parseInt(color.slice(1,3),16)/255, parseInt(color.slice(3,5),16)/255, parseInt(color.slice(5,7),16)/255]}\n", " const actor = target.getActors(actor_selection.value)[0]\n", " actor.getProperty().setEdgeColor(hextoarr(source.color))\n", " target.renderer_el.getRenderWindow().render()\n", "}\n", "\"\"\")\n", "\n", "representation.jscallback(args={\"target\":vtkpan, \"actor_selection\":actor_selection}, value=\"\"\"\n", "if (actor_selection.value!=\"None\"){\n", " const actor = target.getActors(actor_selection.value)[0]\n", " if(source.value==\"Points\"){\n", " actor.getProperty().setRepresentationToPoints()\n", " }else if(source.value==\"Wireframe\"){\n", " actor.getProperty().setRepresentationToWireframe()\n", " }else if(source.value==\"Surface\"){\n", " actor.getProperty().setRepresentationToSurface()\n", " }\n", " target.renderer_el.getRenderWindow().render()\n", "}\n", "\"\"\")\n", "\n", "frontface_culling.jscallback(args={\"target\":vtkpan, \"actor_selection\":actor_selection}, value=\"\"\"\n", "if (actor_selection.value!=\"None\"){\n", " const actor = target.getActors(actor_selection.value)[0]\n", " actor.getProperty().setFrontfaceCulling(source.active)\n", " target.renderer_el.getRenderWindow().render()\n", "}\n", "\"\"\")\n", "\n", "backface_culling.jscallback(args={\"target\":vtkpan, \"actor_selection\":actor_selection}, value=\"\"\"\n", "if (actor_selection.value!=\"None\"){\n", " const actor = target.getActors(actor_selection.value)[0]\n", " actor.getProperty().setBackfaceCulling(source.active)\n", " target.renderer_el.getRenderWindow().render()\n", "}\n", "\"\"\")\n", "\n", "ambient.jscallback(args={\"target\":vtkpan, \"actor_selection\":actor_selection}, value=\"\"\"\n", "if (actor_selection.value!=\"None\"){\n", " const actor = target.getActors(actor_selection.value)[0]\n", " actor.getProperty().setAmbient(source.value)\n", " target.renderer_el.getRenderWindow().render()\n", "}\n", "\"\"\")\n", "\n", "diffuse.jscallback(args={\"target\":vtkpan, \"actor_selection\":actor_selection}, value=\"\"\"\n", "if (actor_selection.value!=\"None\"){\n", " const actor = target.getActors(actor_selection.value)[0]\n", " actor.getProperty().setDiffuse(source.value)\n", " target.renderer_el.getRenderWindow().render()\n", "}\n", "\"\"\")\n", "\n", "specular.jscallback(args={\"target\":vtkpan, \"actor_selection\":actor_selection}, value=\"\"\"\n", "if (actor_selection.value!=\"None\"){\n", " const actor = target.getActors(actor_selection.value)[0]\n", " actor.getProperty().setSpecular(source.value)\n", " target.renderer_el.getRenderWindow().render()\n", "}\n", "\"\"\")\n", "\n", "specular_power.jscallback(args={\"target\":vtkpan, \"actor_selection\":actor_selection}, value=\"\"\"\n", "if (actor_selection.value!=\"None\"){\n", " const actor = target.getActors(actor_selection.value)[0]\n", " actor.getProperty().setSpecularPower(source.value)\n", " target.renderer_el.getRenderWindow().render()\n", "}\n", "\"\"\")\n", "\n", "actor_selection.jslink(target=vtkpan, code = {'value' : \"\"\"\n", "if (source.value!=\"None\"){\n", " const actor = target.getActors(source.value)[0]\n", " target.outline.setInputData(actor.getMapper().getInputData())\n", " target.renderer_el.getRenderer().addActor(target.outline_actor)\n", " \n", " //synchronize actor props and widgets values\n", " const properties = actor.getProperty()\n", " opacity.setv({value: properties.getOpacity()}, {silent: true})\n", " lighting.setv({active: !!properties.getLighting()}, {silent: true})\n", " edges.active = !!properties.getEdgeVisibility()\n", " const actor_color = \"#\" + properties.getEdgeColor().map((c) => (\"0\" + Math.round(255*c).toString(16,2)).slice(-2)).join('')\n", " edges_color.setv({color: actor_color}, {silent: true})\n", " const interp_string = properties.getInterpolationAsString()\n", " interpolation.setv({value: interp_string[0] + interp_string.slice(1).toLocaleLowerCase()}, {silent: true})\n", " const repr_string = properties.getRepresentationAsString()\n", " representation.setv({value: repr_string[0] + repr_string.slice(1).toLocaleLowerCase()}, {silent: true})\n", " frontface_culling.setv({active: !!properties.getFrontfaceCulling()}, {silent: true})\n", " backface_culling.setv({active: !!properties.getBackfaceCulling()}, {silent: true})\n", " ambient.setv({value: properties.getAmbient()}, {silent: true})\n", " diffuse.setv({value: properties.getDiffuse()}, {silent: true})\n", " specular.setv({value: properties.getSpecular()}, {silent: true})\n", " specular_power.setv({value: properties.getSpecularPower()}, {silent: true})\n", " //enable widgets modifications\n", " opacity.disabled = false\n", " lighting.disabled = false\n", " interpolation.disabled = false\n", " edges.disabled = false\n", " edges_color.disabled = false\n", " representation.disabled = false\n", " frontface_culling.disabled = false\n", " backface_culling.disabled = false\n", " ambient.disabled = false\n", " diffuse.disabled = false\n", " specular.disabled = false\n", " specular_power.disabled = false\n", "} else {\n", " target.renderer_el.getRenderer().removeActor(target.outline_actor)\n", " opacity.disabled = true\n", " lighting.disabled = true\n", " interpolation.disabled = true\n", " edges.disabled = true\n", " edges_color.disabled = true\n", " representation.disabled = true\n", " frontface_culling.disabled = true\n", " backface_culling.disabled = true\n", " ambient.disabled = true\n", " diffuse.disabled = true\n", " specular.disabled = true\n", " specular_power.disabled = true\n", "}\n", "target.renderer_el.getRenderWindow().render()\n", "\n", "\"\"\"}, args={\"opacity\":opacity, \"lighting\":lighting, \"interpolation\": interpolation, \"edges\": edges, \"edges_color\": edges_color,\n", " \"representation\": representation, \"frontface_culling\": frontface_culling, \"backface_culling\": backface_culling,\n", " \"ambient\": ambient, \"diffuse\": diffuse, \"specular\": specular, \"specular_power\": specular_power});\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Display all together" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "settings = pn.Column(actor_selection,pn.Tabs(('Scene controller', pn.Column(scene_props, light_props)), ('Actor properties',actor_props)))\n", "pn.Row(vtkpan, settings)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## App\n", "\n", "Lets wrap it into nice template that can be served via `panel serve VTKInteractive.ipynb`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "description=\"This example demonstrates the use of **VTK and pyvista** to display a *scene*\"\n", "pn.template.FastListTemplate(site=\"Panel\", title=\"VTK Interactive\", sidebar=[settings], main=[description, vtkpan]).servable();" ] } ], "metadata": { "language_info": { "name": "python", "pygments_lexer": "ipython3" } }, "nbformat": 4, "nbformat_minor": 4 }