├── .codespellignore ├── .codespellrc ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.md │ ├── config.yml │ └── feature-request.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── auto-approve.yml │ ├── doc.yml │ ├── docker.yaml │ ├── reviewdog.yml │ └── update-pr-branch.yml ├── .gitignore ├── .pre-commit-config.yaml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── README.md ├── SECURITY.md ├── doc ├── .gitignore ├── Makefile ├── ironProt.vtk ├── make.bat └── source │ ├── .gitignore │ ├── _static │ ├── cards.css │ ├── copybutton.css │ ├── fontawesome │ │ ├── LICENSE.txt │ │ ├── css │ │ │ └── all.css │ │ └── webfonts │ │ │ ├── fa-brands-400.eot │ │ │ ├── fa-brands-400.svg │ │ │ ├── fa-brands-400.ttf │ │ │ ├── fa-brands-400.woff │ │ │ ├── fa-brands-400.woff2 │ │ │ ├── fa-regular-400.eot │ │ │ ├── fa-regular-400.svg │ │ │ ├── fa-regular-400.ttf │ │ │ ├── fa-regular-400.woff │ │ │ ├── fa-regular-400.woff2 │ │ │ ├── fa-solid-900.eot │ │ │ ├── fa-solid-900.svg │ │ │ ├── fa-solid-900.ttf │ │ │ ├── fa-solid-900.woff │ │ │ └── fa-solid-900.woff2 │ ├── no_search_highlight.css │ ├── pyvista_banner.png │ ├── pyvista_banner_small.png │ ├── pyvista_ipython_demo.mp4 │ ├── pyvista_jupyterlab_demo.mp4 │ ├── pyvista_logo.png │ ├── pyvista_logo_sm.png │ ├── pyvista_logo_sm_sq.png │ └── table.css │ ├── conf.py │ ├── getting-started.rst │ ├── images │ ├── action │ │ ├── AeroSandbox.png │ │ ├── Duoprism_3-30.gif │ │ ├── air_racing_optimization.png │ │ ├── anvil_cirrus_plumes.png │ │ ├── atmospheric_convection.jpeg │ │ ├── boolean_marching_cubes.png │ │ ├── coil_field_lines.png │ │ ├── comet_fenicsx.png │ │ ├── damavand_volcano.gif │ │ ├── discretize.png │ │ ├── drilldown.jpg │ │ ├── felupe.png │ │ ├── flem.png │ │ ├── forge.png │ │ ├── geemap.gif │ │ ├── gemgis.png │ │ ├── geovista_earth.png │ │ ├── gmsh_model.png │ │ ├── grad_descent_visualizer.gif │ │ ├── griddip.gif │ │ ├── nikolov1.gif │ │ ├── nikolov2.gif │ │ ├── nikolov3.gif │ │ ├── omfvista.png │ │ ├── open-foam.png │ │ ├── optimization.gif │ │ ├── orvisu.gif │ │ ├── ptera_software.gif │ │ ├── pvgeo.png │ │ ├── pyelastica.gif │ │ ├── pyfbs.webp │ │ ├── pymeshfix.png │ │ ├── stpyvista_intro_crop.gif │ │ ├── sunkit-pyvista.png │ │ ├── tetgen.png │ │ ├── vessel_vio.png │ │ └── visualpic.png │ ├── gifs │ │ ├── .gitignore │ │ ├── box-clip.gif │ │ ├── documentation.gif │ │ ├── dynamic_flask.gif │ │ ├── line-widget-streamlines.gif │ │ ├── multiple-checkbox-widget.gif │ │ ├── multiple-slider-widget.gif │ │ ├── plane-clip.gif │ │ ├── plane-glyph.gif │ │ ├── plane-slice-continuous.gif │ │ ├── plane-slice.gif │ │ ├── scalar-bar-interactive.gif │ │ ├── shrink-globe.gif │ │ ├── single-checkbox-widget.gif │ │ ├── slider-widget-resolution.gif │ │ ├── slider-widget-threshold.gif │ │ ├── sphere-widget-a.gif │ │ ├── sphere-widget-b.gif │ │ ├── sphere-widget-c.gif │ │ └── spline-widget.gif │ ├── jupyter.png │ ├── trame-pyvista.png │ └── user-generated │ │ ├── .gitkeep │ │ ├── femorph-qt.png │ │ ├── qt_multiplot.png │ │ └── qt_plotting_sphere.png │ ├── index.rst │ ├── locales │ └── .gitkeep │ ├── make_external_gallery.py │ └── tutorial.rst ├── pyproject.toml ├── requirements.txt ├── start └── tutorial ├── 00_intro ├── README.rst └── a_basic.py ├── 00_jupyter ├── README.rst └── jupyter.py ├── 01_basic ├── README.rst ├── a_lesson_basic.py ├── exercises │ ├── README.rst │ └── a_load_examples_exercise.py ├── ironProt.vtk └── solutions │ ├── P_shelf_pin.stl │ ├── README.rst │ └── a_load_examples_solution.py ├── 02_mesh ├── README.rst ├── a_lesson_mesh.py ├── exercises │ ├── README.rst │ ├── b_create-point-cloud.py │ ├── c_create-uniform-grid.py │ ├── d_create-tri-surface.py │ └── e_read-file.py ├── scipy.vtk └── solutions │ ├── README.rst │ ├── b_create-point-cloud.py │ ├── c_create-uniform-grid.py │ ├── d_create-tri-surface.py │ └── e_read-file.py ├── 03_figures ├── README.rst ├── a_lesson_figures.py ├── b_shading.py ├── bonus │ ├── README.rst │ ├── d_pbr.py │ ├── e_labels.py │ └── g_orbit.py ├── c_geological-map.py ├── d_gif.py ├── exercises │ ├── README.rst │ ├── a_display_options.py │ ├── b_lighting_mesh.py │ └── c_edl.py └── solutions │ ├── README.rst │ ├── a_display_options.py │ ├── b_lighting_mesh.py │ └── c_edl.py ├── 04_filters ├── README.rst ├── a_lesson_filters.py ├── bonus │ ├── README.rst │ └── f_sampling_functions_3d.py ├── exercises │ ├── README.rst │ ├── b_clipping.py │ ├── c_compute-normals.py │ ├── d_contouring.py │ └── e_glyphs.py └── solutions │ ├── README.rst │ ├── b_clipping.py │ ├── c_compute-normals.py │ ├── d_contouring.py │ └── e_glyphs.py ├── 05_action ├── LICENSE └── README.rst ├── 06_vtk ├── README.rst ├── a_1_transition_vtk.py ├── a_2_pyvista_vtk.py ├── b_create_vtk.py ├── c_vtk_algorithms.py ├── d_wasm.py └── e_vtk_next.py ├── 07_sphinx └── README.rst ├── 08_widgets ├── README.rst ├── a_box-widget.py ├── b_checkbox-widget.py ├── c_line-widget.py ├── d_multi-slider-widget.py ├── e_plane-widget.py ├── f_slider-bar-widget.py ├── g_sphere-widget.py └── h_spline-widget.py └── 09_trame ├── README.rst ├── a_getting_started.py ├── a_trame_simple.py ├── b_trame_actor_color.py ├── b_trame_vtk.py ├── c_trame_scalars.py ├── d_trame_scalar_range.py ├── e_trame_algorithm.py └── f_trame_open_file.py /.codespellignore: -------------------------------------------------------------------------------- 1 | flem 2 | FLEM 3 | -------------------------------------------------------------------------------- /.codespellrc: -------------------------------------------------------------------------------- 1 | [codespell] 2 | skip = *.svg 3 | ignore-words = .codespellignore 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Create a report to help us fix broken features 4 | title: "" 5 | labels: bug 6 | assignees: "" 7 | --- 8 | 9 | **Describe the bug, what's wrong, and what you expect:** 10 | 11 | A clear and concise description of what the bug is. 12 | 13 | A clear and concise description of what you expected to happen. 14 | 15 | --- 16 | 17 | **To Reproduce** 18 | 19 | Please include a code snippet to reproduce the bug in the block below: 20 | 21 | ```py 22 | # Insert code here 23 | 24 | ``` 25 | 26 | **Screenshots** 27 | If applicable, add screenshots to help explain your problem. 28 | 29 | --- 30 | 31 | **System Information:** 32 | Please run the following code wherever you are experiencing the bug and paste the output below. This report helps us track down bugs and it is critical to addressing your bug: 33 | 34 | ```py 35 | # Get system info 36 | import pyvista as pv 37 | print(pv.Report()) 38 | ``` 39 | 40 | ```txt 41 | # Paste system info here 42 | 43 | ``` 44 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | contact_links: 2 | - name: Questions and Discussions 3 | url: https://github.com/pyvista/pyvista-tutorial/discussions 4 | about: For general questions and discussions 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Request that a feature be added to pyvista-tutorial 4 | title: "" 5 | labels: enhancement 6 | assignees: "" 7 | --- 8 | 9 | **Describe what feature you would like added.** 10 | 11 | A clear and concise description of what you would like added. 12 | 13 | If you are requesting a feature from PyVista document, please include links to the PyVista document, example, or class definition. 14 | 15 | Feel free to include pseudocode or screenshots of the requested outcome. 16 | 17 | --- 18 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Overview 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ### Details 10 | 11 | - < feature1 or bug1 description > 12 | - < feature2 or bug2 description > 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "pip" 4 | directory: "/" 5 | insecure-external-code-execution: allow 6 | schedule: 7 | interval: "monthly" 8 | open-pull-requests-limit: 100 9 | groups: 10 | trame: 11 | patterns: 12 | - "trame" 13 | - "trame-*" 14 | - package-ecosystem: "docker" 15 | directory: "/" 16 | schedule: 17 | interval: "monthly" 18 | open-pull-requests-limit: 100 19 | - package-ecosystem: "github-actions" 20 | directory: "/" 21 | schedule: 22 | interval: "daily" 23 | open-pull-requests-limit: 100 24 | labels: 25 | - "maintenance" 26 | - "dependencies" 27 | -------------------------------------------------------------------------------- /.github/workflows/auto-approve.yml: -------------------------------------------------------------------------------- 1 | name: Approve PRs 2 | on: 3 | workflow_dispatch: 4 | issue_comment: 5 | types: [created] 6 | 7 | jobs: 8 | autoapprove: 9 | # This job only runs for pull request comments by approved users on creation 10 | name: PR comment 11 | if: github.event.issue.pull_request && 12 | contains(github.event.comment.body, '@pyvista-bot LGTM') && ( 13 | github.event.comment.user.login == 'banesullivan' || 14 | github.event.comment.user.login == 'tkoyama010' || 15 | github.event.comment.user.login == 'akaszynski' 16 | ) 17 | permissions: 18 | pull-requests: write 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: hmarr/auto-approve-action@v4 22 | with: 23 | review-message: ":white_check_mark: Approving this PR because [${{ github.event.comment.user.login }}](https://github.com/${{ github.event.comment.user.login }}) said so in [here](${{ github.event.comment.html_url }}) :shipit:" 24 | pull-request-number: ${{ github.event.issue.number }} 25 | github-token: ${{ secrets.GITHUB_TOKEN }} 26 | -------------------------------------------------------------------------------- /.github/workflows/docker.yaml: -------------------------------------------------------------------------------- 1 | name: Build Docker Image 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | tags: 7 | - "*" 8 | branches: 9 | - main 10 | pull_request: 11 | 12 | env: 13 | REGISTRY: ghcr.io 14 | IMAGE_NAME: ${{ github.repository }} 15 | 16 | jobs: 17 | build-docker: 18 | permissions: 19 | packages: write 20 | pull-requests: read 21 | issues: read 22 | repository-projects: read 23 | runs-on: ubuntu-latest 24 | if: 25 | github.event_name == 'push' || github.event_name == 'workflow_dispatch' || 26 | ( github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository ) 27 | steps: 28 | - uses: actions/checkout@v4 29 | with: 30 | persist-credentials: false 31 | - name: Log into the Container registry 32 | uses: docker/login-action@v3 33 | with: 34 | registry: ${{ env.REGISTRY }} 35 | username: token 36 | password: ${{ secrets.GITHUB_TOKEN }} 37 | - name: Extract metadata for the Jupyter Docker image 38 | id: meta 39 | uses: docker/metadata-action@v5 40 | with: 41 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 42 | - name: Build and push the Jupyter Docker image 43 | uses: docker/build-push-action@v6 44 | with: 45 | context: . 46 | file: Dockerfile 47 | push: ${{ github.actor != 'dependabot[bot]' && github.actor != 'pre-commit-ci[bot]' }} 48 | tags: ${{ steps.meta.outputs.tags }} 49 | labels: ${{ steps.meta.outputs.labels }} 50 | -------------------------------------------------------------------------------- /.github/workflows/reviewdog.yml: -------------------------------------------------------------------------------- 1 | name: reviewdog 2 | on: [pull_request] 3 | jobs: 4 | misspell: 5 | name: runner / misspell 6 | permissions: 7 | pull-requests: read 8 | issues: read 9 | repository-projects: read 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Check out code. 13 | uses: actions/checkout@v4 14 | with: 15 | persist-credentials: false 16 | - name: misspell 17 | uses: reviewdog/action-misspell@v1 18 | with: 19 | github_token: ${{ secrets.github_token }} 20 | locale: "US" 21 | pattern: "*.md" 22 | -------------------------------------------------------------------------------- /.github/workflows/update-pr-branch.yml: -------------------------------------------------------------------------------- 1 | name: PR update 2 | 3 | on: 4 | push: 5 | branches: 6 | - "main" 7 | jobs: 8 | autoupdate: 9 | permissions: 10 | pull-requests: write 11 | issues: read 12 | repository-projects: read 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Automatically update PR 16 | uses: adRise/update-pr-branch@v0.10.1 17 | with: 18 | token: ${{ secrets.GITHUB_TOKEN }} 19 | base: "main" 20 | required_approval_count: 1 21 | require_passed_checks: false 22 | sort: "created" 23 | direction: "desc" 24 | require_auto_merge_enabled: true 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .venv 2 | **/*.DS_Store 3 | **/*.ipynb_checkpoints 4 | 5 | doc/source/images/auto-generated/* 6 | node_modules/ 7 | .vscode/ 8 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/codespell-project/codespell 3 | rev: v2.4.1 4 | hooks: 5 | - id: codespell 6 | args: ["doc tutorial", "*.py *.rst *.md"] 7 | 8 | - repo: https://github.com/pre-commit/pre-commit-hooks 9 | rev: v5.0.0 10 | hooks: 11 | - id: check-merge-conflict 12 | - id: debug-statements 13 | - id: no-commit-to-branch 14 | args: [--branch, main] 15 | - id: requirements-txt-fixer 16 | - id: trailing-whitespace 17 | exclude: ^(doc/source/_static/.*) 18 | - id: mixed-line-ending 19 | - id: end-of-file-fixer 20 | 21 | - repo: https://github.com/python-jsonschema/check-jsonschema 22 | rev: 0.33.0 23 | hooks: 24 | - id: check-github-workflows 25 | 26 | - repo: https://github.com/rbubley/mirrors-prettier 27 | rev: v3.5.3 28 | hooks: 29 | - id: prettier 30 | types_or: [yaml, markdown, html, css, scss, javascript, json] 31 | 32 | - repo: https://github.com/astral-sh/ruff-pre-commit 33 | rev: v0.11.13 34 | hooks: 35 | - id: ruff 36 | args: [--fix, --show-fixes] 37 | - id: ruff-format 38 | 39 | - repo: https://github.com/ComPWA/taplo-pre-commit 40 | rev: v0.9.3 41 | hooks: 42 | - id: taplo-format 43 | # See options: https://taplo.tamasfe.dev/configuration/formatter-options.html 44 | args: [--option, "reorder_arrays=true", --option, "reorder_keys=true"] 45 | 46 | - repo: https://github.com/woodruffw/zizmor-pre-commit 47 | rev: v1.5.2 48 | hooks: 49 | - id: zizmor 50 | 51 | - repo: https://github.com/sphinx-contrib/sphinx-lint 52 | rev: v1.0.0 53 | hooks: 54 | - id: sphinx-lint 55 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our 7 | project and our community a harassment-free experience for everyone, 8 | regardless of age, body size, disability, ethnicity, sex 9 | characteristics, gender identity and expression, level of experience, 10 | education, socioeconomic status, nationality, personal appearance, 11 | race, religion, or sexual identity and orientation. 12 | 13 | Please reference the contributing guide at [pyvista/CODE_OF_CONDUCT.md](https://github.com/pyvista/pyvista/blob/master/CODE_OF_CONDUCT.md) for additional details. 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We absolutely welcome contributions and we hope that this guide will 4 | facilitate an understanding of the PyVista code repository. It is 5 | important to note that the PyVista software package is maintained on a 6 | volunteer basis and thus we need to foster a community that can 7 | support user questions and develop new features to make this software 8 | a useful tool for all users. 9 | 10 | Please reference the contributing guide at [pyvista/CONTRIBUTING.rst](https://github.com/pyvista/pyvista/blob/master/CONTRIBUTING.rst) for contributing to this repository. 11 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG BASE_IMAGE_TAG=latest 2 | FROM ghcr.io/pyvista/pyvista:$BASE_IMAGE_TAG 3 | 4 | COPY . ${HOME} 5 | WORKDIR ${HOME} 6 | RUN pip install hypothesis lxml pyct rtree tqdm 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-2025 The PyVista Developers 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | [Security Policy](https://github.com/pyvista/pyvista/blob/main/SECURITY.md) 2 | -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | 22 | # remove the sphinx-gallery 23 | clean: 24 | rm -rf $(BUILDDIR)/* 25 | rm -rf source/tutorial/ 26 | rm -rf source/images/auto-generated 27 | 28 | # Spin up a local http server to view the rendered documentation. 29 | # This is required for interactive examples to work. 30 | serve-html: 31 | python -m http.server 11000 --directory "$(BUILDDIR)"/html 32 | -------------------------------------------------------------------------------- /doc/ironProt.vtk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/ironProt.vtk -------------------------------------------------------------------------------- /doc/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /doc/source/.gitignore: -------------------------------------------------------------------------------- 1 | tutorial/ 2 | errors.txt 3 | __pycache__ 4 | sg_execution_times.rst 5 | -------------------------------------------------------------------------------- /doc/source/_static/cards.css: -------------------------------------------------------------------------------- 1 | .pyvista-card-title { 2 | color: #459db9; 3 | font-style: normal; 4 | font-weight: 500 !important; 5 | font-size: 20px; 6 | text-align: center; 7 | } 8 | -------------------------------------------------------------------------------- /doc/source/_static/copybutton.css: -------------------------------------------------------------------------------- 1 | /* Copy buttons */ 2 | a.copybtn { 3 | position: absolute; 4 | top: 2px; 5 | right: 2px; 6 | width: 1em; 7 | height: 1em; 8 | padding: 0.3em; 9 | opacity: 0.3; 10 | transition: opacity 0.5s; 11 | } 12 | 13 | div.highlight { 14 | position: relative; 15 | } 16 | 17 | .highlight:hover .copybtn { 18 | opacity: 1; 19 | } 20 | 21 | /** 22 | * A minimal CSS-only tooltip copied from: 23 | * https://codepen.io/mildrenben/pen/rVBrpK 24 | * 25 | * To use, write HTML like the following: 26 | * 27 | *

Short

28 | */ 29 | .o-tooltip--left { 30 | position: relative; 31 | } 32 | 33 | .o-tooltip--left:after { 34 | opacity: 0; 35 | visibility: hidden; 36 | position: absolute; 37 | content: attr(data-tooltip); 38 | padding: 2px; 39 | top: 0; 40 | left: 0; 41 | background: grey; 42 | font-size: 1rem; 43 | color: white; 44 | white-space: nowrap; 45 | z-index: 2; 46 | border-radius: 2px; 47 | transform: translateX(-102%) translateY(0); 48 | transition: 49 | opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), 50 | transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); 51 | } 52 | 53 | .o-tooltip--left:hover:after { 54 | display: block; 55 | opacity: 1; 56 | visibility: visible; 57 | transform: translateX(-100%) translateY(0); 58 | transition: 59 | opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), 60 | transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); 61 | } 62 | -------------------------------------------------------------------------------- /doc/source/_static/fontawesome/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Font Awesome Free License 2 | ------------------------- 3 | 4 | Font Awesome Free is free, open source, and GPL friendly. You can use it for 5 | commercial projects, open source projects, or really almost whatever you want. 6 | Full Font Awesome Free license: https://fontawesome.com/license/free. 7 | 8 | # Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/) 9 | In the Font Awesome Free download, the CC BY 4.0 license applies to all icons 10 | packaged as SVG and JS file types. 11 | 12 | # Fonts: SIL OFL 1.1 License (https://scripts.sil.org/OFL) 13 | In the Font Awesome Free download, the SIL OFL license applies to all icons 14 | packaged as web and desktop font files. 15 | 16 | # Code: MIT License (https://opensource.org/licenses/MIT) 17 | In the Font Awesome Free download, the MIT license applies to all non-font and 18 | non-icon files. 19 | 20 | # Attribution 21 | Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font 22 | Awesome Free files already contain embedded comments with sufficient 23 | attribution, so you shouldn't need to do anything additional when using these 24 | files normally. 25 | 26 | We've kept attribution comments terse, so we ask that you do not actively work 27 | to remove them from files, especially code. They're a great way for folks to 28 | learn about Font Awesome. 29 | 30 | # Brand Icons 31 | All brand icons are trademarks of their respective owners. The use of these 32 | trademarks does not indicate endorsement of the trademark holder by Font 33 | Awesome, nor vice versa. **Please do not use brand logos for any purpose except 34 | to represent the company, product, or service to which they refer.** 35 | -------------------------------------------------------------------------------- /doc/source/_static/fontawesome/webfonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/fontawesome/webfonts/fa-brands-400.eot -------------------------------------------------------------------------------- /doc/source/_static/fontawesome/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/fontawesome/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /doc/source/_static/fontawesome/webfonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/fontawesome/webfonts/fa-brands-400.woff -------------------------------------------------------------------------------- /doc/source/_static/fontawesome/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/fontawesome/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /doc/source/_static/fontawesome/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/fontawesome/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /doc/source/_static/fontawesome/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/fontawesome/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /doc/source/_static/fontawesome/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/fontawesome/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /doc/source/_static/fontawesome/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/fontawesome/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /doc/source/_static/fontawesome/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/fontawesome/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /doc/source/_static/fontawesome/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/fontawesome/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /doc/source/_static/fontawesome/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/fontawesome/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /doc/source/_static/fontawesome/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/fontawesome/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /doc/source/_static/no_search_highlight.css: -------------------------------------------------------------------------------- 1 | /* No search term highlighting, see https://stackoverflow.com/a/48771802 */ 2 | span.highlighted { 3 | background-color: transparent; 4 | } 5 | -------------------------------------------------------------------------------- /doc/source/_static/pyvista_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/pyvista_banner.png -------------------------------------------------------------------------------- /doc/source/_static/pyvista_banner_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/pyvista_banner_small.png -------------------------------------------------------------------------------- /doc/source/_static/pyvista_ipython_demo.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/pyvista_ipython_demo.mp4 -------------------------------------------------------------------------------- /doc/source/_static/pyvista_jupyterlab_demo.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/pyvista_jupyterlab_demo.mp4 -------------------------------------------------------------------------------- /doc/source/_static/pyvista_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/pyvista_logo.png -------------------------------------------------------------------------------- /doc/source/_static/pyvista_logo_sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/pyvista_logo_sm.png -------------------------------------------------------------------------------- /doc/source/_static/pyvista_logo_sm_sq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/_static/pyvista_logo_sm_sq.png -------------------------------------------------------------------------------- /doc/source/_static/table.css: -------------------------------------------------------------------------------- 1 | .rendered_html table { 2 | table-layout: auto; 3 | } 4 | -------------------------------------------------------------------------------- /doc/source/getting-started.rst: -------------------------------------------------------------------------------- 1 | .. _getting_started: 2 | 3 | Getting Started 4 | =============== 5 | 6 | The only prerequisite for installing PyVista is Python itself. If you don't have 7 | Python yet and want the simplest way to get started, we recommend you use the 8 | `Anaconda Distribution`_. 9 | 10 | .. _Anaconda Distribution: https://www.anaconda.com/ 11 | 12 | PyVista can be installed locally with conda or pip. If you'd 13 | prefer it, you can also run PyVista on the cloud using :ref:`colab` or 14 | :ref:`mybinder`. For more detailed instructions, see the installation 15 | guide below. 16 | 17 | 18 | Installation 19 | ------------ 20 | 21 | PyVista can be installed on several environments, including, but not limited to: 22 | 23 | .. tab-set:: 24 | 25 | .. tab-item:: pip 26 | 27 | .. code:: 28 | 29 | pip install 'pyvista[all,trame]' jupyterlab 30 | 31 | .. tab-item:: conda 32 | 33 | .. code:: 34 | 35 | conda install -c conda-forge pyvista jupyterlab trame trame-vuetify trame-vtk ipywidgets 36 | 37 | 38 | 39 | 40 | You can then plot in Jupyter with either a static or interactive backend: 41 | 42 | .. pyvista-plot:: 43 | 44 | import pyvista as pv 45 | from pyvista import examples 46 | 47 | dataset = examples.download_lucy() 48 | dataset.plot(smooth_shading=True, color='white') 49 | 50 | 51 | .. _mybinder: 52 | 53 | MyBinder 54 | -------- 55 | MyBinder, similar to Google Colab, allows you to run Jupyter notebooks on the 56 | cloud. Click on the link below to open up a MyBinder environment to run 57 | PyVista. 58 | 59 | |binder| 60 | 61 | .. |binder| image:: https://static.mybinder.org/badge_logo.svg 62 | :target: https://mybinder.org/v2/gh/pyvista/pyvista-tutorial/gh-pages?urlpath=lab/tree/notebooks 63 | :alt: Launch on Binder 64 | 65 | 66 | .. _colab: 67 | 68 | Google Colab 69 | ------------ 70 | Google Colab is a moving target and many of the "cloud ready" JavaScript 71 | plotting environments that make PyVista so great to work with do not seem to be 72 | available on Google Colab. However, we still have a working PyVista example for 73 | `Google Colab `_ with static plotting. 74 | 75 | Visit the `PyVista on Colab `_ notebook to see PyVista in action. The minimum code to get PyVista running in a Colab environment is: 76 | 77 | .. code:: 78 | 79 | !apt-get install -qq xvfb libgl1-mesa-glx 80 | !pip install pyvista -qq 81 | 82 | .. code:: python 83 | 84 | import pyvista 85 | 86 | pyvista.set_jupyter_backend('static') 87 | pyvista.global_theme.notebook = True 88 | pyvista.start_xvfb() 89 | -------------------------------------------------------------------------------- /doc/source/images/action/AeroSandbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/AeroSandbox.png -------------------------------------------------------------------------------- /doc/source/images/action/Duoprism_3-30.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/Duoprism_3-30.gif -------------------------------------------------------------------------------- /doc/source/images/action/air_racing_optimization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/air_racing_optimization.png -------------------------------------------------------------------------------- /doc/source/images/action/anvil_cirrus_plumes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/anvil_cirrus_plumes.png -------------------------------------------------------------------------------- /doc/source/images/action/atmospheric_convection.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/atmospheric_convection.jpeg -------------------------------------------------------------------------------- /doc/source/images/action/boolean_marching_cubes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/boolean_marching_cubes.png -------------------------------------------------------------------------------- /doc/source/images/action/coil_field_lines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/coil_field_lines.png -------------------------------------------------------------------------------- /doc/source/images/action/comet_fenicsx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/comet_fenicsx.png -------------------------------------------------------------------------------- /doc/source/images/action/damavand_volcano.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/damavand_volcano.gif -------------------------------------------------------------------------------- /doc/source/images/action/discretize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/discretize.png -------------------------------------------------------------------------------- /doc/source/images/action/drilldown.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/drilldown.jpg -------------------------------------------------------------------------------- /doc/source/images/action/felupe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/felupe.png -------------------------------------------------------------------------------- /doc/source/images/action/flem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/flem.png -------------------------------------------------------------------------------- /doc/source/images/action/forge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/forge.png -------------------------------------------------------------------------------- /doc/source/images/action/geemap.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/geemap.gif -------------------------------------------------------------------------------- /doc/source/images/action/gemgis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/gemgis.png -------------------------------------------------------------------------------- /doc/source/images/action/geovista_earth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/geovista_earth.png -------------------------------------------------------------------------------- /doc/source/images/action/gmsh_model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/gmsh_model.png -------------------------------------------------------------------------------- /doc/source/images/action/grad_descent_visualizer.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/grad_descent_visualizer.gif -------------------------------------------------------------------------------- /doc/source/images/action/griddip.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/griddip.gif -------------------------------------------------------------------------------- /doc/source/images/action/nikolov1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/nikolov1.gif -------------------------------------------------------------------------------- /doc/source/images/action/nikolov2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/nikolov2.gif -------------------------------------------------------------------------------- /doc/source/images/action/nikolov3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/nikolov3.gif -------------------------------------------------------------------------------- /doc/source/images/action/omfvista.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/omfvista.png -------------------------------------------------------------------------------- /doc/source/images/action/open-foam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/open-foam.png -------------------------------------------------------------------------------- /doc/source/images/action/optimization.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/optimization.gif -------------------------------------------------------------------------------- /doc/source/images/action/orvisu.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/orvisu.gif -------------------------------------------------------------------------------- /doc/source/images/action/ptera_software.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/ptera_software.gif -------------------------------------------------------------------------------- /doc/source/images/action/pvgeo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/pvgeo.png -------------------------------------------------------------------------------- /doc/source/images/action/pyelastica.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/pyelastica.gif -------------------------------------------------------------------------------- /doc/source/images/action/pyfbs.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/pyfbs.webp -------------------------------------------------------------------------------- /doc/source/images/action/pymeshfix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/pymeshfix.png -------------------------------------------------------------------------------- /doc/source/images/action/stpyvista_intro_crop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/stpyvista_intro_crop.gif -------------------------------------------------------------------------------- /doc/source/images/action/sunkit-pyvista.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/sunkit-pyvista.png -------------------------------------------------------------------------------- /doc/source/images/action/tetgen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/tetgen.png -------------------------------------------------------------------------------- /doc/source/images/action/vessel_vio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/vessel_vio.png -------------------------------------------------------------------------------- /doc/source/images/action/visualpic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/action/visualpic.png -------------------------------------------------------------------------------- /doc/source/images/gifs/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/.gitignore -------------------------------------------------------------------------------- /doc/source/images/gifs/box-clip.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/box-clip.gif -------------------------------------------------------------------------------- /doc/source/images/gifs/documentation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/documentation.gif -------------------------------------------------------------------------------- /doc/source/images/gifs/dynamic_flask.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/dynamic_flask.gif -------------------------------------------------------------------------------- /doc/source/images/gifs/line-widget-streamlines.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/line-widget-streamlines.gif -------------------------------------------------------------------------------- /doc/source/images/gifs/multiple-checkbox-widget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/multiple-checkbox-widget.gif -------------------------------------------------------------------------------- /doc/source/images/gifs/multiple-slider-widget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/multiple-slider-widget.gif -------------------------------------------------------------------------------- /doc/source/images/gifs/plane-clip.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/plane-clip.gif -------------------------------------------------------------------------------- /doc/source/images/gifs/plane-glyph.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/plane-glyph.gif -------------------------------------------------------------------------------- /doc/source/images/gifs/plane-slice-continuous.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/plane-slice-continuous.gif -------------------------------------------------------------------------------- /doc/source/images/gifs/plane-slice.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/plane-slice.gif -------------------------------------------------------------------------------- /doc/source/images/gifs/scalar-bar-interactive.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/scalar-bar-interactive.gif -------------------------------------------------------------------------------- /doc/source/images/gifs/shrink-globe.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/shrink-globe.gif -------------------------------------------------------------------------------- /doc/source/images/gifs/single-checkbox-widget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/single-checkbox-widget.gif -------------------------------------------------------------------------------- /doc/source/images/gifs/slider-widget-resolution.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/slider-widget-resolution.gif -------------------------------------------------------------------------------- /doc/source/images/gifs/slider-widget-threshold.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/slider-widget-threshold.gif -------------------------------------------------------------------------------- /doc/source/images/gifs/sphere-widget-a.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/sphere-widget-a.gif -------------------------------------------------------------------------------- /doc/source/images/gifs/sphere-widget-b.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/sphere-widget-b.gif -------------------------------------------------------------------------------- /doc/source/images/gifs/sphere-widget-c.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/sphere-widget-c.gif -------------------------------------------------------------------------------- /doc/source/images/gifs/spline-widget.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/gifs/spline-widget.gif -------------------------------------------------------------------------------- /doc/source/images/jupyter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/jupyter.png -------------------------------------------------------------------------------- /doc/source/images/trame-pyvista.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/trame-pyvista.png -------------------------------------------------------------------------------- /doc/source/images/user-generated/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/user-generated/.gitkeep -------------------------------------------------------------------------------- /doc/source/images/user-generated/femorph-qt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/user-generated/femorph-qt.png -------------------------------------------------------------------------------- /doc/source/images/user-generated/qt_multiplot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/user-generated/qt_multiplot.png -------------------------------------------------------------------------------- /doc/source/images/user-generated/qt_plotting_sphere.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/images/user-generated/qt_plotting_sphere.png -------------------------------------------------------------------------------- /doc/source/locales/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/doc/source/locales/.gitkeep -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | dynamic = ['version'] 3 | name = "pyvista-tutorial" 4 | requires-python = '>=3.9' 5 | 6 | [project.optional-dependencies] 7 | all = ['docs'] 8 | docs = [ 9 | 'Sphinx==8.2.1', 10 | 'atsphinx-mini18n==0.4.1', 11 | 'cmocean==4.0.3', 12 | 'colorcet==3.1.0', 13 | 'geovista==0.5.3', 14 | 'imageio-ffmpeg==0.6.0', 15 | 'imageio>=2.5.0', 16 | 'ipygany==0.5.0', 17 | 'ipywidgets==8.1.7', 18 | 'jupyter_sphinx==0.5.3', 19 | 'jupyterlab==4.4.3', 20 | 'lxml==5.4.0', 21 | 'matplotlib==3.10.1', 22 | 'meshio==5.3.5', 23 | 'mypy-extensions==1.1.0', 24 | 'mypy==1.16.0', 25 | 'numpydoc==1.8.0', 26 | 'osmnx==2.0.3', 27 | 'pypandoc==1.15', 28 | 'pytest-sphinx==0.6.3', 29 | 'pyvista-xarray==0.1.7', 30 | 'pyvista[all]==0.45.2', 31 | 'scipy==1.15.2', 32 | 'sphinx-autobuild==2024.10.3', 33 | 'sphinx-book-theme==1.1.4', 34 | 'sphinx-copybutton==0.5.2', 35 | 'sphinx-gallery==0.19.0', 36 | 'sphinx-notfound-page==1.1.0', 37 | 'sphinx_design==0.6.1', 38 | 'sphinxcontrib-websupport==2.0.0', 39 | 'sphinxcontrib.asciinema==0.4.2', 40 | 'trame-client==3.9.0', 41 | 'trame-server==3.4.0', 42 | 'trame-vtk==2.8.15', 43 | 'trame-vuetify==3.0.1', 44 | 'trame==3.10.1', 45 | 'trimesh==4.6.10', 46 | 'typed-ast==1.5.5', 47 | 'typing_extensions==4.13.2', 48 | 'vtk-xref==0.1.0', 49 | 'vtk<9.5', 50 | ] 51 | 52 | [tool.ruff] 53 | exclude = ['.git', 'build', 'dist', 'doc/_build', 'doc/tutorial', 'pycache__'] 54 | indent-width = 4 55 | line-length = 100 56 | lint.ignore = ["COM812", "D203", "D212", "E501", "ERA001", "ISC001"] 57 | lint.select = ["ALL"] 58 | 59 | [tool.ruff.lint.per-file-ignores] 60 | "doc/**" = ["ANN", "ARG", "D", "INP001"] 61 | "tutorial/**" = [ 62 | "ANN", 63 | "ARG", 64 | "B015", # https://github.com/pyvista/pyvista/pull/6014 65 | "B018", # https://github.com/pyvista/pyvista/pull/6019 66 | "D101", 67 | "D102", 68 | "D103", 69 | "D107", 70 | "D205", 71 | "D400", 72 | "D401", 73 | "D415", 74 | "E402", 75 | "F704", 76 | "INP001", 77 | "NPY", 78 | "PLE1142", 79 | ] 80 | 81 | [tool.ruff.format] 82 | docstring-code-format = true 83 | quote-style = "preserve" 84 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | cmocean 2 | geovista 3 | imageio>=2.5.0 4 | imageio-ffmpeg 5 | ipywidgets<9.0.0 6 | jupyterlab<5.0.0 7 | matplotlib 8 | pyvista[all] 9 | sphinx 10 | tqdm 11 | trame>=2.5.0 12 | trame-client>=2.9.4 13 | trame-server>=2.11.4 14 | trame-vtk>=2.5.4 15 | -------------------------------------------------------------------------------- /start: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export PYVISTA_TRAME_SERVER_PROXY_PREFIX="$JUPYTERHUB_SERVICE_PREFIX/proxy/" 3 | exec "$@" 4 | -------------------------------------------------------------------------------- /tutorial/00_intro/a_basic.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _ref_geometric_example: 3 | 4 | Create Basic Geometric Objects 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | This is the "Hello, world!" of PyVista. 8 | """ 9 | 10 | import pyvista as pv 11 | 12 | ############################################################################### 13 | # This runs through several of the available geometric objects available in 14 | # VTK which PyVista provides simple convenience methods for generating. 15 | # 16 | # Let's run through creating a few geometric objects! 17 | 18 | cyl = pv.Cylinder() 19 | arrow = pv.Arrow() 20 | sphere = pv.Sphere() 21 | plane = pv.Plane() 22 | line = pv.Line() 23 | box = pv.Box() 24 | cone = pv.Cone() 25 | poly = pv.Polygon() 26 | disc = pv.Disc() 27 | 28 | ############################################################################### 29 | # Now let's plot them all in one window 30 | 31 | p = pv.Plotter(shape=(3, 3)) 32 | # Top row 33 | p.subplot(0, 0) 34 | p.add_mesh(cyl, color="tan", show_edges=True) 35 | p.subplot(0, 1) 36 | p.add_mesh(arrow, color="tan", show_edges=True) 37 | p.subplot(0, 2) 38 | p.add_mesh(sphere, color="tan", show_edges=True) 39 | # Middle row 40 | p.subplot(1, 0) 41 | p.add_mesh(plane, color="tan", show_edges=True) 42 | p.subplot(1, 1) 43 | p.add_mesh(line, color="tan", line_width=3) 44 | p.subplot(1, 2) 45 | p.add_mesh(box, color="tan", show_edges=True) 46 | # Bottom row 47 | p.subplot(2, 0) 48 | p.add_mesh(cone, color="tan", show_edges=True) 49 | p.subplot(2, 1) 50 | p.add_mesh(poly, color="tan", show_edges=True) 51 | p.subplot(2, 2) 52 | p.add_mesh(disc, color="tan", show_edges=True) 53 | # Render all of them 54 | p.show() 55 | # Export this plotter as an interactive scene to a HTML file. 56 | # p.export_html("a_basic.html") 57 | 58 | ############################################################################### 59 | # .. raw:: html 60 | # 61 | #
62 | # 63 | # Open In Colab 64 | # 65 | #
66 | -------------------------------------------------------------------------------- /tutorial/00_jupyter/jupyter.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test out PyVista's Jupyter Backend 3 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | 5 | Become familiar with PyVista Jupyter backend. 6 | """ 7 | 8 | import pyvista as pv 9 | 10 | # Set/enable the backed 11 | pv.set_jupyter_backend("trame") 12 | 13 | ############################################################################### 14 | 15 | pl = pv.Plotter() 16 | pl.add_mesh(pv.ParametricKlein()) 17 | pl.show() 18 | 19 | 20 | ############################################################################### 21 | # Client-side rendering only (in browser) 22 | 23 | pl = pv.Plotter() 24 | pl.add_mesh(pv.ParametricRandomHills().elevation()) 25 | pl.show(jupyter_backend="client") 26 | 27 | 28 | ############################################################################### 29 | # Server-side rendering only 30 | 31 | pl = pv.Plotter() 32 | pl.add_volume(pv.Wavelet()) 33 | pl.show(jupyter_backend="server") 34 | 35 | ############################################################################### 36 | # .. raw:: html 37 | # 38 | #
39 | # 40 | # Open In Colab 41 | # 42 | #
43 | -------------------------------------------------------------------------------- /tutorial/01_basic/README.rst: -------------------------------------------------------------------------------- 1 | .. _basic: 2 | 3 | Basic usage 4 | =========== 5 | 6 | This section demonstrates how to use PyVista to reading and plotting 3D data 7 | using the `pyvista.examples`_ module and external files. 8 | 9 | .. tip:: 10 | 11 | This section of the tutorial was adopted from the `Basic API Usage 12 | `_ chapter of the PyVista 13 | documentation. 14 | 15 | .. _pyvista.examples: https://docs.pyvista.org/api/examples/_autosummary/pyvista.examples.examples.html# 16 | 17 | Using Existing Data 18 | ~~~~~~~~~~~~~~~~~~~ 19 | There are two main ways of getting data into PyVista: creating it yourself from 20 | scratch or loading the dataset from any one of the `compatible file formats 21 | `_. Since we're just starting 22 | out, let's load a file. 23 | 24 | If you have a dataset handy, like a surface model, point cloud, or VTK file, 25 | you can use that. If you don't have something immediately available, PyVista 26 | has a variety of files you can download in its `pyvista.examples.downloads 27 | `_ 28 | module. 29 | 30 | Here's a very basic dataset you can download. 31 | 32 | .. pyvista-plot:: 33 | :context: 34 | :include-source: False 35 | 36 | # Configure for trame 37 | import pyvista 38 | pyvista.set_plot_theme('document') 39 | pyvista.set_jupyter_backend('trame') 40 | pyvista.global_theme.axes.show = False 41 | pyvista.global_theme.smooth_shading = True 42 | 43 | 44 | .. pyvista-plot:: 45 | :context: 46 | 47 | from pyvista import examples 48 | dataset = examples.download_saddle_surface() 49 | dataset 50 | 51 | | 52 | 53 | Note how this is a :class:`pyvista.PolyData`, which is effectively a surface 54 | dataset containing points, lines, and/or faces. We can immediately plot this with: 55 | 56 | .. pyvista-plot:: 57 | :context: 58 | 59 | dataset.plot(color='tan') 60 | 61 | | 62 | 63 | This is a fairly basic plot. You can change how its plotted by adding 64 | parameters as ``show_edges=True`` or changing the color by setting ``color`` to 65 | a different value. All of this is described in PyVista's API documentation in 66 | :func:`pyvista.plot`, but for now let's take a look at another dataset. This 67 | one is a volumetric dataset. 68 | 69 | .. pyvista-plot:: 70 | :context: 71 | 72 | dataset = examples.download_frog() 73 | dataset 74 | 75 | | 76 | 77 | This is a :class:`pyvista.ImageData`, which is a dataset containing a uniform 78 | set of points with consistent spacing. When we plot this dataset, we have the 79 | option of enabling volumetric plotting, which plots individual cells based on 80 | the content of the data associated with those cells. 81 | 82 | .. pyvista-plot:: 83 | :context: 84 | 85 | dataset.plot(volume=True) 86 | 87 | .. note:: 88 | One thing you might have noticed by now is that the plots here in the online 89 | tutorial may look slightly different than your plots depending on how you're plotting them 90 | on your computer. This depends on your ``jupyter_backend``, or if 91 | you're even using a jupyter notebook. As you're playing around with these 92 | examples, feel free to change settings like disabling (or enabling) 93 | ``notebook``, or using a different plotting backend for displaying within 94 | your notebook (if applicable). 95 | 96 | 97 | Read from a file 98 | ~~~~~~~~~~~~~~~~ 99 | You can read datasets directly from a file if you have access to it locally on 100 | your computer. This can be one of the many file formats that VTK supports, and 101 | many more that it doesn't as PyVista can rely on libraries like `meshio 102 | `_. 103 | 104 | In the following example, we load VTK's iron protein dataset `ironProt.vtk 105 | `_ from a 106 | file using :func:`pyvista.read`. 107 | 108 | .. pyvista-plot:: 109 | :context: 110 | 111 | import pyvista as pv 112 | dataset = pv.read('ironProt.vtk') 113 | dataset 114 | 115 | | 116 | 117 | This is again a :class:`pyvista.ImageData` and we can plot it volumetrically 118 | with: 119 | 120 | .. pyvista-plot:: 121 | :context: 122 | 123 | dataset.plot(volume=True) 124 | 125 | | 126 | 127 | Lesson Material 128 | =============== 129 | 130 | This is the notebook rendering of this page where you can interactively follow 131 | along with this lesson. 132 | -------------------------------------------------------------------------------- /tutorial/01_basic/a_lesson_basic.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _basic_lesson: 3 | 4 | Basic Usage Lesson 5 | ================== 6 | 7 | This section demonstrates how to use PyVista to read and plot 3D data 8 | using the `pyvista.examples.downloads 9 | `_ 10 | module and external files. 11 | """ 12 | 13 | import pyvista as pv 14 | from pyvista import examples 15 | 16 | # Set the default plot theme to the "document" theme. 17 | # pv.set_plot_theme('document') 18 | 19 | 20 | ############################################################################### 21 | # Using Existing Data 22 | # ~~~~~~~~~~~~~~~~~~~ 23 | # There are two main ways of getting data into PyVista: creating it yourself from 24 | # scratch or loading the dataset from any one of the `compatible file formats 25 | # `_. Since we're just starting 26 | # out, let's load a file. 27 | 28 | # If you have a dataset handy, like a surface model, point cloud, or VTK file, 29 | # you can use that. If you don't have something immediately available, PyVista 30 | # has a variety of files you can download in its `pyvista.examples.downloads 31 | # `_ 32 | # 33 | 34 | 35 | dataset = examples.download_saddle_surface() 36 | dataset 37 | 38 | ############################################################################### 39 | # Note how this is a :class:`pyvista.PolyData`, which is effectively a surface 40 | # dataset containing points, lines, and/or faces. We can immediately plot this with: 41 | 42 | dataset.plot() 43 | 44 | ############################################################################### 45 | # This is a fairly basic plot. You can change how its plotted by adding 46 | # parameters as ``show_edges=True`` or changing the color by setting ``color`` to 47 | # a different value. All of this is described in PyVista's API documentation in 48 | # :func:`pyvista.plot`, but for now let's take a look at another dataset. This 49 | # one is a volumetric dataset. 50 | 51 | dataset = examples.download_frog() 52 | dataset 53 | 54 | ############################################################################### 55 | # This is a :class:`pyvista.ImageData`, which is a dataset containing a uniform 56 | # set of points with consistent spacing. When we plot this dataset, we have the 57 | # option of enabling volumetric plotting, which plots individual cells based on 58 | # the content of the data associated with those cells. 59 | 60 | dataset.plot(volume=True) 61 | 62 | 63 | ############################################################################### 64 | # Read from a file 65 | # ~~~~~~~~~~~~~~~~ 66 | # You can read datasets directly from a file if you have access to it on your 67 | # environment. This can be one of the many file formats that VTK supports, and 68 | # many more that it doesn't as PyVista can rely on libraries like `meshio 69 | # `_. 70 | # 71 | # In the following example, we load VTK's iron protein dataset `ironProt.vtk 72 | # `_ from a 73 | # file using :func:`pyvista.read`. 74 | 75 | dataset = pv.read("ironProt.vtk") 76 | dataset 77 | 78 | ############################################################################### 79 | # This is again a :class:`pyvista.ImageData` and we can plot it volumetrically 80 | # with: 81 | 82 | dataset.plot(volume=True) 83 | 84 | ############################################################################### 85 | # .. raw:: html 86 | # 87 | #
88 | # 89 | # Open In Colab 90 | # 91 | #
92 | -------------------------------------------------------------------------------- /tutorial/01_basic/exercises/README.rst: -------------------------------------------------------------------------------- 1 | Exercises 2 | ========= 3 | -------------------------------------------------------------------------------- /tutorial/01_basic/exercises/a_load_examples_exercise.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _load_examples: 3 | 4 | Download and Plot Examples 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | Download and plot example datasets. 8 | 9 | PyVista contains many downloadable datasets documented at 10 | `pyvista.examples.downloads 11 | `_. You can download these through Python and immediately plot them. 12 | 13 | This is an easy way to immediately get started with example datasets within 14 | PyVista without having to manually download and load them. 15 | 16 | 17 | """ 18 | 19 | ############################################################################### 20 | # Import PyVista and the examples module 21 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 | import pyvista as pv 23 | from pyvista import examples 24 | 25 | ############################################################################### 26 | # Surface DataSet - Download 27 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~ 28 | # Download a surface dataset of pine roots. Note how the dataset is 29 | # automatically loaded right into Python. 30 | dataset = examples.download_pine_roots() 31 | dataset 32 | 33 | 34 | ############################################################################### 35 | # Surface DataSet - Plot 36 | # ~~~~~~~~~~~~~~~~~~~~~~ 37 | # Plot the pine roots using PyVista's default plotting settings. 38 | dataset.plot() 39 | 40 | 41 | ############################################################################### 42 | # Volume DataSet - Download 43 | # ~~~~~~~~~~~~~~~~~~~~~~~~~ 44 | # Download the bolt dataset. This is an excellent dataset to visualize using 45 | # "volumetric" plotting. 46 | 47 | dataset = examples.download_bolt_nut() 48 | dataset 49 | 50 | 51 | ############################################################################### 52 | # Volume DataSet - Plot 53 | # ~~~~~~~~~~~~~~~~~~~~~ 54 | # Here, we plot the dataset using a custom view direction using 55 | # :class:`pyvista.Plotter`. 56 | 57 | pl = pv.Plotter() 58 | _ = pl.add_volume( 59 | dataset, 60 | cmap="coolwarm", 61 | opacity="sigmoid_5", 62 | show_scalar_bar=False, 63 | ) 64 | pl.camera_position = [(194.6, -141.8, 182.0), (34.5, 61.0, 32.5), (-0.229, 0.45, 0.86)] 65 | pl.show() 66 | 67 | 68 | ############################################################################### 69 | # Exercise #1 - Use PyVista Examples 70 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 71 | # Visualize one of PyVista's built in examples. 72 | # 73 | # If your IDE supports it, you should be able to type 74 | # ``dataset = examples.download_`` and press tab to see all the available 75 | # examples you can download. 76 | 77 | 78 | ############################################################################### 79 | # Exercise #2 - Download and View a File 80 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 81 | # Experiment on your own by downloading a dataset and reading it in with 82 | # :func:`pyvista.read`. You can use one of your own files or try downloading 83 | # one from the following sources: 84 | # 85 | # - `Sample VTK DataSets `_ 86 | # - `Sample STL files `_ 87 | # - `Thingiverse `_ 88 | 89 | ############################################################################### 90 | # .. raw:: html 91 | # 92 | #
93 | # 94 | # Open In Colab 95 | # 96 | #
97 | -------------------------------------------------------------------------------- /tutorial/01_basic/ironProt.vtk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/tutorial/01_basic/ironProt.vtk -------------------------------------------------------------------------------- /tutorial/01_basic/solutions/P_shelf_pin.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/tutorial/01_basic/solutions/P_shelf_pin.stl -------------------------------------------------------------------------------- /tutorial/01_basic/solutions/README.rst: -------------------------------------------------------------------------------- 1 | Solutions 2 | ========= 3 | 4 | These are the solutions to the above examples. 5 | -------------------------------------------------------------------------------- /tutorial/01_basic/solutions/a_load_examples_solution.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _load_examples_solution: 3 | 4 | Download and Plot Examples 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | .. note:: 8 | This is the solution to :ref:`load_examples`. If you haven't already tried to 9 | solve it on your own, you probably should try that first. 10 | 11 | Download and plot example datasets. 12 | 13 | PyVista contains many downloadable datasets documented at 14 | `pyvista.examples.downloads 15 | `_. You can download these through Python and then immediately plot them. 16 | 17 | This is an easy way to immediately get started with example datasets within 18 | PyVista without having to manually download and load them. 19 | 20 | """ 21 | 22 | ############################################################################### 23 | # Import PyVista and the examples module 24 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 25 | import pyvista as pv 26 | from pyvista import examples 27 | 28 | ############################################################################### 29 | # Surface DataSet - Download 30 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~ 31 | # Download a surface dataset of pine roots. Note how the dataset is 32 | # automatically loaded right into Python. 33 | dataset = examples.download_pine_roots() 34 | dataset 35 | 36 | 37 | ############################################################################### 38 | # Surface DataSet - Plot 39 | # ~~~~~~~~~~~~~~~~~~~~~~ 40 | # Plot the pine roots using PyVista's default plotting settings. 41 | dataset.plot() 42 | 43 | 44 | ############################################################################### 45 | # Volume DataSet - Download 46 | # ~~~~~~~~~~~~~~~~~~~~~~~~~ 47 | # Download the bolt dataset. This is an excellent dataset to visualize using 48 | # "volumetric" plotting. 49 | 50 | dataset = examples.download_bolt_nut() 51 | dataset 52 | 53 | 54 | ############################################################################### 55 | # Volume DataSet - Plot 56 | # ~~~~~~~~~~~~~~~~~~~~~ 57 | # Here, we plot the dataset using a custom view direction using 58 | # :class:`pyvista.Plotter`. 59 | 60 | pl = pv.Plotter() 61 | _ = pl.add_volume( 62 | dataset, 63 | cmap="coolwarm", 64 | opacity="sigmoid_5", 65 | show_scalar_bar=False, 66 | ) 67 | pl.camera_position = [(194.6, -141.8, 182.0), (34.5, 61.0, 32.5), (-0.229, 0.45, 0.86)] 68 | pl.show() 69 | 70 | 71 | ############################################################################### 72 | # Exercise #1 - Use PyVista Examples 73 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 74 | # Visualize one of PyVista's built in examples. 75 | # 76 | # If your IDE supports it, you should be able to type 77 | # ``dataset = examples.download_`` and press tab to see all the available 78 | # examples you can download. 79 | 80 | dataset = examples.download_gears() 81 | bodies = dataset.split_bodies() 82 | bodies.plot( 83 | cmap="jet", 84 | multi_colors=True, 85 | smooth_shading=True, 86 | split_sharp_edges=True, 87 | ) 88 | 89 | 90 | ############################################################################### 91 | # Exercise #2 - Download and View a File 92 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 93 | # Experiment on your own by downloading a dataset and reading it in with 94 | # :class:`pyvista.read`. You can use one of your own files or try downloading 95 | # one from the following sources: 96 | # 97 | # - `Sample VTK DataSets `_ 98 | # - `Sample STL files `_ 99 | # - `Thingiverse `_ 100 | # 101 | # **Solution** 102 | # Download the file ``'P_shelf_pin.stl'`` from 103 | # https://www.thingiverse.com/thing:5412753 104 | 105 | mesh = pv.read("P_shelf_pin.stl") 106 | mesh.plot() 107 | 108 | ############################################################################### 109 | # .. raw:: html 110 | # 111 | #
112 | # 113 | # Open In Colab 114 | # 115 | #
116 | -------------------------------------------------------------------------------- /tutorial/02_mesh/exercises/README.rst: -------------------------------------------------------------------------------- 1 | Do it yourself 2 | ~~~~~~~~~~~~~~ 3 | -------------------------------------------------------------------------------- /tutorial/02_mesh/exercises/d_create-tri-surface.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _triangulated_surface_exercises: 3 | 4 | Create Triangulated Surface 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | Create a surface from a set of points through a Delaunay triangulation. 8 | 9 | .. note:: 10 | We will use a filter from PyVista to perform our triangulation: `delaunay_2d `_. 11 | """ 12 | 13 | import numpy as np 14 | import pyvista as pv 15 | 16 | ############################################################################### 17 | # Simple Triangulations 18 | # +++++++++++++++++++++ 19 | # 20 | # First, create some points for the surface. 21 | 22 | # Define a simple Gaussian surface 23 | n = 20 24 | x = np.linspace(-200, 200, num=n) + np.random.uniform(-5, 5, size=n) 25 | y = np.linspace(-200, 200, num=n) + np.random.uniform(-5, 5, size=n) 26 | xx, yy = np.meshgrid(x, y) 27 | A, b = 100, 100 28 | zz = A * np.exp(-0.5 * ((xx / b) ** 2.0 + (yy / b) ** 2.0)) 29 | 30 | # Get the points as a 2D NumPy array (N by 3) 31 | points = np.c_[xx.reshape(-1), yy.reshape(-1), zz.reshape(-1)] 32 | points[0:5, :] 33 | 34 | ############################################################################### 35 | # Now use those points to create a point cloud PyVista data object. This will 36 | # be encompassed in a :class:`pyvista.PolyData` object. 37 | 38 | # simply pass the numpy points to the PolyData constructor 39 | cloud = ... 40 | cloud.plot(point_size=15) 41 | 42 | ############################################################################### 43 | # Now that we have a PyVista data structure of the points, we can perform a 44 | # triangulation to turn those boring discrete points into a connected surface. 45 | # See :func:`pyvista.UnstructuredGridFilters.delaunay_2d`. 46 | help(cloud.delaunay_2d) 47 | 48 | ############################################################################### 49 | # Apply the ``delaunay_2d`` filter. 50 | 51 | surf = ... 52 | 53 | # And plot it with edges shown 54 | surf.plot(show_edges=True) 55 | 56 | 57 | ############################################################################### 58 | # Clean Edges & Triangulations 59 | # ++++++++++++++++++++++++++++ 60 | 61 | # Create the points to triangulate 62 | x = np.arange(10, dtype=float) 63 | xx, yy, zz = np.meshgrid(x, x, [0]) 64 | points = np.column_stack((xx.ravel(order="F"), yy.ravel(order="F"), zz.ravel(order="F"))) 65 | # Perturb the points 66 | points[:, 0] += np.random.rand(len(points)) * 0.3 67 | points[:, 1] += np.random.rand(len(points)) * 0.3 68 | 69 | # Create the point cloud mesh to triangulate from the coordinates 70 | cloud = pv.PolyData(points) 71 | cloud 72 | 73 | ############################################################################### 74 | cloud.plot(cpos="xy") 75 | 76 | ############################################################################### 77 | # Run the triangulation on these points 78 | surf = cloud.delaunay_2d() 79 | surf.plot(cpos="xy", show_edges=True) 80 | 81 | ############################################################################### 82 | # Note that some of the outer edges are unconstrained and the triangulation 83 | # added unwanted triangles. We can mitigate that with the ``alpha`` parameter. 84 | surf = cloud.delaunay_2d(alpha=...) 85 | surf.plot(cpos="xy", show_edges=True) 86 | 87 | ############################################################################### 88 | # .. raw:: html 89 | # 90 | #
91 | # 92 | # Open In Colab 93 | # 94 | #
95 | -------------------------------------------------------------------------------- /tutorial/02_mesh/exercises/e_read-file.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _read_file_exercise: 3 | 4 | Load and Plot from a File 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | Read a dataset from a known file type. 8 | 9 | """ 10 | 11 | ############################################################################### 12 | # We try to make loading a mesh as easy as possible - if your data is in one 13 | # of the many supported file formats, simply use :func:`pyvista.read` to 14 | # load your spatially referenced dataset into a PyVista mesh object. 15 | # 16 | # The following code block uses a built-in example file and displays an 17 | # airplane mesh. 18 | 19 | # sphinx_gallery_thumbnail_number = 5 20 | import pyvista as pv 21 | from pyvista import examples 22 | 23 | ############################################################################### 24 | help(pv.read) 25 | 26 | ############################################################################### 27 | # PyVista supports a wide variety of file formats. The supported file 28 | # extensions are listed in an internal function: 29 | help(pv.core.utilities.reader.get_reader) 30 | 31 | 32 | ############################################################################### 33 | # The following code block uses a built-in example 34 | # file, displays an airplane mesh and returns the camera's position: 35 | 36 | # Get a sample file 37 | filename = examples.planefile 38 | filename 39 | 40 | ############################################################################### 41 | # Note the above filename, it's a ``.ply`` file - one of the many supported 42 | # formats in PyVista. 43 | # 44 | # Use ``pv.read`` to load the file as a mesh: 45 | 46 | mesh = ... 47 | cpos = mesh.plot() 48 | 49 | 50 | ############################################################################### 51 | # The points from the mesh are directly accessible as a NumPy array: 52 | 53 | mesh.points 54 | 55 | ############################################################################### 56 | # The faces from the mesh are also directly accessible as a NumPy array: 57 | 58 | mesh.faces.reshape(-1, 4)[:, 1:] # triangular faces 59 | 60 | 61 | ############################################################################### 62 | # Loading other files types is just as easy! Simply pass your file path to the 63 | # :func:`pyvista.read` function and that's it! 64 | # 65 | # Here are a few other examples - simply replace ``examples.download_*`` in the 66 | # examples below with ``pyvista.read('path/to/you/file.ext')`` 67 | 68 | ############################################################################### 69 | # Example STL file: 70 | mesh = examples.download_cad_model() 71 | cpos = [(107.0, 68.5, 204.0), (128.0, 86.5, 223.5), (0.45, 0.36, -0.8)] 72 | mesh.plot(cpos=cpos) 73 | 74 | ############################################################################### 75 | # Example OBJ file 76 | mesh = examples.download_doorman() 77 | mesh.plot(cpos="xy") 78 | 79 | 80 | ############################################################################### 81 | # Example BYU file 82 | mesh = examples.download_teapot() 83 | mesh.plot(cpos=[-1, 2, -5], show_edges=True) 84 | 85 | 86 | ############################################################################### 87 | # Example VTK file 88 | mesh = examples.download_bunny_coarse() 89 | cpos = [(0.2, 0.3, 0.9), (0, 0, 0), (0, 1, 0)] 90 | mesh.plot(cpos=cpos, show_edges=True, color=True) 91 | 92 | 93 | ############################################################################### 94 | # Exercise 95 | # ^^^^^^^^ 96 | # Read a file yourself with :func:`pyvista.read`. If you have a supported file 97 | # format, use that! Otherwise, download this file: 98 | # https://github.com/pyvista/pyvista-tutorial/raw/main/tutorial/02_mesh/scipy.vtk 99 | 100 | # (your code here) 101 | # mesh = pv.read('path/to/file.vtk) 102 | 103 | ############################################################################### 104 | # .. raw:: html 105 | # 106 | #
107 | # 108 | # Open In Colab 109 | # 110 | #
111 | -------------------------------------------------------------------------------- /tutorial/02_mesh/scipy.vtk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyvista/pyvista-tutorial/b4166075a08f6212278067b6d6d051f4ee6d170d/tutorial/02_mesh/scipy.vtk -------------------------------------------------------------------------------- /tutorial/02_mesh/solutions/README.rst: -------------------------------------------------------------------------------- 1 | Solutions 2 | ~~~~~~~~~ 3 | -------------------------------------------------------------------------------- /tutorial/02_mesh/solutions/d_create-tri-surface.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _triangulated_surface: 3 | 4 | Create Triangulated Surface 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | Create a surface from a set of points through a Delaunay triangulation. 8 | 9 | .. note:: 10 | We will use a filter from PyVista to perform our triangulation: `delaunay_2d `_. 11 | """ 12 | 13 | import numpy as np 14 | import pyvista as pv 15 | 16 | ############################################################################### 17 | # Simple Triangulations 18 | # +++++++++++++++++++++ 19 | # 20 | # First, create some points for the surface. 21 | 22 | # Define a simple Gaussian surface 23 | n = 20 24 | x = np.linspace(-200, 200, num=n) + np.random.uniform(-5, 5, size=n) 25 | y = np.linspace(-200, 200, num=n) + np.random.uniform(-5, 5, size=n) 26 | xx, yy = np.meshgrid(x, y) 27 | A, b = 100, 100 28 | zz = A * np.exp(-0.5 * ((xx / b) ** 2.0 + (yy / b) ** 2.0)) 29 | 30 | # Get the points as a 2D NumPy array (N by 3) 31 | points = np.c_[xx.reshape(-1), yy.reshape(-1), zz.reshape(-1)] 32 | points[0:5, :] 33 | 34 | ############################################################################### 35 | # Now use those points to create a point cloud PyVista data object. This will 36 | # be encompassed in a :class:`pyvista.PolyData` object. 37 | 38 | # simply pass the numpy points to the PolyData constructor 39 | cloud = pv.PolyData(points) 40 | cloud.plot(point_size=15) 41 | 42 | ############################################################################### 43 | # Now that we have a PyVista data structure of the points, we can perform a 44 | # triangulation to turn those boring discrete points into a connected surface. 45 | # See :func:`pyvista.UnstructuredGridFilters.delaunay_2d`. 46 | help(cloud.delaunay_2d) 47 | 48 | ############################################################################### 49 | # Apply the ``delaunay_2d`` filter. 50 | 51 | surf = cloud.delaunay_2d() 52 | 53 | # And plot it with edges shown 54 | surf.plot(show_edges=True) 55 | 56 | 57 | ############################################################################### 58 | # Clean Edges & Triangulations 59 | # ++++++++++++++++++++++++++++ 60 | 61 | # Create the points to triangulate 62 | x = np.arange(10, dtype=float) 63 | xx, yy, zz = np.meshgrid(x, x, [0]) 64 | points = np.column_stack((xx.ravel(order="F"), yy.ravel(order="F"), zz.ravel(order="F"))) 65 | # Perturb the points 66 | points[:, 0] += np.random.rand(len(points)) * 0.3 67 | points[:, 1] += np.random.rand(len(points)) * 0.3 68 | 69 | # Create the point cloud mesh to triangulate from the coordinates 70 | cloud = pv.PolyData(points) 71 | cloud 72 | 73 | ############################################################################### 74 | cloud.plot(cpos="xy") 75 | 76 | ############################################################################### 77 | # Run the triangulation on these points 78 | surf = cloud.delaunay_2d() 79 | surf.plot(cpos="xy", show_edges=True) 80 | 81 | ############################################################################### 82 | # Note that some of the outer edges are unconstrained and the triangulation 83 | # added unwanted triangles. We can mitigate that with the ``alpha`` parameter. 84 | surf = cloud.delaunay_2d(alpha=1.0) 85 | surf.plot(cpos="xy", show_edges=True) 86 | 87 | ############################################################################### 88 | # .. raw:: html 89 | # 90 | #
91 | # 92 | # Open In Colab 93 | # 94 | #
95 | -------------------------------------------------------------------------------- /tutorial/02_mesh/solutions/e_read-file.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _read_file_example: 3 | 4 | Load and Plot from a File 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | Read a dataset from a known file type. 8 | 9 | """ 10 | 11 | ############################################################################### 12 | # We try to make loading a mesh as easy as possible - if your data is in one 13 | # of the many supported file formats, simply use :func:`pyvista.read` to 14 | # load your spatially referenced dataset into a PyVista mesh object. 15 | # 16 | # The following code block uses a built-in example file and displays an 17 | # airplane mesh. 18 | 19 | # sphinx_gallery_thumbnail_number = 5 20 | import pyvista as pv 21 | from pyvista import examples 22 | 23 | ############################################################################### 24 | help(pv.read) 25 | 26 | ############################################################################### 27 | # PyVista supports a wide variety of file formats. The supported file 28 | # extensions are listed in an internal function: 29 | help(pv.core.utilities.reader.get_reader) 30 | 31 | 32 | ############################################################################### 33 | # The following code block uses a built-in example 34 | # file, displays an airplane mesh and returns the camera's position: 35 | 36 | # Get a sample file 37 | filename = examples.planefile 38 | filename 39 | 40 | ############################################################################### 41 | # Note the above filename, it's a ``.ply`` file - one of the many supported 42 | # formats in PyVista. 43 | # 44 | # Use ``pv.read`` to load the file as a mesh: 45 | 46 | mesh = pv.read(filename) 47 | cpos = mesh.plot() 48 | 49 | 50 | ############################################################################### 51 | # The points from the mesh are directly accessible as a NumPy array: 52 | 53 | mesh.points 54 | 55 | ############################################################################### 56 | # The faces from the mesh are also directly accessible as a NumPy array: 57 | 58 | mesh.faces.reshape(-1, 4)[:, 1:] # triangular faces 59 | 60 | 61 | ############################################################################### 62 | # Loading other files types is just as easy! Simply pass your file path to the 63 | # :func:`pyvista.read` function and that's it! 64 | # 65 | # Here are a few other examples - simply replace ``examples.download_*`` in the 66 | # examples below with ``pyvista.read('path/to/you/file.ext')`` 67 | 68 | ############################################################################### 69 | # Example STL file: 70 | mesh = examples.download_cad_model() 71 | cpos = [(107.0, 68.5, 204.0), (128.0, 86.5, 223.5), (0.45, 0.36, -0.8)] 72 | mesh.plot(cpos=cpos) 73 | 74 | ############################################################################### 75 | # Example OBJ file 76 | mesh = examples.download_doorman() 77 | mesh.plot(cpos="xy") 78 | 79 | 80 | ############################################################################### 81 | # Example BYU file 82 | mesh = examples.download_teapot() 83 | mesh.plot(cpos=[-1, 2, -5], show_edges=True) 84 | 85 | 86 | ############################################################################### 87 | # Example VTK file 88 | mesh = examples.download_bunny_coarse() 89 | cpos = [(0.2, 0.3, 0.9), (0, 0, 0), (0, 1, 0)] 90 | mesh.plot(cpos=cpos, show_edges=True, color=True) 91 | 92 | 93 | ############################################################################### 94 | # Exercise 95 | # ^^^^^^^^ 96 | # Read a file yourself with :func:`pyvista.read`. If you have a supported file 97 | # format, use that! Otherwise, download this file: 98 | # https://github.com/pyvista/pyvista-tutorial/raw/main/tutorial/02_mesh/scipy.vtk 99 | 100 | # (your code here) 101 | # mesh = pv.read('path/to/file.vtk) 102 | 103 | ############################################################################### 104 | # .. raw:: html 105 | # 106 | #
107 | # 108 | # Open In Colab 109 | # 110 | #
111 | -------------------------------------------------------------------------------- /tutorial/03_figures/a_lesson_figures.py: -------------------------------------------------------------------------------- 1 | """ 2 | Lesson Overview 3 | ~~~~~~~~~~~~~~~ 4 | """ 5 | 6 | import pyvista as pv 7 | from pyvista import examples 8 | 9 | mesh = pv.Wavelet() 10 | 11 | ############################################################################### 12 | # ``add_mesh`` 13 | # ++++++++++++++ 14 | # 15 | # When plotting, users must first create a :class:`pyvista.Plotter` instance (much like a Matplotlib figure). Then data are added to the plotter instance through the :func:`pyvista.Plotter.add_mesh` method. This workflow typically looks like: 16 | 17 | p = pv.Plotter() 18 | p.add_mesh(mesh) 19 | p.show() 20 | 21 | ############################################################################### 22 | # You can customize how that mesh is displayed through the parameters of the :func:`pyvista.Plotter.add_mesh` method. For example, we can change the colormap via the ``cmap`` argument: 23 | 24 | p = pv.Plotter() 25 | p.add_mesh(mesh, cmap="coolwarm") 26 | p.show() 27 | 28 | ############################################################################### 29 | # Or show the edges of the mesh with ``show_edges``: 30 | 31 | p = pv.Plotter() 32 | p.add_mesh(mesh, show_edges=True) 33 | p.show() 34 | 35 | ############################################################################### 36 | # Or adjust the opacity to be a scalar value or linear transfer function via the ``opacity`` argument: 37 | 38 | mesh = examples.download_st_helens().warp_by_scalar() 39 | 40 | p = pv.Plotter() 41 | p.add_mesh(mesh, cmap="terrain", opacity="linear") 42 | p.show() 43 | 44 | ############################################################################### 45 | # Take a look at all of the options for `add_mesh `_. 46 | # 47 | # The ``add_mesh`` method can be called over and over to add different data to the same ``Plotter`` scene. For example, we can create many different mesh objects and plot them together: 48 | 49 | kinds = [ 50 | "tetrahedron", 51 | "cube", 52 | "octahedron", 53 | "dodecahedron", 54 | "icosahedron", 55 | ] 56 | centers = [ 57 | (0, 1, 0), 58 | (0, 0, 0), 59 | (0, 2, 0), 60 | (-1, 0, 0), 61 | (-1, 2, 0), 62 | ] 63 | 64 | solids = [pv.PlatonicSolid(kind, radius=0.4, center=center) for kind, center in zip(kinds, centers)] 65 | 66 | p = pv.Plotter(window_size=[1000, 1000]) 67 | for _ind, solid in enumerate(solids): 68 | p.add_mesh(solid, color="silver", specular=1.0, specular_power=10) 69 | p.view_vector((5.0, 2, 3)) 70 | p.add_floor("-z", lighting=True, color="tan", pad=1.0) 71 | p.enable_shadows() 72 | p.show() 73 | 74 | ############################################################################### 75 | # Subplotting 76 | # +++++++++++ 77 | # 78 | # Creating side-by-side comparisons of datasets is easy with PyVista's subplotting API. Get started by specifying the shape of the :class:`pyvista.Plotter` object then registering the active subplot by the :func:`pyvista.Plotter.subplot` method much like how you subplot with Matplotlib's API. 79 | p = pv.Plotter(shape=(1, 2)) 80 | 81 | p.subplot(0, 0) 82 | p.add_mesh(pv.Sphere()) 83 | 84 | p.subplot(0, 1) 85 | p.add_mesh(pv.Cube()) 86 | 87 | p.show() 88 | 89 | ############################################################################### 90 | # Below is an example of side-by-side comparisons of the contours and slices of a single dataset. 91 | # 92 | # .. tip:: 93 | # 94 | # You can link the cameras of both views with the :func:`pyvista.Plotter.link_views` method 95 | mesh = pv.Wavelet() 96 | cntr = mesh.contour() 97 | slices = mesh.slice_orthogonal() 98 | 99 | p = pv.Plotter(shape=(1, 2)) 100 | 101 | p.add_mesh(cntr) 102 | 103 | p.subplot(0, 1) 104 | p.add_mesh(slices) 105 | 106 | p.link_views() 107 | p.view_isometric() 108 | p.show() 109 | 110 | ############################################################################### 111 | # Axes and Bounds 112 | # +++++++++++++++ 113 | # 114 | # Axes can be added to the scene with :func:`pyvista.Plotter.show_axes` 115 | 116 | 117 | mesh = examples.load_random_hills() 118 | 119 | p = pv.Plotter() 120 | p.add_mesh(mesh) 121 | p.show_axes() 122 | p.show() 123 | 124 | ############################################################################### 125 | # And bounds similarly with :func:`pyvista.Plotter.show_bounds` 126 | # 127 | # .. tip:: 128 | # 129 | # See `Plotting Bounds `_ for more details. 130 | 131 | 132 | p = pv.Plotter() 133 | p.add_mesh(mesh) 134 | p.show_axes() 135 | p.show_bounds() 136 | p.show() 137 | 138 | ############################################################################### 139 | # .. raw:: html 140 | # 141 | #
142 | # 143 | # Open In Colab 144 | # 145 | #
146 | -------------------------------------------------------------------------------- /tutorial/03_figures/b_shading.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _shading_example: 3 | 4 | Types of Shading 5 | ~~~~~~~~~~~~~~~~ 6 | 7 | Comparison of default, flat shading vs. smooth shading. 8 | """ 9 | 10 | # sphinx_gallery_thumbnail_number = 4 11 | import pyvista as pv 12 | from pyvista import examples 13 | 14 | ############################################################################### 15 | # PyVista supports two types of shading: flat and smooth shading that uses 16 | # VTK's Phong shading algorithm. 17 | # 18 | # This is a plot with the default flat shading. 19 | mesh = examples.load_nut() 20 | mesh.plot() 21 | 22 | 23 | ############################################################################### 24 | # Here's the same sphere with smooth shading. 25 | mesh.plot(smooth_shading=True) 26 | 27 | 28 | ############################################################################### 29 | # Note how smooth shading makes edges that should be sharp look odd, 30 | # it's because the points of these normals are averaged between two 31 | # faces that have a sharp angle between them. You can avoid this by 32 | # enabling ``split_sharp_edges``. 33 | # 34 | # .. note:: 35 | # You can configure the splitting angle with the optional 36 | # ``feature_angle`` keyword argument. 37 | mesh.plot(smooth_shading=True, split_sharp_edges=True) 38 | 39 | 40 | ############################################################################### 41 | # We can even plot the edges that will be split using 42 | # :func:`extract_feature_edges `. 43 | 44 | # extract the feature edges exceeding 30 degrees 45 | edges = mesh.extract_feature_edges( 46 | boundary_edges=False, non_manifold_edges=False, feature_angle=30, manifold_edges=False 47 | ) 48 | 49 | # plot both the edges and the smoothed mesh 50 | pl = pv.Plotter() 51 | # pl.enable_anti_aliasing() 52 | pl.add_mesh(mesh, smooth_shading=True, split_sharp_edges=True) 53 | pl.add_mesh(edges, color="k", line_width=5) 54 | pl.show() 55 | 56 | 57 | ############################################################################### 58 | # The ``split_sharp_edges`` keyword argument is compatible with 59 | # physically based rendering as well. 60 | 61 | # plot both the edges and the smoothed mesh 62 | pl = pv.Plotter() 63 | # pl.enable_anti_aliasing() 64 | pl.add_mesh(mesh, color="w", split_sharp_edges=True, pbr=True, metallic=1.0, roughness=0.5) 65 | pl.show() 66 | 67 | ############################################################################### 68 | # .. raw:: html 69 | # 70 | #
71 | # 72 | # Open In Colab 73 | # 74 | #
75 | -------------------------------------------------------------------------------- /tutorial/03_figures/bonus/README.rst: -------------------------------------------------------------------------------- 1 | Bonus Content 2 | ~~~~~~~~~~~~~ 3 | -------------------------------------------------------------------------------- /tutorial/03_figures/bonus/d_pbr.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _pbr_example: 3 | 4 | Physically Based Rendering 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | VTK 9 introduced Physically Based Rendering (PBR) and we have exposed 8 | that functionality in PyVista. Read the `blog about PBR 9 | `_ for more details. 10 | 11 | PBR is only supported for :class:`pyvista.PolyData` and can be 12 | triggered via the ``pbr`` keyword argument of ``add_mesh``. Also use 13 | the ``metallic`` and ``roughness`` arguments for further control. 14 | 15 | Let's show off this functionality by rendering a high quality mesh of 16 | a statue as though it were metallic. 17 | 18 | """ 19 | 20 | from itertools import product 21 | 22 | import pyvista as pv 23 | from pyvista import examples 24 | 25 | # Load the statue mesh 26 | mesh = examples.download_nefertiti() 27 | mesh.rotate_x(-90.0, inplace=True) # rotate to orient with the skybox 28 | 29 | # Download skybox 30 | cubemap = examples.download_sky_box_cube_map() 31 | 32 | 33 | ############################################################################### 34 | # Let's render the mesh with a base color of "linen" to give it a metal looking 35 | # finish. 36 | p = pv.Plotter() 37 | p.add_actor(cubemap.to_skybox()) 38 | p.set_environment_texture(cubemap) # For reflecting the environment off the mesh 39 | p.add_mesh(mesh, color="linen", pbr=True, metallic=0.8, roughness=0.1, diffuse=1) 40 | 41 | # Define a nice camera perspective 42 | cpos = [(-313.40, 66.09, 1000.61), (0.0, 0.0, 0.0), (0.018, 0.99, -0.06)] 43 | 44 | p.show(cpos=cpos) 45 | 46 | 47 | ############################################################################### 48 | # Show the variation of the metallic and roughness parameters. 49 | # 50 | # Plot with metallic increasing from left to right and roughness 51 | # increasing from bottom to top. 52 | 53 | colors = ["red", "teal", "black", "orange", "silver"] 54 | 55 | p = pv.Plotter() 56 | p.set_environment_texture(cubemap) 57 | 58 | for i, j in product(range(5), range(6)): 59 | sphere = pv.Sphere(radius=0.5, center=(0.0, 4 - i, j)) 60 | p.add_mesh(sphere, color=colors[i], pbr=True, metallic=i / 4, roughness=j / 5) 61 | 62 | p.view_vector((-1, 0, 0), (0, 1, 0)) 63 | p.show() 64 | 65 | 66 | ############################################################################### 67 | # Combine custom lighting and physically based rendering. 68 | 69 | # download louis model 70 | mesh = examples.download_louis_louvre() 71 | mesh.rotate_z(140, inplace=True) 72 | 73 | 74 | plotter = pv.Plotter(lighting=None) 75 | plotter.set_background("black") 76 | plotter.add_mesh(mesh, color="linen", pbr=True, metallic=0.5, roughness=0.5, diffuse=1) 77 | 78 | 79 | # set up lighting 80 | light = pv.Light((-2, 2, 0), (0, 0, 0), "white") 81 | plotter.add_light(light) 82 | 83 | light = pv.Light((2, 0, 0), (0, 0, 0), (0.7, 0.0862, 0.0549)) 84 | plotter.add_light(light) 85 | 86 | light = pv.Light((0, 0, 10), (0, 0, 0), "white") 87 | plotter.add_light(light) 88 | 89 | 90 | # plot with a good camera position 91 | plotter.camera_position = [(9.51, 13.92, 15.81), (-2.836, -0.93, 10.2), (-0.22, -0.18, 0.959)] 92 | cpos = plotter.show() 93 | 94 | ############################################################################### 95 | # .. raw:: html 96 | # 97 | #
98 | # 99 | # Open In Colab 100 | # 101 | #
102 | -------------------------------------------------------------------------------- /tutorial/03_figures/bonus/e_labels.py: -------------------------------------------------------------------------------- 1 | """ 2 | Label Points 3 | ~~~~~~~~~~~~ 4 | 5 | Use string arrays in a point set to label points 6 | """ 7 | 8 | # sphinx_gallery_thumbnail_number = 3 9 | import numpy as np 10 | import pyvista as pv 11 | from pyvista import examples 12 | 13 | ############################################################################### 14 | # The :func:`pyvista.Plotter.add_point_labels` method makes it easy to add 15 | # point labels to a scene. 16 | help(pv.Plotter.add_point_labels) 17 | 18 | ############################################################################### 19 | # Label Point Cloud 20 | # ++++++++++++++++++ 21 | # 22 | # Let's make a random point cloud and label each point in 3D space 23 | 24 | # Make some random points 25 | poly = pv.PolyData(np.random.rand(10, 3)) 26 | 27 | ############################################################################### 28 | # Add string labels to the point data - this associates a label with every 29 | # node: 30 | 31 | poly["My Labels"] = [f"Label {i}" for i in range(poly.n_points)] 32 | poly 33 | 34 | ############################################################################### 35 | # Now plot the points with labels using :func:`pyvista.Plotter.add_point_labels` 36 | 37 | # (your code here, answer below) 38 | 39 | 40 | ############################################################################### 41 | plotter = pv.Plotter() 42 | plotter.add_point_labels(poly, "My Labels", point_size=20, font_size=36) 43 | plotter.show() 44 | 45 | 46 | ############################################################################### 47 | # Label Node Locations 48 | # ++++++++++++++++++++ 49 | # 50 | # This example will label the nodes of a mesh with their coordinate locations 51 | 52 | # Load example beam file 53 | grid = pv.UnstructuredGrid(examples.hexbeamfile) 54 | 55 | 56 | ############################################################################### 57 | # Create plotting class and add the unstructured grid 58 | plotter = pv.Plotter() 59 | plotter.add_mesh(grid, show_edges=True, color="tan") 60 | 61 | # Add labels to points on the yz plane (where x == 0) 62 | points = grid.points 63 | mask = points[:, 0] == 0 64 | plotter.add_point_labels(points[mask], points[mask].tolist(), point_size=20, font_size=36) 65 | 66 | plotter.camera_position = [(-1.5, 1.5, 3.0), (0.05, 0.6, 1.2), (0.2, 0.9, -0.25)] 67 | 68 | plotter.show() 69 | 70 | 71 | ############################################################################### 72 | # Label Scalar Values 73 | # +++++++++++++++++++ 74 | # 75 | # This example will label each point with their scalar values 76 | 77 | mesh = examples.load_uniform().slice() 78 | 79 | ############################################################################### 80 | p = pv.Plotter() 81 | 82 | # Add the mesh: 83 | p.add_mesh(mesh, scalars="Spatial Point Data", show_edges=True) 84 | # Add the points with scalar labels: 85 | p.add_point_scalar_labels(mesh, "Spatial Point Data", point_size=20, font_size=36) 86 | 87 | # Use a nice camera position: 88 | p.camera_position = [(7, 4, 5), (4.4, 7.0, 7.2), (0.8, 0.5, 0.25)] 89 | 90 | p.show() 91 | 92 | ############################################################################### 93 | # .. raw:: html 94 | # 95 | #
96 | # 97 | # Open In Colab 98 | # 99 | #
100 | -------------------------------------------------------------------------------- /tutorial/03_figures/bonus/g_orbit.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _orbiting_example: 3 | 4 | Orbiting 5 | ~~~~~~~~ 6 | 7 | Orbit around a scene. 8 | 9 | .. note:: 10 | The quality of the movie will be better when using 11 | ``p.open_movie('orbit.mp4')`` instead of 12 | ``p.open_gif('orbit.gif')`` 13 | 14 | For orbiting to work you first have to show the scene and leave the plotter open 15 | with ``.show(auto_close=False)``. You may also have to set 16 | ``pv.Plotter(off_screen=True)`` 17 | 18 | .. note:: 19 | Use ``lighting=False`` to reduce the size of the color space to avoid 20 | "jittery" GIFs when showing the scalar bar. 21 | 22 | """ 23 | 24 | # sphinx_gallery_thumbnail_number = 2 25 | import pyvista as pv 26 | from pyvista import examples 27 | 28 | mesh = examples.download_st_helens().warp_by_scalar() 29 | 30 | ############################################################################### 31 | # Orbit around the Mt. St Helens dataset. 32 | 33 | p = pv.Plotter() 34 | p.add_mesh(mesh, lighting=False) 35 | p.camera.zoom(1.5) 36 | p.show(auto_close=False) 37 | path = p.generate_orbital_path(n_points=36, shift=mesh.length) 38 | p.open_gif("orbit.gif") 39 | p.orbit_on_path(path, write_frames=True) 40 | p.close() 41 | 42 | 43 | ############################################################################### 44 | 45 | p = pv.Plotter() 46 | p.add_mesh(mesh, lighting=False) 47 | p.show_grid() 48 | p.show(auto_close=False) 49 | viewup = [0.5, 0.5, 1] 50 | path = p.generate_orbital_path(factor=2.0, shift=10000, viewup=viewup, n_points=36) 51 | p.open_gif("orbit.gif") 52 | p.orbit_on_path(path, write_frames=True, viewup=[0, 0, 1], step=0.05) 53 | p.close() 54 | 55 | 56 | ############################################################################### 57 | 58 | mesh = examples.download_dragon() 59 | viewup = [0, 1, 0] 60 | 61 | ############################################################################### 62 | p = pv.Plotter() 63 | p.add_mesh(mesh) 64 | p.show(auto_close=False) 65 | path = p.generate_orbital_path(factor=2.0, n_points=36, viewup=viewup, shift=0.2) 66 | p.open_gif("orbit.gif") 67 | p.orbit_on_path(path, write_frames=True, viewup=viewup, step=0.05) 68 | p.close() 69 | 70 | ############################################################################### 71 | # .. raw:: html 72 | # 73 | #
74 | # 75 | # Open In Colab 76 | # 77 | #
78 | -------------------------------------------------------------------------------- /tutorial/03_figures/c_geological-map.py: -------------------------------------------------------------------------------- 1 | """ 2 | Geological Map on Topography 3 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | 5 | Texture mapping for a GeoTIFF on a topography surface. 6 | 7 | To overlay an image/map from a GeoTIFF on to a topography surface, it's necessary to have texture coordinates ("texture mapping") matching the proper extends of the mesh/surface you'd like to drape the texture (GeoTIFF) on. 8 | 9 | We can do this by using the spatial reference of the GeoTIFF itself, as this allows you to preserve the entire mesh that the texture is being draped on without having to clip out the parts where you don't have imagery. In this example, we explicitly set the texture extents onto a topography surface where the texture/GeoTIFF has a much larger extent than the topography surface. 10 | 11 | Originally posted here: https://github.com/pyvista/pyvista-support/issues/14 12 | """ 13 | 14 | # sphinx_gallery_thumbnail_number = 2 15 | import os 16 | import tempfile 17 | 18 | import numpy as np 19 | import pyvista as pv 20 | import requests 21 | from pyvista import examples 22 | 23 | ############################################################################### 24 | path = examples.download_file("topo_clean.vtk") 25 | topo = pv.read(path) 26 | topo 27 | 28 | ############################################################################### 29 | # Load the GeoTIFF/texture (this could take a minute to download) 30 | # https://dl.dropbox.com/s/bp9j3fl3wbi0fld/downsampled_Geologic_map_on_air_photo.tif?dl=0 31 | url = "https://dl.dropbox.com/s/bp9j3fl3wbi0fld/downsampled_Geologic_map_on_air_photo.tif?dl=0" 32 | 33 | response = requests.get(url) # noqa: S113 34 | filename = os.path.join(tempfile.gettempdir(), "downsampled_Geologic_map_on_air_photo.tif") # noqa: PTH118 35 | open(filename, "wb").write(response.content) # noqa: SIM115, PTH123 36 | 37 | 38 | ############################################################################### 39 | # In the block below, we can use the ``get_gcps`` function to get the 40 | # Ground Control Points of the raster, however this depends on GDAL. For this 41 | # tutorial, we are going to hard code the GCPs to avoid having users install 42 | # GDAL. 43 | 44 | 45 | def get_gcps(filename): 46 | """ 47 | Helper function retrieves the Ground Control 48 | Points of a GeoTIFF. Note that this requires gdal. 49 | """ 50 | import rasterio 51 | 52 | def get_point(gcp): 53 | return np.array([gcp.x, gcp.y, gcp.z]) 54 | 55 | # Load a raster 56 | src = rasterio.open(filename) 57 | # Grab the Groung Control Points 58 | points = np.array([get_point(gcp) for gcp in src.gcps[0]]) 59 | # Now Grab the three corners of their bounding box 60 | # -- This guarantees we grab the right points 61 | bounds = pv.PolyData(points).bounds 62 | origin = [bounds[0], bounds[2], bounds[4]] # BOTTOM LEFT CORNER 63 | point_u = [bounds[1], bounds[2], bounds[4]] # BOTTOM RIGHT CORNER 64 | point_v = [bounds[0], bounds[3], bounds[4]] # TOP LEFT CORNER 65 | return origin, point_u, point_v 66 | 67 | 68 | ############################################################################### 69 | 70 | # Fetch the GCPs 71 | # origin, point_u, point_v = get_gcps(filename) 72 | 73 | # Hard code GCPs 74 | origin = [310967.75148705335, 4238841.045453942, 0.0] 75 | point_u = [358682.9364281533, 4238841.045453942, 0.0] 76 | point_v = [310967.75148705335, 4276281.98755258, 0.0] 77 | 78 | ############################################################################### 79 | 80 | # Use the GCPs to map the texture coordinates onto the topography surface 81 | topo.texture_map_to_plane(origin, point_u, point_v, inplace=True) 82 | 83 | ############################################################################### 84 | # Show GCPs in relation to topo surface with texture coordinates displayed 85 | p = pv.Plotter() 86 | p.add_point_labels( 87 | np.array( 88 | [ 89 | origin, 90 | point_u, 91 | point_v, 92 | ] 93 | ), 94 | ["Origin", "Point U", "Point V"], 95 | point_size=5, 96 | ) 97 | 98 | p.add_mesh(topo) 99 | p.show(cpos="xy") 100 | 101 | 102 | ############################################################################### 103 | # Read the GeoTIFF as a ``Texture`` in PyVista: 104 | texture = pv.read_texture(filename) 105 | 106 | # Now plot the topo surface with the texture draped over it 107 | # And make window size large for a high-res screenshot 108 | p = pv.Plotter(window_size=np.array([1024, 768]) * 3) 109 | p.add_mesh(topo, texture=texture) 110 | p.camera_position = [ 111 | (337461.4124956896, 4257141.430658634, 2738.4956020899253), 112 | (339000.40935731295, 4260394.940646875, 1724.0720826501868), 113 | (0.10526647627366331, 0.2502863297360612, 0.962432190920575), 114 | ] 115 | p.show() 116 | 117 | ############################################################################### 118 | # .. raw:: html 119 | # 120 | #
121 | # 122 | # Open In Colab 123 | # 124 | #
125 | -------------------------------------------------------------------------------- /tutorial/03_figures/d_gif.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _gif_movie_example: 3 | 4 | Create a GIF Movie 5 | ~~~~~~~~~~~~~~~~~~ 6 | Generate a moving gif from an active plotter. 7 | 8 | .. note:: 9 | Use ``lighting=False`` to reduce the size of the color space to avoid 10 | "jittery" GIFs, especially for the scalar bar. 11 | 12 | """ 13 | 14 | import numpy as np 15 | import pyvista as pv 16 | 17 | x = np.arange(-10, 10, 0.5) 18 | y = np.arange(-10, 10, 0.5) 19 | x, y = np.meshgrid(x, y) 20 | r = np.sqrt(x**2 + y**2) 21 | z = np.sin(r) 22 | 23 | # Create and structured surface 24 | grid = pv.StructuredGrid(x, y, z) 25 | 26 | # Create a plotter object and set the scalars to the Z height 27 | plotter = pv.Plotter(notebook=False, off_screen=True) 28 | plotter.add_mesh( 29 | grid, 30 | scalars=z.ravel(), 31 | lighting=False, 32 | show_edges=True, 33 | scalar_bar_args={"title": "Height"}, 34 | clim=[-1, 1], 35 | ) 36 | 37 | # Open a gif 38 | plotter.open_gif("wave.gif") 39 | 40 | pts = grid.points.copy() 41 | 42 | # Update Z and write a frame for each updated position 43 | nframe = 15 44 | for phase in np.linspace(0, 2 * np.pi, nframe + 1)[:nframe]: 45 | z = np.sin(r + phase) 46 | pts[:, -1] = z.ravel() 47 | plotter.update_coordinates(pts, render=False) 48 | plotter.update_scalars(z.ravel(), render=False) 49 | 50 | # Write a frame. This triggers a render. 51 | plotter.write_frame() 52 | 53 | # Closes and finalizes movie 54 | plotter.close() 55 | 56 | ############################################################################### 57 | # .. raw:: html 58 | # 59 | #
60 | # 61 | # Open In Colab 62 | # 63 | #
64 | -------------------------------------------------------------------------------- /tutorial/03_figures/exercises/README.rst: -------------------------------------------------------------------------------- 1 | Do it yourself 2 | ~~~~~~~~~~~~~~ 3 | -------------------------------------------------------------------------------- /tutorial/03_figures/exercises/a_display_options.py: -------------------------------------------------------------------------------- 1 | """ 2 | Display Options 3 | ~~~~~~~~~~~~~~~ 4 | 5 | Take a look at the different display options offered by the ``add_mesh`` method. 6 | """ 7 | 8 | import pyvista as pv 9 | from pyvista import examples 10 | 11 | mesh = examples.load_random_hills() 12 | 13 | p = pv.Plotter() 14 | p.add_mesh(mesh) 15 | p.show() 16 | 17 | ############################################################################### 18 | # Let's take a look at some different options for the ``add_mesh`` method to 19 | # alter how the above data are displayed. 20 | help(p.add_mesh) 21 | 22 | ############################################################################### 23 | # Plot that mesh with the edges of cells displayed 24 | p = pv.Plotter() 25 | p.add_mesh(mesh, ...) 26 | p.show() 27 | 28 | ############################################################################### 29 | # Plot that mesh with the colored edges and as a show the surface as a solid 30 | # color (use a named color!) 31 | p = pv.Plotter() 32 | p.add_mesh(mesh, ...) 33 | p.show() 34 | 35 | ############################################################################### 36 | # Display with a points representation style 37 | p = pv.Plotter() 38 | p.add_mesh(mesh, ...) 39 | p.show() 40 | 41 | ############################################################################### 42 | # And adjust the points display size 43 | p = pv.Plotter() 44 | p.add_mesh(mesh, ...) 45 | p.show() 46 | 47 | ############################################################################### 48 | # Change the color map and the color limits 49 | p = pv.Plotter() 50 | p.add_mesh(mesh, ...) 51 | p.show() 52 | 53 | ############################################################################### 54 | # Add some opacity 55 | p = pv.Plotter() 56 | p.add_mesh(mesh, ...) 57 | p.show() 58 | 59 | ############################################################################### 60 | # There you go! Those are a few of the most commonly used display options! 61 | 62 | ############################################################################### 63 | # .. raw:: html 64 | # 65 | #
66 | # 67 | # Open In Colab 68 | # 69 | #
70 | -------------------------------------------------------------------------------- /tutorial/03_figures/exercises/b_lighting_mesh.py: -------------------------------------------------------------------------------- 1 | """ 2 | Lighting Properties 3 | ~~~~~~~~~~~~~~~~~~~ 4 | 5 | Control aspects of the rendered mesh's lighting such as Ambient, Diffuse, 6 | and Specular. These options only work if the ``lighting`` argument to 7 | ``add_mesh`` is ``True`` (it's ``True`` by default). 8 | 9 | You can turn off all lighting for the given mesh by passing ``lighting=False`` 10 | to ``add_mesh``. 11 | 12 | See the ``add_mesh`` docs for lighting options: 13 | https://docs.pyvista.org/api/plotting/_autosummary/pyvista.Plotter.add_mesh.html 14 | """ 15 | 16 | # sphinx_gallery_thumbnail_number = 4 17 | import pyvista as pv 18 | from pyvista import examples 19 | 20 | mesh = examples.download_st_helens().warp_by_scalar() 21 | 22 | cpos = [(575848.0, 5128459.0, 22289.0), (562835.0, 5114981.5, 2294.5), (-0.5, -0.5, 0.7)] 23 | 24 | ############################################################################### 25 | # First, let's take a look at the mesh with default lighting conditions 26 | mesh.plot(cpos=cpos, show_scalar_bar=False) 27 | 28 | ############################################################################### 29 | # What about with no lighting? 30 | mesh.plot(..., cpos=cpos, show_scalar_bar=False) 31 | 32 | ############################################################################### 33 | # Demonstration of the specular property 34 | # 35 | # Feel free to adjust the specular value in the ``s`` variable. 36 | p = pv.Plotter(shape=(1, 2), window_size=[1500, 500]) 37 | 38 | p.subplot(0, 0) 39 | p.add_mesh(mesh, show_scalar_bar=False) 40 | p.add_text("No Specular") 41 | 42 | p.subplot(0, 1) 43 | specular = ... 44 | p.add_mesh(mesh, ..., show_scalar_bar=False) 45 | p.add_text(f"Specular of {specular}") 46 | 47 | p.link_views() 48 | p.view_isometric() 49 | p.show(cpos=cpos) 50 | 51 | ############################################################################### 52 | # Specular power (feel free to adjust) 53 | mesh.plot(..., cpos=cpos, show_scalar_bar=False) 54 | 55 | ############################################################################### 56 | # Demonstration of all diffuse, specular, and ambient in use together 57 | # (feel free to adjust) 58 | mesh.plot(..., cpos=cpos, show_scalar_bar=False) 59 | 60 | ############################################################################### 61 | # For detailed control over lighting conditions in general see the 62 | # `lighting examples `_ 63 | 64 | ############################################################################### 65 | # .. raw:: html 66 | # 67 | #
68 | # 69 | # Open In Colab 70 | # 71 | #
72 | -------------------------------------------------------------------------------- /tutorial/03_figures/exercises/c_edl.py: -------------------------------------------------------------------------------- 1 | """ 2 | Eye Dome Lighting 3 | ~~~~~~~~~~~~~~~~~ 4 | 5 | Eye-Dome Lighting (EDL) is a non-photorealistic, image-based shading technique 6 | designed to improve depth perception in scientific visualization images. 7 | To learn more, please see `this blog post`_. 8 | 9 | .. _this blog post: https://blog.kitware.com/eye-dome-lighting-a-non-photorealistic-shading-technique/ 10 | 11 | """ 12 | 13 | ############################################################################### 14 | 15 | # sphinx_gallery_thumbnail_number = 1 16 | import pyvista as pv 17 | from pyvista import examples 18 | 19 | ############################################################################### 20 | # Point Cloud 21 | # +++++++++++ 22 | # 23 | # When plotting a simple point cloud, it can be difficult to perceive depth. 24 | # Take this Lidar point cloud for example: 25 | 26 | point_cloud = examples.download_lidar() 27 | point_cloud 28 | 29 | ############################################################################### 30 | # And now plot this point cloud as-is: 31 | 32 | # Plot a typical point cloud with no EDL 33 | p = pv.Plotter() 34 | p.add_mesh(point_cloud, color="tan", point_size=5) 35 | p.show() 36 | 37 | 38 | ############################################################################### 39 | # We can improve the depth mapping by enabling eye dome lighting on the 40 | # renderer with :func:`pyvista.Renderer.enable_eye_dome_lighting`. 41 | # 42 | # Try plotting that point cloud with Eye-Dome-Lighting yourself below: 43 | 44 | p = pv.Plotter() 45 | p.add_mesh(point_cloud, color="tan", point_size=5) 46 | # Turn on eye dome lighting here 47 | p.show() 48 | 49 | 50 | ############################################################################### 51 | # The eye dome lighting mode can also handle plotting scalar arrays. Try the 52 | # above block but by specifying a ``scalars`` array instead of ``color`` in 53 | # the ``add_mesh`` call. 54 | 55 | ############################################################################### 56 | # .. raw:: html 57 | # 58 | #
59 | # 60 | # Open In Colab 61 | # 62 | #
63 | -------------------------------------------------------------------------------- /tutorial/03_figures/solutions/README.rst: -------------------------------------------------------------------------------- 1 | Solutions 2 | ~~~~~~~~~ 3 | -------------------------------------------------------------------------------- /tutorial/03_figures/solutions/a_display_options.py: -------------------------------------------------------------------------------- 1 | """ 2 | Display Options 3 | ~~~~~~~~~~~~~~~ 4 | 5 | Take a look at the different display options offered by the ``add_mesh`` method. 6 | """ 7 | 8 | import pyvista as pv 9 | from pyvista import examples 10 | 11 | mesh = examples.load_random_hills() 12 | 13 | p = pv.Plotter() 14 | p.add_mesh(mesh) 15 | p.show() 16 | 17 | ############################################################################### 18 | # Let's take a look at some different options for the ``add_mesh`` method to 19 | # alter how the above data are displayed. 20 | # 21 | # See also https://docs.pyvista.org/api/plotting/_autosummary/pyvista.Plotter.add_mesh.html 22 | help(p.add_mesh) 23 | 24 | ############################################################################### 25 | # Plot that mesh with the edges of cells displayed 26 | p = pv.Plotter() 27 | p.add_mesh(mesh, show_edges=True) 28 | p.show() 29 | 30 | ############################################################################### 31 | # Plot that mesh with the colored edges and as a show the surface as a solid 32 | # color (use a named color!) 33 | p = pv.Plotter() 34 | p.add_mesh(mesh, color="magenta", show_edges=True, edge_color="blue") 35 | p.show() 36 | 37 | ############################################################################### 38 | # Display with a points representation style 39 | p = pv.Plotter() 40 | p.add_mesh(mesh, style="points") 41 | p.show() 42 | 43 | ############################################################################### 44 | # And adjust the points display size 45 | p = pv.Plotter() 46 | p.add_mesh(mesh, style="points", point_size=10, render_points_as_spheres=True) 47 | p.show() 48 | 49 | ############################################################################### 50 | # Change the color map and the color limits 51 | p = pv.Plotter() 52 | p.add_mesh(mesh, cmap="terrain", clim=[2, 5]) 53 | p.show() 54 | 55 | ############################################################################### 56 | # Add some opacity 57 | p = pv.Plotter() 58 | p.add_mesh(mesh, cmap="terrain", clim=[2, 5], opacity="linear") 59 | p.show() 60 | 61 | ############################################################################### 62 | # There you go! Those are a few of the most commonly used display options! 63 | 64 | ############################################################################### 65 | # .. raw:: html 66 | # 67 | #
68 | # 69 | # Open In Colab 70 | # 71 | #
72 | -------------------------------------------------------------------------------- /tutorial/03_figures/solutions/b_lighting_mesh.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _ref_lighting_properties_example: 3 | 4 | Lighting Properties 5 | ~~~~~~~~~~~~~~~~~~~ 6 | 7 | Control aspects of the rendered mesh's lighting such as Ambient, Diffuse, 8 | and Specular. These options only work if the ``lighting`` argument to 9 | ``add_mesh`` is ``True`` (it's ``True`` by default). 10 | 11 | You can turn off all lighting for the given mesh by passing ``lighting=False`` 12 | to ``add_mesh``. 13 | 14 | See the ``add_mesh`` docs for lighting options: 15 | https://docs.pyvista.org/api/plotting/_autosummary/pyvista.Plotter.add_mesh.html 16 | """ 17 | 18 | # sphinx_gallery_thumbnail_number = 4 19 | import pyvista as pv 20 | from pyvista import examples 21 | 22 | mesh = examples.download_st_helens().warp_by_scalar() 23 | 24 | cpos = [(575848.0, 5128459.0, 22289.0), (562835.0, 5114981.5, 2294.5), (-0.5, -0.5, 0.7)] 25 | 26 | ############################################################################### 27 | # First, lets take a look at the mesh with default lighting conditions 28 | mesh.plot(cpos=cpos, show_scalar_bar=False) 29 | 30 | ############################################################################### 31 | # What about with no lighting? 32 | mesh.plot(lighting=False, cpos=cpos, show_scalar_bar=False) 33 | 34 | ############################################################################### 35 | # Demonstration of the specular property 36 | # 37 | # Feel free to adjust the specular value in the ``s`` variable. 38 | p = pv.Plotter(shape=(1, 2), window_size=[1500, 500]) 39 | 40 | p.subplot(0, 0) 41 | p.add_mesh(mesh, show_scalar_bar=False) 42 | p.add_text("No Specular") 43 | 44 | p.subplot(0, 1) 45 | specular = 1.0 46 | p.add_mesh(mesh, specular=specular, show_scalar_bar=False) 47 | p.add_text(f"Specular of {specular}") 48 | 49 | p.link_views() 50 | p.view_isometric() 51 | p.show(cpos=cpos) 52 | 53 | ############################################################################### 54 | # Specular power (feel free to adjust) 55 | mesh.plot(specular=0.5, specular_power=15, cpos=cpos, show_scalar_bar=False) 56 | 57 | ############################################################################### 58 | # Demonstration of all diffuse, specular, and ambient in use together 59 | # (feel free to adjust) 60 | mesh.plot(diffuse=0.5, specular=0.5, ambient=0.5, cpos=cpos, show_scalar_bar=False) 61 | 62 | ############################################################################### 63 | # For detailed control over lighting conditions in general see the 64 | # `lighting examples `_ 65 | 66 | ############################################################################### 67 | # .. raw:: html 68 | # 69 | #
70 | # 71 | # Open In Colab 72 | # 73 | #
74 | -------------------------------------------------------------------------------- /tutorial/03_figures/solutions/c_edl.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _ref_edl: 3 | 4 | Eye Dome Lighting 5 | ~~~~~~~~~~~~~~~~~ 6 | 7 | Eye-Dome Lighting (EDL) is a non-photorealistic, image-based shading technique 8 | designed to improve depth perception in scientific visualization images. 9 | To learn more, please see `this blog post`_. 10 | 11 | .. _this blog post: https://blog.kitware.com/eye-dome-lighting-a-non-photorealistic-shading-technique/ 12 | 13 | """ 14 | 15 | ############################################################################### 16 | 17 | # sphinx_gallery_thumbnail_number = 1 18 | import pyvista as pv 19 | from pyvista import examples 20 | 21 | ############################################################################### 22 | # Point Cloud 23 | # +++++++++++ 24 | # 25 | # When plotting a simple point cloud, it can be difficult to perceive depth. 26 | # Take this Lidar point cloud for example: 27 | 28 | point_cloud = examples.download_lidar() 29 | point_cloud 30 | 31 | ############################################################################### 32 | # And now plot this point cloud as-is: 33 | 34 | # Plot a typical point cloud with no EDL 35 | p = pv.Plotter() 36 | p.add_mesh(point_cloud, color="tan", point_size=5) 37 | p.show() 38 | 39 | 40 | ############################################################################### 41 | # We can improve the depth mapping by enabling eye dome lighting on the 42 | # renderer with :func:`pyvista.Renderer.enable_eye_dome_lighting`. 43 | # 44 | # Try plotting that point cloud with Eye-Dome-Lighting yourself below: 45 | 46 | p = pv.Plotter() 47 | p.add_mesh(point_cloud, color="tan", point_size=5) 48 | p.enable_eye_dome_lighting() # Turn on eye dome lighting here 49 | p.show() 50 | 51 | 52 | ############################################################################### 53 | # The eye dome lighting mode can also handle plotting scalar arrays. Try the 54 | # above block but by specifying a ``scalars`` array instead of ``color`` in 55 | # the ``add_mesh`` call. 56 | 57 | p = pv.Plotter() 58 | p.add_mesh(point_cloud, scalars="Elevation", point_size=5) 59 | p.enable_eye_dome_lighting() # Turn on eye dome lighting here 60 | p.show() 61 | 62 | ############################################################################### 63 | # .. raw:: html 64 | # 65 | #
66 | # 67 | # Open In Colab 68 | # 69 | #
70 | -------------------------------------------------------------------------------- /tutorial/04_filters/bonus/README.rst: -------------------------------------------------------------------------------- 1 | Bonus Content 2 | ~~~~~~~~~~~~~ 3 | -------------------------------------------------------------------------------- /tutorial/04_filters/bonus/f_sampling_functions_3d.py: -------------------------------------------------------------------------------- 1 | """ 2 | Sample Function: Perlin Noise in 3D 3 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | Here we use :func:`pyvista.core.utilities.features.sample_function` to sample 5 | Perlin noise over a region to generate random terrain. 6 | 7 | Video games like Minecraft use Perlin noise to create terrain. Here, 8 | we create a voxelized mesh similar to a Minecraft "cave". 9 | 10 | """ 11 | 12 | import pyvista as pv 13 | 14 | ############################################################################### 15 | # Generate Perlin Noise over a 3D StructuredGrid 16 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 17 | # Feel free to change the values of ``freq`` to change the shape of 18 | # the "caves". For example, lowering the frequency will make the 19 | # caves larger and more expansive, while a higher frequency in any 20 | # direction will make the caves appear more "vein-like" and less open. 21 | # 22 | # Change the threshold to reduce or increase the percent of the 23 | # terrain that is open or closed 24 | 25 | freq = (1, 1, 1) 26 | noise = pv.perlin_noise(1, freq, (0, 0, 0)) 27 | grid = pv.sample_function(noise, [0, 3.0, -0, 1.0, 0, 1.0], dim=(120, 40, 40)) 28 | out = grid.threshold(0.02) 29 | out 30 | 31 | ############################################################################### 32 | # color limits without blue 33 | mn, mx = [out["scalars"].min(), out["scalars"].max()] 34 | clim = (mn, mx * 1.8) 35 | 36 | out.plot( 37 | cmap="gist_earth_r", 38 | background="white", 39 | show_scalar_bar=False, 40 | lighting=True, 41 | clim=clim, 42 | show_edges=False, 43 | ) 44 | 45 | ############################################################################### 46 | # .. raw:: html 47 | # 48 | #
49 | # 50 | # Open In Colab 51 | # 52 | #
53 | -------------------------------------------------------------------------------- /tutorial/04_filters/exercises/README.rst: -------------------------------------------------------------------------------- 1 | Do it yourself 2 | ~~~~~~~~~~~~~~ 3 | -------------------------------------------------------------------------------- /tutorial/04_filters/exercises/b_clipping.py: -------------------------------------------------------------------------------- 1 | """ 2 | Clipping with Planes & Boxes 3 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | 5 | Clip/cut any dataset using using planes or boxes. 6 | """ 7 | 8 | # sphinx_gallery_thumbnail_number = 2 9 | import pyvista as pv 10 | from pyvista import examples 11 | 12 | ############################################################################### 13 | # Clip with Plane 14 | # +++++++++++++++ 15 | # 16 | # Clip any dataset by a user defined plane using the 17 | # :func:`pyvista.DataSetFilters.clip` filter 18 | dataset = examples.download_bunny_coarse() 19 | dataset 20 | 21 | ############################################################################### 22 | help(dataset.clip) 23 | 24 | ############################################################################### 25 | # Perform a clip with a Y axis normal 26 | clipped = ... 27 | clipped 28 | 29 | ############################################################################### 30 | # Plot the result. 31 | p = pv.Plotter() 32 | p.add_mesh(dataset, style="wireframe", color="blue", label="Input") 33 | p.add_mesh(clipped, label="Clipped") 34 | p.add_legend() 35 | p.camera_position = [(0.24, 0.32, 0.7), (0.02, 0.03, -0.02), (-0.12, 0.93, -0.34)] 36 | p.show() 37 | 38 | 39 | ############################################################################### 40 | # Clip with Bounds 41 | # ++++++++++++++++ 42 | # 43 | # Clip any dataset by a set of XYZ bounds using the 44 | # :func:`pyvista.DataSetFilters.clip_box` filter. 45 | # 46 | # First, download an example dataset. 47 | dataset = examples.download_office() 48 | 49 | ############################################################################### 50 | help(dataset.clip_box) 51 | 52 | ############################################################################### 53 | # Clip the dataset with a bounding box defined by the values in ``bounds`` 54 | # ``(xmin, xmax, ymin, ymax, zmin, zmax)`` 55 | bounds = [2, 4.5, 2, 4.5, 1, 3] 56 | clipped = ... 57 | clipped 58 | 59 | ############################################################################### 60 | # Plot the original dataset and the clipped one. 61 | p = pv.Plotter() 62 | p.add_mesh(dataset, style="wireframe", color="blue", label="Input") 63 | p.add_mesh(clipped, label="Clipped") 64 | p.add_legend() 65 | p.show() 66 | 67 | 68 | ############################################################################### 69 | # Clip with Rotated Box 70 | # +++++++++++++++++++++ 71 | # 72 | # Clip any dataset by an arbitrarily rotated solid box using the 73 | # :func:`pyvista.DataSetFilters.clip_box` filter. 74 | mesh = examples.load_airplane() 75 | 76 | # Use `pv.Box()` or `pv.Cube()` to create a region of interest 77 | roi = pv.Cube(center=(0.9e3, 0.2e3, mesh.center[2]), x_length=500, y_length=500, z_length=500) 78 | roi.rotate_z(33, inplace=True) 79 | 80 | p = pv.Plotter() 81 | p.add_mesh(roi, opacity=0.75, color="red") 82 | p.add_mesh(mesh, opacity=0.5) 83 | p.show() 84 | 85 | ############################################################################### 86 | # Run the box clipping algorithm with the defined box geometry. 87 | extracted = ... 88 | 89 | p = pv.Plotter(shape=(1, 2)) 90 | p.add_mesh(roi, opacity=0.75, color="red") 91 | p.add_mesh(mesh) 92 | p.subplot(0, 1) 93 | p.add_mesh(extracted) 94 | p.add_mesh(roi, opacity=0.75, color="red") 95 | p.link_views() 96 | p.view_isometric() 97 | p.show() 98 | 99 | ############################################################################### 100 | # Crinkled Clipping 101 | # +++++++++++++++++ 102 | # Crinkled clipping is useful if you don't want the clip filter to truly clip 103 | # cells on the boundary, but want to preserve the input cell structure and to 104 | # pass the entire cell on through the boundary. 105 | # 106 | # This option is available for :func:`pyvista.DataSetFilters.clip`, 107 | # :func:`pyvista.DataSetFilters.clip_box`, and 108 | # :func:`pyvista.DataSetFilters.clip_sruface`, but not available when clipping 109 | # by scalar in :func:`pyvista.DataSetFilters.clip_scalar`. 110 | 111 | # Input mesh 112 | mesh = pv.Wavelet() 113 | 114 | ############################################################################### 115 | # Define clipping plane 116 | normal = (1, 1, 1) 117 | plane = pv.Plane(i_size=30, j_size=30, direction=normal) 118 | 119 | ############################################################################### 120 | # Perform a standard clip 121 | clipped = mesh.clip(normal=normal) 122 | 123 | ############################################################################### 124 | # Perform a crinkled clip to compare 125 | crinkled = mesh.clip(..., normal=normal) 126 | 127 | ############################################################################### 128 | # Plot comparison 129 | p = pv.Plotter(shape=(1, 2)) 130 | p.add_mesh(clipped, show_edges=True) 131 | p.add_mesh(plane.extract_feature_edges(), color="r") 132 | p.subplot(0, 1) 133 | p.add_mesh(crinkled, show_edges=True) 134 | p.add_mesh(plane.extract_feature_edges(), color="r") 135 | p.link_views() 136 | p.show() 137 | 138 | ############################################################################### 139 | # .. raw:: html 140 | # 141 | #
142 | # 143 | # Open In Colab 144 | # 145 | #
146 | -------------------------------------------------------------------------------- /tutorial/04_filters/exercises/c_compute-normals.py: -------------------------------------------------------------------------------- 1 | """ 2 | Computing Surface Normals 3 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | 5 | 6 | Compute normals on a surface. 7 | """ 8 | 9 | import numpy as np 10 | 11 | # sphinx_gallery_thumbnail_number = 2 12 | from pyvista import examples 13 | 14 | mesh = examples.download_topo_global() 15 | mesh.plot(cmap="gist_earth", show_scalar_bar=False) 16 | 17 | ############################################################################### 18 | # Now we have a surface dataset of the globe loaded - unfortunately, the 19 | # dataset shows the globe with a uniform radius which hides topographic relief. 20 | # Using :func:`pyvista.PolyData.compute_normals`, we can compute the normal 21 | # vectors on the globe at all points in the dataset, then use the values given 22 | # in the dataset to warp the surface in the normals direction to create some 23 | # exaggerated topographic relief. 24 | 25 | # Compute the normals in-place and use them to warp the globe 26 | 27 | ############################################################################### 28 | # Now use those normals to warp the surface 29 | warp = mesh.warp_by_scalar(factor=0.5e-5) 30 | 31 | ############################################################################### 32 | # And let's see it! 33 | warp.plot(cmap="gist_earth", show_scalar_bar=False) 34 | 35 | 36 | ############################################################################### 37 | # We could also use face or cell normals to extract all the faces of a mesh 38 | # facing a general direction. In the following snippet, we take a mesh, compute 39 | # the normals along its cell faces, and extract the faces that face upward. 40 | 41 | mesh = examples.download_nefertiti() 42 | # Compute normals 43 | mesh.compute_normals(...) 44 | 45 | # Get list of cell IDs that meet condition 46 | ids = np.arange(mesh.n_cells)[mesh["Normals"][...] > ...] 47 | 48 | # Extract those cells 49 | top = mesh.extract_cells(ids) 50 | 51 | cpos = [ 52 | (-834.3184529757553, -918.4677714398535, 236.5468795300025), 53 | (11.03829376004883, -13.642289291587957, -35.91218884207208), 54 | (0.19212361465657216, 0.11401076390090074, 0.9747256344254143), 55 | ] 56 | 57 | top.plot(cpos=cpos, color=True) 58 | 59 | ############################################################################### 60 | # .. raw:: html 61 | # 62 | #
63 | # 64 | # Open In Colab 65 | # 66 | #
67 | -------------------------------------------------------------------------------- /tutorial/04_filters/exercises/d_contouring.py: -------------------------------------------------------------------------------- 1 | """ 2 | Contouring 3 | ~~~~~~~~~~ 4 | 5 | Generate iso-lines or -surfaces for the scalars of a surface or volume. 6 | 7 | 3D meshes can have 2D iso-surfaces of a scalar field extracted and 2D surface 8 | meshes can have 1D iso-lines of a scalar field extracted. 9 | """ 10 | 11 | import pyvista as pv 12 | from pyvista import examples 13 | 14 | ############################################################################### 15 | # Iso-Lines 16 | # +++++++++ 17 | # 18 | # Let's extract 1D iso-lines of a scalar field from a 2D surface mesh. 19 | mesh = examples.load_random_hills() 20 | 21 | ############################################################################### 22 | help(mesh.contour) 23 | 24 | ############################################################################### 25 | contours = ... 26 | 27 | ############################################################################### 28 | p = pv.Plotter() 29 | p.add_mesh(mesh, opacity=0.85) 30 | p.add_mesh(contours, color="white", line_width=5) 31 | p.show() 32 | 33 | 34 | ############################################################################### 35 | # Iso-Surfaces 36 | # ++++++++++++ 37 | # 38 | # Let's extract 2D iso-surfaces of a scalar field from a 3D mesh. 39 | 40 | mesh = examples.download_embryo() 41 | mesh 42 | 43 | ############################################################################### 44 | # For this example dataset, let's create 5 contour levels between the values 45 | # of 50 and 200 46 | 47 | contours = ... 48 | 49 | ############################################################################### 50 | p = pv.Plotter() 51 | p.add_mesh(mesh.outline(), color="k") 52 | p.add_mesh(contours, opacity=0.25, clim=[0, 200]) 53 | p.camera_position = [ 54 | (-130.99381142132086, 644.4868354828589, 163.80447435848686), 55 | (125.21748748157661, 123.94368717158413, 108.83283586619626), 56 | (0.2780372840777734, 0.03547871361794171, 0.9599148553609699), 57 | ] 58 | p.show() 59 | 60 | ############################################################################### 61 | # .. raw:: html 62 | # 63 | #
64 | # 65 | # Open In Colab 66 | # 67 | #
68 | -------------------------------------------------------------------------------- /tutorial/04_filters/exercises/e_glyphs.py: -------------------------------------------------------------------------------- 1 | """ 2 | Plotting Glyphs (Vectors or PolyData) 3 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | 5 | Use vectors in a dataset to plot and orient glyphs/geometric objects. 6 | """ 7 | 8 | import numpy as np 9 | import pyvista as pv 10 | from pyvista import examples 11 | 12 | ############################################################################### 13 | # Example dataset with normals 14 | mesh = examples.load_random_hills() 15 | 16 | ############################################################################### 17 | # Glyphying can be done via the :func:`pyvista.DataSetFilters.glyph` filter 18 | help(mesh.glyph) 19 | 20 | ############################################################################### 21 | # Sometimes you might not want glyphs for every node in the input dataset. In 22 | # this case, you can choose to build glyphs for a subset of the input dataset 23 | # by using a merging tolerance. Here we specify a merging tolerance of five 24 | # percent which equates to five percent of the bounding box's length. 25 | # 26 | # create a subset of arrows using the glyph filter 27 | arrows = ... 28 | 29 | 30 | ############################################################################### 31 | p = pv.Plotter() 32 | p.add_mesh(arrows, color="black") 33 | p.add_mesh(mesh, scalars="Elevation", cmap="terrain", smooth_shading=True) 34 | p.show() 35 | 36 | ############################################################################### 37 | # A common approach is to load vectors directly to the mesh object and then 38 | # access the :attr:`pyvista.DataSet.arrows` property to produce glyphs. 39 | 40 | sphere = pv.Sphere(radius=3.14) 41 | 42 | # make cool swirly pattern 43 | vectors = np.vstack( 44 | ( 45 | np.sin(sphere.points[:, 0]), 46 | np.cos(sphere.points[:, 1]), 47 | np.cos(sphere.points[:, 2]), 48 | ) 49 | ).T 50 | vectors 51 | 52 | 53 | ############################################################################### 54 | 55 | # add and scale 56 | sphere["vectors"] = vectors * 0.3 57 | sphere.set_active_vectors("vectors") 58 | 59 | # plot just the arrows 60 | sphere.arrows.plot() 61 | 62 | ############################################################################### 63 | # Plot the arrows and the sphere. 64 | p = pv.Plotter() 65 | p.add_mesh(sphere.arrows, lighting=False, scalar_bar_args={"title": "Vector Magnitude"}) 66 | p.add_mesh(sphere, color="grey", ambient=0.6, opacity=0.5, show_edges=False) 67 | p.show() 68 | 69 | ############################################################################### 70 | # .. raw:: html 71 | # 72 | #
73 | # 74 | # Open In Colab 75 | # 76 | #
77 | -------------------------------------------------------------------------------- /tutorial/04_filters/solutions/README.rst: -------------------------------------------------------------------------------- 1 | Solutions 2 | ~~~~~~~~~ 3 | -------------------------------------------------------------------------------- /tutorial/04_filters/solutions/c_compute-normals.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _surface_normal_example: 3 | 4 | Computing Surface Normals 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | 8 | Compute normals on a surface. 9 | """ 10 | 11 | import numpy as np 12 | 13 | # sphinx_gallery_thumbnail_number = 2 14 | from pyvista import examples 15 | 16 | mesh = examples.download_topo_global() 17 | mesh.plot(cmap="gist_earth", show_scalar_bar=False) 18 | 19 | ############################################################################### 20 | # Now we have a surface dataset of the globe loaded - unfortunately, the 21 | # dataset shows the globe with a uniform radius which hides topographic relief. 22 | # Using :func:`pyvista.PolyData.compute_normals`, we can compute the normal 23 | # vectors on the globe at all points in the dataset, then use the values given 24 | # in the dataset to warp the surface in the normals direction to create some 25 | # exaggerated topographic relief. 26 | 27 | # Compute the normals in-place and use them to warp the globe 28 | mesh.compute_normals(inplace=True) # this activates the normals as well 29 | 30 | ############################################################################### 31 | # Now use those normals to warp the surface 32 | warp = mesh.warp_by_scalar(factor=0.5e-5) 33 | 34 | ############################################################################### 35 | # And let's see it! 36 | warp.plot(cmap="gist_earth", show_scalar_bar=False) 37 | 38 | 39 | ############################################################################### 40 | # We could also use face or cell normals to extract all the faces of a mesh 41 | # facing a general direction. In the following snippet, we take a mesh, compute 42 | # the normals along its cell faces, and extract the faces that face upward. 43 | 44 | mesh = examples.download_nefertiti() 45 | # Compute normals 46 | mesh.compute_normals(cell_normals=True, point_normals=False, inplace=True) 47 | 48 | # Get list of cell IDs that meet condition 49 | ids = np.arange(mesh.n_cells)[mesh["Normals"][:, 2] > 0.0] 50 | 51 | # Extract those cells 52 | top = mesh.extract_cells(ids) 53 | 54 | cpos = [ 55 | (-834.3184529757553, -918.4677714398535, 236.5468795300025), 56 | (11.03829376004883, -13.642289291587957, -35.91218884207208), 57 | (0.19212361465657216, 0.11401076390090074, 0.9747256344254143), 58 | ] 59 | 60 | top.plot(cpos=cpos, color=True) 61 | 62 | ############################################################################### 63 | # .. raw:: html 64 | # 65 | #
66 | # 67 | # Open In Colab 68 | # 69 | #
70 | -------------------------------------------------------------------------------- /tutorial/04_filters/solutions/d_contouring.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _contouring_example: 3 | 4 | Contouring 5 | ~~~~~~~~~~ 6 | 7 | Generate iso-lines or -surfaces for the scalars of a surface or volume. 8 | 9 | 3D meshes can have 2D iso-surfaces of a scalar field extracted and 2D surface 10 | meshes can have 1D iso-lines of a scalar field extracted. 11 | """ 12 | 13 | import numpy as np 14 | import pyvista as pv 15 | from pyvista import examples 16 | 17 | ############################################################################### 18 | # Iso-Lines 19 | # +++++++++ 20 | # 21 | # Let's extract 1D iso-lines of a scalar field from a 2D surface mesh. 22 | mesh = examples.load_random_hills() 23 | 24 | ############################################################################### 25 | help(mesh.contour) 26 | 27 | ############################################################################### 28 | contours = mesh.contour() 29 | 30 | ############################################################################### 31 | p = pv.Plotter() 32 | p.add_mesh(mesh, opacity=0.85) 33 | p.add_mesh(contours, color="white", line_width=5) 34 | p.show() 35 | 36 | 37 | ############################################################################### 38 | # Iso-Surfaces 39 | # ++++++++++++ 40 | # 41 | # Let's extract 2D iso-surfaces of a scalar field from a 3D mesh. 42 | 43 | mesh = examples.download_embryo() 44 | mesh 45 | 46 | ############################################################################### 47 | # For this example dataset, let's create 5 contour levels between the values 48 | # of 50 and 200 49 | 50 | contours = mesh.contour(np.linspace(50, 200, 5)) 51 | 52 | ############################################################################### 53 | p = pv.Plotter() 54 | p.add_mesh(mesh.outline(), color="k") 55 | p.add_mesh(contours, opacity=0.25, clim=[0, 200]) 56 | p.camera_position = [ 57 | (-130.99381142132086, 644.4868354828589, 163.80447435848686), 58 | (125.21748748157661, 123.94368717158413, 108.83283586619626), 59 | (0.2780372840777734, 0.03547871361794171, 0.9599148553609699), 60 | ] 61 | p.show() 62 | 63 | ############################################################################### 64 | # .. raw:: html 65 | # 66 | #
67 | # 68 | # Open In Colab 69 | # 70 | #
71 | -------------------------------------------------------------------------------- /tutorial/04_filters/solutions/e_glyphs.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _glyph_example: 3 | 4 | Plotting Glyphs (Vectors or PolyData) 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | Use vectors in a dataset to plot and orient glyphs/geometric objects. 8 | """ 9 | 10 | import numpy as np 11 | import pyvista as pv 12 | from pyvista import examples 13 | 14 | ############################################################################### 15 | # Example dataset with normals 16 | mesh = examples.load_random_hills() 17 | 18 | ############################################################################### 19 | # Glyphying can be done via the :func:`pyvista.DataSetFilters.glyph` filter 20 | help(mesh.glyph) 21 | 22 | ############################################################################### 23 | # Sometimes you might not want glyphs for every node in the input dataset. In 24 | # this case, you can choose to build glyphs for a subset of the input dataset 25 | # by using a merging tolerance. Here we specify a merging tolerance of five 26 | # percent which equates to five percent of the bounding box's length. 27 | # 28 | # create a subset of arrows using the glyph filter 29 | arrows = mesh.glyph(scale="Normals", orient="Normals", tolerance=0.05) 30 | 31 | 32 | ############################################################################### 33 | p = pv.Plotter() 34 | p.add_mesh(arrows, color="black") 35 | p.add_mesh(mesh, scalars="Elevation", cmap="terrain", smooth_shading=True) 36 | p.show() 37 | 38 | ############################################################################### 39 | # A common approach is to load vectors directly to the mesh object and then 40 | # access the :attr:`pyvista.DataSet.arrows` property to produce glyphs. 41 | 42 | sphere = pv.Sphere(radius=3.14) 43 | 44 | # make cool swirly pattern 45 | vectors = np.vstack( 46 | ( 47 | np.sin(sphere.points[:, 0]), 48 | np.cos(sphere.points[:, 1]), 49 | np.cos(sphere.points[:, 2]), 50 | ) 51 | ).T 52 | vectors 53 | 54 | 55 | ############################################################################### 56 | 57 | # add and scale 58 | sphere["vectors"] = vectors * 0.3 59 | sphere.set_active_vectors("vectors") 60 | 61 | # plot just the arrows 62 | sphere.arrows.plot() 63 | 64 | ############################################################################### 65 | # Plot the arrows and the sphere. 66 | p = pv.Plotter() 67 | p.add_mesh(sphere.arrows, lighting=False, scalar_bar_args={"title": "Vector Magnitude"}) 68 | p.add_mesh(sphere, color="grey", ambient=0.6, opacity=0.5, show_edges=False) 69 | p.show() 70 | 71 | ############################################################################### 72 | # .. raw:: html 73 | # 74 | #
75 | # 76 | # Open In Colab 77 | # 78 | #
79 | -------------------------------------------------------------------------------- /tutorial/05_action/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2021-2023, Bill Little 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /tutorial/05_action/README.rst: -------------------------------------------------------------------------------- 1 | .. include:: ./external_gallery.txt 2 | 3 | Exercises 4 | --------- 5 | 6 | See `GeoVista tutorial `_ . 7 | -------------------------------------------------------------------------------- /tutorial/06_vtk/a_2_pyvista_vtk.py: -------------------------------------------------------------------------------- 1 | """ 2 | PyVista and VTK Together 3 | ~~~~~~~~~~~~~~~~~~~~~~~~ 4 | 5 | PyVista is best known for is easy to use plotting API -- being familiar to most Python users already experienced with libraries like Matplotlib. Many people benefit from combining the power of VTK's Python bindings for their data pipelines and the flexibility and simplicity of PyVista for 3D rendering. The following section demonstrates this usage scenario. 6 | 7 | .. tip:: 8 | 9 | In case it was not made clear in the :ref:`mesh` section, PyVista mesh classes are subclasses of their VTK counterparts - which means PyVista can be intermixed with VTK workflows. 10 | 11 | Nothing stops you from using VTK classes and then wrapping 12 | the output with PyVista for streamlined plotting. For example: 13 | 14 | """ 15 | 16 | import pyvista as pv 17 | import vtk 18 | from pyvista import examples 19 | 20 | ############################################################################### 21 | # Create a circle using vtk 22 | polygonSource = vtk.vtkRegularPolygonSource() # noqa: N816 23 | polygonSource.GeneratePolygonOff() 24 | polygonSource.SetNumberOfSides(50) 25 | polygonSource.SetRadius(5.0) 26 | polygonSource.SetCenter(0.0, 0.0, 0.0) 27 | polygonSource.Update() 28 | 29 | ############################################################################### 30 | # wrap and plot using pyvista 31 | mesh = pv.wrap(polygonSource.GetOutput()) 32 | mesh.plot(line_width=3, cpos="xy", color="k") 33 | 34 | ############################################################################### 35 | # In this manner, you can get the "best of both worlds" should you need 36 | # the flexibility of PyVista and the raw power of VTK. 37 | # 38 | # .. note:: 39 | # You can use :func:`pyvista.Polygon` for a one line replacement of 40 | # the above VTK code. 41 | 42 | ############################################################################### 43 | # VTK Algorithms 44 | # ~~~~~~~~~~~~~~ 45 | # 46 | # Perhaps there is a VTK algorithm that is not (yet) exposed in PyVista that you'd like to use. This is easy enough to work with since PyVista objects are VTK objects. We can pass our PyVista meshes to the VTK algorithm, then wrap the output for plotting, further filtering, or anything. 47 | 48 | mesh = examples.download_bunny_coarse() 49 | 50 | ############################################################################### 51 | # Initialize VTK algorithm 52 | splatter = vtk.vtkGaussianSplatter() 53 | 54 | ############################################################################### 55 | # Pass PyVista object as input to VTK 56 | splatter.SetInputData(mesh) 57 | 58 | ############################################################################### 59 | # Set parameters 60 | n = 200 61 | splatter.SetSampleDimensions(n, n, n) 62 | splatter.SetRadius(0.02) 63 | splatter.SetExponentFactor(-10) 64 | splatter.SetEccentricity(2) 65 | splatter.Update() 66 | 67 | ############################################################################### 68 | # Retrieve output and wrap with PyVista 69 | vol = pv.wrap(splatter.GetOutput()) 70 | 71 | ############################################################################### 72 | # Use PyVista to produce contours 73 | cntrs = vol.contour([0.95 * splatter.GetRadius()]) 74 | 75 | ############################################################################### 76 | # Use PyVista to plot 77 | p = pv.Plotter() 78 | p.add_mesh(mesh, style="wireframe") 79 | p.add_mesh(cntrs, color=True) 80 | p.show() 81 | 82 | ############################################################################### 83 | # .. note:: 84 | # 85 | # The above example was adapted from VTK's `Embed Points Into Volume `_ 86 | 87 | ############################################################################### 88 | # .. raw:: html 89 | # 90 | #
91 | # 92 | # Open In Colab 93 | # 94 | #
95 | -------------------------------------------------------------------------------- /tutorial/06_vtk/b_create_vtk.py: -------------------------------------------------------------------------------- 1 | """ 2 | Create VTK Objects 3 | ~~~~~~~~~~~~~~~~~~ 4 | 5 | This exercise walks through the creation of a few different types of VTK datasets. 6 | """ 7 | 8 | import numpy as np 9 | import pyvista as pv 10 | import vtk 11 | 12 | try: 13 | from vtkmodules.util.numpy_support import numpy_to_vtk 14 | except: # noqa: E722 15 | from vtk.util.numpy_support import numpy_to_vtk 16 | 17 | ############################################################################### 18 | # Create ``vtkImageData`` 19 | # ^^^^^^^^^^^^^^^^^^^^^^^ 20 | image = vtk.vtkImageData() 21 | image.SetDimensions(10, 10, 2) 22 | image.SetSpacing(1, 2, 5) 23 | image.SetOrigin(-0.5, -3, 0) 24 | 25 | ############################################################################### 26 | # Add point data 27 | values = np.arange(np.prod(image.GetDimensions())) 28 | # Convert numpy array to VTK array 29 | arr = numpy_to_vtk(values) 30 | arr.SetName("values") # CRITICAL 31 | image.GetPointData().SetScalars(arr) 32 | image 33 | 34 | ############################################################################### 35 | # Plot with PyVista for simplicity 36 | pv.plot(image, show_edges=True) 37 | 38 | ############################################################################### 39 | # Create ``vtkStructuredGrid`` 40 | # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 41 | 42 | # Define structured points with NumPy 43 | x = np.arange(-10, 10, 0.25) 44 | y = np.arange(-10, 10, 0.25) 45 | x, y = np.meshgrid(x, y) 46 | r = np.sqrt(x**2 + y**2) 47 | z = np.sin(r) 48 | 49 | # Join the points 50 | values = np.c_[x.ravel(), y.ravel(), z.ravel()] 51 | 52 | coords = numpy_to_vtk(values) 53 | 54 | points = vtk.vtkPoints() 55 | points.SetData(coords) 56 | 57 | grid = vtk.vtkStructuredGrid() 58 | grid.SetDimensions(*z.shape, 1) 59 | grid.SetPoints(points) 60 | grid 61 | 62 | ############################################################################### 63 | # Add point data 64 | arr = numpy_to_vtk(z.ravel()) 65 | arr.SetName("z") # CRITICAL 66 | grid.GetPointData().SetScalars(arr) 67 | 68 | 69 | ############################################################################### 70 | # Plot with PyVista for simplicity 71 | pv.plot(grid, show_edges=True) 72 | 73 | ############################################################################### 74 | # .. raw:: html 75 | # 76 | #
77 | # 78 | # Open In Colab 79 | # 80 | #
81 | -------------------------------------------------------------------------------- /tutorial/06_vtk/c_vtk_algorithms.py: -------------------------------------------------------------------------------- 1 | """ 2 | Using VTK Algorithms 3 | ~~~~~~~~~~~~~~~~~~~~ 4 | 5 | In this exercise, you will use a VTK Algorithm directly to filter a PyVista mesh. 6 | 7 | VTK algorithms (filters) follow a standard flow for most cases: 8 | 9 | 1. Instantiate the algorithm 10 | 2. Set the input data object or connection: ``.SetInputDataObject(mesh)`` 11 | 3. Adjust algorithm parameters with the setter methods, e.g., ``SetParameterName(value)`` 12 | 4. Call ``.Update()`` to run the algorithm 13 | 5. Retrieve the output of the algorithm: ``output = alg.GetOutput()`` 14 | 15 | Let's see if we can try a few VTK algorithms with that standard workflow. 16 | """ 17 | 18 | import pyvista as pv 19 | import vtk 20 | from pyvista import examples 21 | 22 | ############################################################################### 23 | # Here is a sample mesh 24 | mesh = examples.load_random_hills() 25 | mesh 26 | 27 | ############################################################################### 28 | mesh.plot() 29 | 30 | ############################################################################### 31 | # Simple Filter 32 | # ^^^^^^^^^^^^^ 33 | # Let's start out with a simple VTK filter: ``vtkOutlineFilter`` 34 | help(vtk.vtkOutlineFilter) 35 | 36 | ############################################################################### 37 | # Try using this VTK filter yourself here: 38 | # 39 | # Remember that you will have to wrap the output of the algorithm with :func:`pyvista.wrap` 40 | alg = vtk.vtkOutlineFilter() 41 | 42 | # (your code here, answer below) 43 | 44 | outline = pv.wrap(alg.GetOutput()) 45 | outline 46 | 47 | ############################################################################### 48 | alg.SetInputDataObject(mesh) 49 | alg.SetGenerateFaces(False) # noqa: FBT003 50 | alg.Update() 51 | 52 | outline = pv.wrap(alg.GetOutput()) 53 | outline 54 | 55 | ############################################################################### 56 | # .. note:: 57 | # 58 | # Note that the about filter can be replaced with a ``.outline()`` filter in PyVista 59 | 60 | ############################################################################### 61 | p = pv.Plotter() 62 | p.add_mesh(mesh) 63 | p.add_mesh(outline, color="k") 64 | p.show() 65 | 66 | 67 | ############################################################################### 68 | # Find your own filter 69 | # ^^^^^^^^^^^^^^^^^^^^ 70 | # 71 | # Take a look at VTK's examples and documentation to find a filter you'd like 72 | # to apply to your mesh. The instructors will be around to help you implement. 73 | # 74 | # See https://kitware.github.io/vtk-examples/site/Python/ 75 | 76 | ############################################################################### 77 | # .. raw:: html 78 | # 79 | #
80 | # 81 | # Open In Colab 82 | # 83 | #
84 | -------------------------------------------------------------------------------- /tutorial/07_sphinx/README.rst: -------------------------------------------------------------------------------- 1 | .. _sphinx: 2 | 3 | PyVista and Sphinx 4 | ================== 5 | 6 | Leverage PyVista to make some awesome web documentation. 7 | 8 | .. tip:: 9 | 10 | This section of the tutorial was adopted from `Plotting Themes 11 | `_ and `Sphinx PyVista 12 | Plot Directive `_ 13 | chapter of the PyVista documentation. 14 | 15 | Generating 3D Plots in your Documentation 16 | ----------------------------------------- 17 | PyVista allows you to generate images directly within Sphinx 18 | much like the `Matplotlib plot_directive 19 | `_. Rather 20 | than manually creating and adding plots after code sections, you can instead 21 | dynamically generate images and embed them directly within your 22 | documentation. This also works seamlessly with `sphinx-gallery 23 | `_, so you can create notebook examples just 24 | like the `Matplotlib Example Gallery 25 | `_. 26 | 27 | As an added side benefit, you can be sure that the documentation you generate 28 | matches your project API. If you include this within a `GitHub Workflow 29 | `_ 30 | 31 | This section covers the following topics. 32 | 33 | - :ref:`static_plots` 34 | 35 | .. _static_plots: 36 | 37 | Static Plotting - Sphinx PyVista Plot Directive 38 | ----------------------------------------------- 39 | You can generate static images of PyVista plots within sphinx using the 40 | ``pyvista-plot`` directive by adding the following to your ``conf.py`` 41 | when building your documentation using Sphinx. 42 | 43 | .. code:: python 44 | 45 | extensions = [ 46 | "sphinx.ext.napoleon", 47 | "pyvista.ext.plot_directive", 48 | ] 49 | 50 | You can then issue the plotting directive within your sphinx 51 | documentation files:: 52 | 53 | .. pyvista-plot:: 54 | :caption: A sphere 55 | :include-source: True 56 | 57 | >>> import pyvista 58 | >>> sphere = pyvista.Sphere() 59 | >>> out = sphere.plot() 60 | 61 | Which will be rendered as: 62 | 63 | .. pyvista-plot:: 64 | :caption: This is a default sphere 65 | :include-source: True 66 | 67 | >>> import pyvista 68 | >>> sphere = pyvista.Sphere() 69 | >>> out = sphere.plot() 70 | 71 | 72 | Examples and Usage 73 | ~~~~~~~~~~~~~~~~~~ 74 | There are two ways to use `trame `_ within 75 | Jupyter notebooks. You can use it on a plot by plot basis by setting the 76 | ``jupyter_backend`` in ``mesh.plot()``:: 77 | 78 | .. pyvista-plot:: 79 | 80 | import pyvista as pv 81 | from pyvista import examples 82 | 83 | # create a point cloud from lidar data and add height scalars 84 | dataset = examples.download_lidar() 85 | point_cloud = pv.PolyData(dataset.points[::100]) 86 | point_cloud['height'] = point_cloud.points[:, 2] 87 | point_cloud.plot(window_size=[500, 500], 88 | cmap='jet', 89 | point_size=2, 90 | background='w') 91 | 92 | And here's the resulting output in Sphinx: 93 | 94 | .. pyvista-plot:: 95 | 96 | import pyvista as pv 97 | from pyvista import examples 98 | 99 | # create a point cloud from lidar data and add height scalars 100 | dataset = examples.download_lidar() 101 | point_cloud = pv.PolyData(dataset.points[::100]) 102 | point_cloud['height'] = point_cloud.points[:, 2] 103 | point_cloud.plot(window_size=[500, 500], 104 | cmap='jet', 105 | point_size=2, 106 | background='w') 107 | 108 | | 109 | 110 | And now just directly execute ``plot`` on any dataset:: 111 | 112 | .. pyvista-plot:: 113 | 114 | from pyvista import examples 115 | dataset = examples.download_dragon() 116 | dataset.plot(cpos="xy") 117 | 118 | Which looks like: 119 | 120 | .. pyvista-plot:: 121 | 122 | from pyvista import examples 123 | dataset = examples.download_dragon() 124 | dataset.plot(cpos="xy") 125 | 126 | 127 | Exercises 128 | --------- 129 | 130 | Generate Sphinx documentation on your own using the 131 | `pyvista/pyvista-doc-example `_ 132 | repository. Either clone the repository with:: 133 | 134 | git clone https://github.com/pyvista/pyvista-doc-example 135 | 136 | Or just download the zip of the repository. 137 | 138 | .. button-link:: https://github.com/pyvista/pyvista-doc-example/archive/refs/heads/main.zip 139 | :color: primary 140 | :shadow: 141 | 142 | pyvista-doc-example-main.zip 143 | 144 | 145 | Build the documentation 146 | ~~~~~~~~~~~~~~~~~~~~~~~ 147 | 148 | Once you've downloaded `pyvista/pyvista-doc-example 149 | `_, cd into the directory and 150 | install the documentation build requirements with:: 151 | 152 | cd pyvista-doc-example 153 | pip install -r requirements_docs.txt 154 | 155 | Finally, build the documentation locally with:: 156 | 157 | cd doc 158 | make html 159 | 160 | Or, if on Windows:: 161 | 162 | cd doc 163 | make.bat 164 | 165 | You will then find the generated documentation within the ``doc/_build`` 166 | directory. Open up ``index.html`` using your browser to see the documentation. 167 | -------------------------------------------------------------------------------- /tutorial/08_widgets/README.rst: -------------------------------------------------------------------------------- 1 | .. _widgets: 2 | 3 | Widgets in PyVista 4 | ================== 5 | 6 | PyVista has several widgets that can be added to the rendering scene to control 7 | filters like clipping, slicing, and thresholding - specifically there are 8 | widgets to control the positions of boxes, planes, and lines or slider bars 9 | which can all be highly customized through the use of custom callback 10 | functions. 11 | 12 | Here we’ll take a look at the various widgets, some helper methods that 13 | leverage those widgets to do common tasks, and demonstrate how to leverage the 14 | widgets for user defined tasks and processing routines. 15 | 16 | .. tip:: 17 | 18 | This section of the tutorial was adopted from the `widgets section 19 | `_ 20 | of the PyVista example documentation. 21 | 22 | 23 | Widget Examples 24 | --------------- 25 | 26 | .. leave blank after this point for Sphinx-Gallery to populate examples 27 | -------------------------------------------------------------------------------- /tutorial/08_widgets/a_box-widget.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _box_widget_example: 3 | 4 | Box Widget 5 | ~~~~~~~~~~ 6 | 7 | The box widget can be enabled and disabled by the 8 | :func:`pyvista.Plotter.add_box_widget` and 9 | :func:`pyvista.Plotter.clear_box_widgets` methods respectively. 10 | When enabling the box widget, you must provide a custom callback function 11 | otherwise the box would appear and do nothing - the callback functions are 12 | what allow us to leverage the widget to perform a task like clipping/cropping. 13 | 14 | Considering that using a box to clip/crop a mesh is one of the most common use 15 | cases, we have included a helper method that will allow you to add a mesh to a 16 | scene with a box widget that controls its extent, the 17 | :func:`pyvista.Plotter.add_mesh_clip_box` method. 18 | 19 | .. image:: ../../images/gifs/box-clip.gif 20 | """ 21 | 22 | import pyvista as pv 23 | from pyvista import examples 24 | 25 | mesh = examples.download_nefertiti() 26 | 27 | ############################################################################### 28 | 29 | p = pv.Plotter() 30 | p.add_mesh_clip_box(mesh, color="white") 31 | p.show(cpos=[-1, -1, 0.2]) 32 | 33 | 34 | ############################################################################### 35 | # After interacting with the scene, the clipped mesh is available as: 36 | p.box_clipped_meshes 37 | 38 | ############################################################################### 39 | # .. raw:: html 40 | # 41 | #
42 | # 43 | # Open In Colab 44 | # 45 | #
46 | -------------------------------------------------------------------------------- /tutorial/08_widgets/b_checkbox-widget.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _checkbox_widget_example: 3 | 4 | Checkbox Widget 5 | ~~~~~~~~~~~~~~~ 6 | 7 | Use a checkbox to turn on/off the visibility of meshes in a scene. 8 | 9 | See :func:`pyvista.Plotter.add_checkbox_button_widget` for more details. 10 | 11 | """ 12 | 13 | # sphinx_gallery_thumbnail_number = 2 14 | import pyvista as pv 15 | 16 | ############################################################################### 17 | # Single Checkbox 18 | # +++++++++++++++ 19 | 20 | mesh = pv.Sphere() 21 | 22 | p = pv.Plotter() 23 | actor = p.add_mesh(mesh) 24 | 25 | 26 | def toggle_vis(flag) -> None: 27 | actor.SetVisibility(flag) 28 | 29 | 30 | p.add_checkbox_button_widget(toggle_vis, value=True) 31 | p.show() 32 | 33 | ############################################################################## 34 | # And here is a screen capture of a user interacting with this 35 | # 36 | # .. image:: ../../images/gifs/single-checkbox-widget.gif 37 | 38 | ############################################################################### 39 | # Multiple Checkboxes 40 | # +++++++++++++++++++ 41 | # 42 | # In this example, we will add many meshes to a scene with unique colors and 43 | # create corresponding checkboxes for those meshes of the same color to toggle 44 | # their visibility in the scene. 45 | 46 | colors = [ 47 | ["ff0000", "28e5da", "0000ff"], 48 | ["ffff00", "c8bebe", "f79292"], 49 | ["fffff0", "f18c1d", "23dcaa"], 50 | ["d785ec", "9d5b13", "e4e0b1"], 51 | ["894509", "af45f5", "fff000"], 52 | ] 53 | 54 | 55 | class SetVisibilityCallback: 56 | """Helper callback to keep a reference to the actor being modified.""" 57 | 58 | def __init__(self, actor) -> None: 59 | self.actor = actor 60 | 61 | def __call__(self, state): 62 | self.actor.SetVisibility(state) 63 | 64 | 65 | ############################################################################### 66 | 67 | # Widget size 68 | size = 50 69 | 70 | p = pv.Plotter() 71 | 72 | Startpos = 12 73 | for i, lst in enumerate(colors): 74 | for j, color in enumerate(lst): 75 | actor = p.add_mesh(pv.Sphere(center=(i, j, 0)), color=color) 76 | # Make a separate callback for each widget 77 | callback = SetVisibilityCallback(actor) 78 | p.add_checkbox_button_widget( 79 | callback, 80 | value=True, 81 | position=(5.0, Startpos), 82 | size=size, 83 | border_size=1, 84 | color_on=color, 85 | color_off="grey", 86 | background_color="grey", 87 | ) 88 | Startpos = Startpos + size + (size // 10) 89 | 90 | p.show() 91 | 92 | ############################################################################## 93 | # And here is a screen capture of a user interacting with this 94 | # 95 | # .. image:: ../../images/gifs/multiple-checkbox-widget.gif 96 | 97 | ############################################################################### 98 | # .. raw:: html 99 | # 100 | #
101 | # 102 | # Open In Colab 103 | # 104 | #
105 | -------------------------------------------------------------------------------- /tutorial/08_widgets/c_line-widget.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _line_widget_example: 3 | 4 | Line Widget 5 | ~~~~~~~~~~~ 6 | 7 | The line widget can be enabled and disabled by the 8 | :func:`pyvista.Plotter.add_line_widget` and 9 | :func:`pyvista.Plotter.clear_line_widgets` methods respectively. 10 | Unfortunately, PyVista does not have any helper methods to utilize this 11 | widget, so it is necessary to pass a custom callback method. 12 | 13 | One particularly fun example is to use the line widget to create a source for 14 | the :func:`pyvista.DataSetFilters.streamlines` filter. Again note the use of 15 | the ``name`` argument in ``add_mesh``. 16 | """ 17 | 18 | import numpy as np 19 | import pyvista as pv 20 | from pyvista import examples 21 | 22 | pv.set_plot_theme("document") 23 | 24 | mesh = examples.download_kitchen() 25 | furniture = examples.download_kitchen(split=True) 26 | 27 | arr = np.linalg.norm(mesh["velocity"], axis=1) 28 | clim = [arr.min(), arr.max()] 29 | 30 | ############################################################################### 31 | 32 | p = pv.Plotter() 33 | p.add_mesh(furniture, name="furniture", color=True) 34 | p.add_mesh(mesh.outline(), color="black") 35 | p.add_axes() 36 | 37 | 38 | def simulate(pointa, pointb) -> None: 39 | streamlines = mesh.streamlines( 40 | n_points=10, max_steps=100, pointa=pointa, pointb=pointb, integration_direction="forward" 41 | ) 42 | p.add_mesh(streamlines, name="streamlines", line_width=5, render_lines_as_tubes=True, clim=clim) 43 | 44 | 45 | p.add_line_widget(callback=simulate, use_vertices=True) 46 | p.show() 47 | 48 | ############################################################################## 49 | # And here is a screen capture of a user interacting with this 50 | # 51 | # .. image:: ../../images/gifs/line-widget-streamlines.gif 52 | 53 | ############################################################################### 54 | # .. raw:: html 55 | # 56 | #
57 | # 58 | # Open In Colab 59 | # 60 | #
61 | -------------------------------------------------------------------------------- /tutorial/08_widgets/d_multi-slider-widget.py: -------------------------------------------------------------------------------- 1 | """ 2 | Multiple Slider Widgets 3 | ~~~~~~~~~~~~~~~~~~~~~~~ 4 | 5 | Use a class based callback to track multiple slider widgets for updating a 6 | single mesh. 7 | 8 | In this example we simply change a few parameters for the 9 | :func:`pyvista.Sphere` method, but this could easily be applied to any 10 | mesh-generating/altering code. 11 | 12 | """ 13 | 14 | import pyvista as pv 15 | 16 | 17 | class MyCustomRoutine: 18 | def __init__(self, mesh) -> None: 19 | self.output = mesh # Expected PyVista mesh type 20 | # default parameters 21 | self.kwargs = { 22 | "radius": 0.5, 23 | "theta_resolution": 30, 24 | "phi_resolution": 30, 25 | } 26 | 27 | def __call__(self, param, value): 28 | self.kwargs[param] = value 29 | self.update() 30 | 31 | def update(self) -> None: 32 | # This is where you call your simulation 33 | result = pv.Sphere(**self.kwargs) 34 | self.output.copy_from(result) 35 | 36 | 37 | ############################################################################### 38 | 39 | starting_mesh = pv.Sphere() 40 | engine = MyCustomRoutine(starting_mesh) 41 | 42 | ############################################################################### 43 | 44 | p = pv.Plotter() 45 | p.add_mesh(starting_mesh, show_edges=True) 46 | p.add_slider_widget( 47 | callback=lambda value: engine("phi_resolution", int(value)), 48 | rng=[3, 60], 49 | value=30, 50 | title="Phi Resolution", 51 | pointa=(0.025, 0.1), 52 | pointb=(0.31, 0.1), 53 | style="modern", 54 | ) 55 | p.add_slider_widget( 56 | callback=lambda value: engine("theta_resolution", int(value)), 57 | rng=[3, 60], 58 | value=30, 59 | title="Theta Resolution", 60 | pointa=(0.35, 0.1), 61 | pointb=(0.64, 0.1), 62 | style="modern", 63 | ) 64 | p.add_slider_widget( 65 | callback=lambda value: engine("radius", value), 66 | rng=[0.1, 1.5], 67 | value=0.5, 68 | title="Radius", 69 | pointa=(0.67, 0.1), 70 | pointb=(0.98, 0.1), 71 | style="modern", 72 | ) 73 | p.show() 74 | 75 | ############################################################################## 76 | # And here is a screen capture of a user interacting with this 77 | # 78 | # .. image:: ../../images/gifs/multiple-slider-widget.gif 79 | 80 | ############################################################################### 81 | # .. raw:: html 82 | # 83 | #
84 | # 85 | # Open In Colab 86 | # 87 | #
88 | -------------------------------------------------------------------------------- /tutorial/08_widgets/e_plane-widget.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _plane_widget_example: 3 | 4 | Plane Widget 5 | ~~~~~~~~~~~~ 6 | 7 | The plane widget can be enabled and disabled by the 8 | :func:`pyvista.Plotter.add_plane_widget` and 9 | :func:`pyvista.Plotter.clear_plane_widgets` methods respectively. 10 | As with all widgets, you must provide a custom callback method to utilize that 11 | plane. Considering that planes are most commonly used for clipping and slicing 12 | meshes, we have included two helper methods for doing those tasks! 13 | 14 | Let's use a plane to clip a mesh: 15 | """ 16 | 17 | # sphinx_gallery_thumbnail_number = 2 18 | import pyvista as pv 19 | from pyvista import examples 20 | 21 | vol = examples.download_brain() 22 | 23 | p = pv.Plotter() 24 | p.add_mesh_clip_plane(vol) 25 | p.show() 26 | 27 | ############################################################################### 28 | # After interacting with the scene, the clipped mesh is available as: 29 | p.plane_clipped_meshes 30 | 31 | ############################################################################### 32 | # And here is a screen capture of a user interacting with this 33 | # 34 | # .. image:: ../../images/gifs/plane-clip.gif 35 | 36 | ############################################################################### 37 | # Or you could slice a mesh using the plane widget: 38 | 39 | p = pv.Plotter() 40 | p.add_mesh_slice(vol) 41 | p.show() 42 | ############################################################################### 43 | # After interacting with the scene, the slice is available as: 44 | p.plane_sliced_meshes 45 | 46 | ############################################################################### 47 | # And here is a screen capture of a user interacting with this 48 | # 49 | # .. image:: ../../images/gifs/plane-slice.gif 50 | 51 | ############################################################################### 52 | # Or you could leverage the plane widget for some custom task like glyphing a 53 | # vector field along that plane. Note that we have to pass a ``name`` when 54 | # calling ``add_mesh`` to ensure that there is only one set of glyphs plotted 55 | # at a time. 56 | 57 | import pyvista as pv 58 | from pyvista import examples 59 | 60 | mesh = examples.download_carotid() 61 | 62 | p = pv.Plotter() 63 | p.add_mesh(mesh.contour(8).extract_largest(), opacity=0.5) 64 | 65 | 66 | def my_plane_func(normal, origin) -> None: 67 | slc = mesh.slice(normal=normal, origin=origin) 68 | arrows = slc.glyph(orient="vectors", scale="scalars", factor=0.01) 69 | p.add_mesh(arrows, name="arrows") 70 | 71 | 72 | p.add_plane_widget(my_plane_func) 73 | p.show_grid() 74 | p.add_axes() 75 | p.show() 76 | 77 | ############################################################################### 78 | # And here is a screen capture of a user interacting with this 79 | # 80 | # .. image:: ../../images/gifs/plane-glyph.gif 81 | 82 | 83 | ############################################################################### 84 | # Further, a user can disable the arrow vector by setting the 85 | # ``normal_rotation`` argument to ``False``. For example, here we 86 | # programmatically set the normal vector on which we want to translate the 87 | # plane and we disable the arrow to prevent its rotation. 88 | 89 | p = pv.Plotter() 90 | p.add_mesh_slice(vol, normal=(1, 1, 1), normal_rotation=False) 91 | p.show() 92 | 93 | ############################################################################### 94 | # The vector is also forcibly disabled anytime the ``assign_to_axis`` argument 95 | # is set. 96 | p = pv.Plotter() 97 | p.add_mesh_slice(vol, assign_to_axis="z") 98 | p.show() 99 | 100 | 101 | ############################################################################### 102 | # Additionally, users can modify the interaction event that triggers the 103 | # callback functions handled by the different plane widget helpers through the 104 | # ``interaction_event`` keyword argument when available. For example, 105 | # we can have continuous slicing by using the ``InteractionEvent`` observer. 106 | import vtk 107 | 108 | p = pv.Plotter() 109 | p.add_mesh_slice(vol, assign_to_axis="z", interaction_event=vtk.vtkCommand.InteractionEvent) 110 | p.show() 111 | 112 | ############################################################################### 113 | # And here is a screen capture of a user interacting with this continuously via 114 | # the ``InteractionEvent`` observer: 115 | # 116 | # .. image:: ../../images/gifs/plane-slice-continuous.gif 117 | 118 | ############################################################################### 119 | # .. raw:: html 120 | # 121 | #
122 | # 123 | # Open In Colab 124 | # 125 | #
126 | -------------------------------------------------------------------------------- /tutorial/08_widgets/f_slider-bar-widget.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. _slider_bar_widget_example: 3 | 4 | Slider Bar Widget 5 | ~~~~~~~~~~~~~~~~~ 6 | 7 | The slider widget can be enabled and disabled by the 8 | :func:`pyvista.Plotter.add_slider_widget` and 9 | :func:`pyvista.Plotter.clear_slider_widgets` methods respectively. 10 | This is one of the most versatile widgets as it can control a value that can 11 | be used for just about anything. 12 | """ 13 | 14 | # sphinx_gallery_thumbnail_number = 1 15 | 16 | ############################################################################## 17 | # One helper method we've added is the 18 | # :func:`pyvista.Plotter.add_mesh_threshold` method which leverages the 19 | # slider widget to control a thresholding value. 20 | 21 | import pyvista as pv 22 | from pyvista import examples 23 | 24 | mesh = examples.download_knee_full() 25 | 26 | p = pv.Plotter() 27 | p.add_mesh_threshold(mesh) 28 | p.show() 29 | 30 | ############################################################################### 31 | # After interacting with the scene, the threshold mesh is available as: 32 | p.threshold_meshes 33 | 34 | ############################################################################## 35 | # And here is a screen capture of a user interacting with this 36 | # 37 | # .. image:: ../../images/gifs/slider-widget-threshold.gif 38 | 39 | ############################################################################### 40 | # Custom Callback 41 | # +++++++++++++++ 42 | # 43 | # Or you could leverage a custom callback function that takes a single value 44 | # from the slider as its argument to do something like control the resolution 45 | # of a mesh. Again note the use of the ``name`` argument in ``add_mesh``: 46 | 47 | p = pv.Plotter() 48 | 49 | 50 | def create_mesh(value) -> None: 51 | res = int(value) 52 | sphere = pv.Sphere(phi_resolution=res, theta_resolution=res) 53 | p.add_mesh(sphere, name="sphere", show_edges=True) 54 | 55 | 56 | p.add_slider_widget(create_mesh, [5, 100], title="Resolution") 57 | p.show() 58 | 59 | ############################################################################## 60 | # And here is a screen capture of a user interacting with this 61 | # 62 | # .. image:: ../../images/gifs/slider-widget-resolution.gif 63 | 64 | ############################################################################### 65 | # .. raw:: html 66 | # 67 | #
68 | # 69 | # Open In Colab 70 | # 71 | #
72 | -------------------------------------------------------------------------------- /tutorial/08_widgets/g_sphere-widget.py: -------------------------------------------------------------------------------- 1 | """ 2 | Sphere Widget 3 | ~~~~~~~~~~~~~ 4 | 5 | The sphere widget can be enabled and disabled by the 6 | :func:`pyvista.Plotter.add_sphere_widget` and 7 | :func:`pyvista.Plotter.clear_sphere_widgets` methods respectively. 8 | This is a very versatile widget as it can control vertex location that can 9 | be used to control or update the location of just about anything. 10 | 11 | We don't have any convenient helper methods that utilize this widget out of 12 | the box, but we have added a lot of ways to use this widget so that you can 13 | easily add several widgets to a scene. 14 | 15 | Let's look at a few use cases that all update a surface mesh. 16 | """ 17 | 18 | # sphinx_gallery_thumbnail_number = 3 19 | 20 | ############################################################################## 21 | # Example A 22 | # +++++++++ 23 | # 24 | # Use a single sphere widget 25 | 26 | import numpy as np 27 | import pyvista as pv 28 | 29 | # Create a triangle surface 30 | surf = pv.PolyData() 31 | surf.points = np.array( 32 | [ 33 | [-10, -10, -10], 34 | [10, 10, -10], 35 | [-10, 10, 0], 36 | ] 37 | ) 38 | surf.faces = np.array([3, 0, 1, 2]) 39 | 40 | p = pv.Plotter() 41 | 42 | 43 | def callback(point) -> None: 44 | surf.points[0] = point 45 | 46 | 47 | p.add_sphere_widget(callback) 48 | p.add_mesh(surf, color=True) 49 | 50 | p.show_grid() 51 | p.show() 52 | 53 | ############################################################################## 54 | # And here is a screen capture of a user interacting with this 55 | # 56 | # .. image:: ../../images/gifs/sphere-widget-a.gif 57 | 58 | 59 | ############################################################################### 60 | # Example B 61 | # +++++++++ 62 | # 63 | # Use several sphere widgets at once 64 | 65 | import numpy as np 66 | import pyvista as pv 67 | 68 | # Create a triangle surface 69 | surf = pv.PolyData() 70 | surf.points = np.array( 71 | [ 72 | [-10, -10, -10], 73 | [10, 10, -10], 74 | [-10, 10, 0], 75 | ] 76 | ) 77 | surf.faces = np.array([3, 0, 1, 2]) 78 | 79 | 80 | p = pv.Plotter() 81 | 82 | 83 | def callback(point, i) -> None: 84 | surf.points[i] = point 85 | 86 | 87 | p.add_sphere_widget(callback, center=surf.points) 88 | p.add_mesh(surf, color=True) 89 | 90 | p.show_grid() 91 | p.show() 92 | 93 | ############################################################################## 94 | # And here is a screen capture of a user interacting with this 95 | # 96 | # .. image:: ../../images/gifs/sphere-widget-b.gif 97 | 98 | ############################################################################### 99 | # Example C 100 | # +++++++++ 101 | # 102 | # This one is the coolest - use four sphere widgets to update perturbations on 103 | # a surface and interpolate between them with some boundary conditions 104 | 105 | import numpy as np 106 | import pyvista as pv 107 | from scipy.interpolate import griddata 108 | 109 | 110 | def get_colors(n): 111 | """A helper function to get n colors.""" 112 | from itertools import cycle 113 | 114 | import matplotlib as mpl 115 | 116 | cycler = mpl.rcParams["axes.prop_cycle"] 117 | colors = cycle(cycler) 118 | return [next(colors)["color"] for i in range(n)] 119 | 120 | 121 | # Create a grid to interpolate to 122 | xmin, xmax, ymin, ymax = 0, 100, 0, 100 123 | x = np.linspace(xmin, xmax, num=25) 124 | y = np.linspace(ymin, ymax, num=25) 125 | xx, yy, zz = np.meshgrid(x, y, [0]) 126 | 127 | # Make sure boundary conditions exist 128 | boundaries = np.array([[xmin, ymin, 0], [xmin, ymax, 0], [xmax, ymin, 0], [xmax, ymax, 0]]) 129 | 130 | # Create the PyVista mesh to hold this grid 131 | surf = pv.StructuredGrid(xx, yy, zz) 132 | 133 | # Create some initial perturbations 134 | # - this array will be updated inplace 135 | points = np.array([[33, 25, 45], [70, 80, 13], [51, 57, 10], [25, 69, 20]]) 136 | 137 | 138 | # Create an interpolation function to update that surface mesh 139 | def update_surface(point, i) -> None: 140 | points[i] = point 141 | tp = np.vstack((points, boundaries)) 142 | zz = griddata(tp[:, 0:2], tp[:, 2], (xx[:, :, 0], yy[:, :, 0]), method="cubic") 143 | surf.points[:, -1] = zz.ravel(order="F") 144 | 145 | 146 | # Get a list of unique colors for each widget 147 | colors = get_colors(len(points)) 148 | 149 | ############################################################################## 150 | 151 | # Begin the plotting routine 152 | p = pv.Plotter() 153 | 154 | # Add the surface to the scene 155 | p.add_mesh(surf, color=True) 156 | 157 | # Add the widgets which will update the surface 158 | p.add_sphere_widget(update_surface, center=points, color=colors, radius=3) 159 | # Add axes grid 160 | p.show_grid() 161 | 162 | # Show it! 163 | p.show() 164 | 165 | ############################################################################## 166 | # And here is a screen capture of a user interacting with this 167 | # 168 | # .. image:: ../../images/gifs/sphere-widget-c.gif 169 | 170 | ############################################################################### 171 | # .. raw:: html 172 | # 173 | #
174 | # 175 | # Open In Colab 176 | # 177 | #
178 | -------------------------------------------------------------------------------- /tutorial/08_widgets/h_spline-widget.py: -------------------------------------------------------------------------------- 1 | """ 2 | Spline Widget 3 | ~~~~~~~~~~~~~ 4 | 5 | 6 | A spline widget can be enabled and disabled by the 7 | :func:`pyvista.Plotter.add_spline_widget` and 8 | :func:`pyvista.Plotter.clear_spline_widgets` methods respectively. 9 | This widget allows users to interactively create a poly line (spline) through 10 | a scene and use that spline. 11 | 12 | A common task with splines is to slice a volumetric dataset using an irregular 13 | path. To do this, we have added a convenient helper method which leverages the 14 | :func:`pyvista.DataSetFilters.slice_along_line` filter named 15 | :func:`pyvista.Plotter.add_mesh_slice_spline`. 16 | """ 17 | 18 | import numpy as np 19 | import pyvista as pv 20 | 21 | ############################################################################## 22 | 23 | mesh = pv.Wavelet() 24 | 25 | # initial spline to seed the example 26 | points = np.array( 27 | [ 28 | [-8.64208925, -7.34294559, -9.13803458], 29 | [-8.25601497, -2.54814702, 0.93860914], 30 | [-0.30179377, -3.21555997, -4.19999019], 31 | [3.24099167, 2.05814768, 3.39041509], 32 | [4.39935227, 4.18804542, 8.96391132], 33 | ] 34 | ) 35 | 36 | p = pv.Plotter() 37 | p.add_mesh(mesh.outline(), color="black") 38 | p.add_mesh_slice_spline(mesh, initial_points=points, n_handles=5) 39 | p.camera_position = [(30, -42, 30), (0.0, 0.0, 0.0), (-0.09, 0.53, 0.84)] 40 | p.show() 41 | 42 | ############################################################################## 43 | # And here is a screen capture of a user interacting with this 44 | # 45 | # .. image:: ../../images/gifs/spline-widget.gif 46 | 47 | ############################################################################### 48 | # .. raw:: html 49 | # 50 | #
51 | # 52 | # Open In Colab 53 | # 54 | #
55 | -------------------------------------------------------------------------------- /tutorial/09_trame/README.rst: -------------------------------------------------------------------------------- 1 | .. _trame: 2 | 3 | Trame 4 | ===== 5 | 6 | `Kitware's Trame `_ is an open-source platform for creating interactive and powerful visual analytics applications. Based on Python, and leveraging platforms such as VTK, ParaView, and Vega, it is possible to create web-based applications in minutes. 7 | 8 | .. raw:: html 9 | 10 | 11 | 12 | 13 | What is Trame? 14 | -------------- 15 | 16 | Trame is a Python framework for building reactive web applications. 17 | 18 | * All the logic and UI definition can be done in plain Python 19 | * Runs on laptops, desktops, clusters, and the cloud while displaying everywhere (phone, tablet, laptop, workstation) 20 | 21 | 22 | .. tab-set:: 23 | 24 | .. tab-item:: Documentation 25 | 26 | Learn more about Trame 27 | 28 | .. button-link:: https://kitware.github.io/trame/ 29 | :color: primary 30 | :shadow: 31 | 32 | Trame Documentation 33 | 34 | 35 | .. tab-item:: Tutorial 36 | 37 | Gain hands on experience with Trame through the tutorial. 38 | 39 | 40 | .. button-link:: https://github.com/Kitware/trame-tutorial 41 | :color: primary 42 | :shadow: 43 | 44 | Trame Tutorial 45 | 46 | 47 | 3D visualization in web applications 48 | ------------------------------------ 49 | 50 | PyVista and Trame work excellently together to provide a cutting-edge capabilities for 3D 51 | visualization in reactive web applications. 52 | 53 | 1. Trame provides a high-level framework for building reactive, stateful web applications 54 | 2. PyVista provides a high-level framework for 3D visualization, exposing VTK in a “Pythonic” manner 55 | 56 | High-level framework 1 + high-level framework 2 = a streamlined approach to making powerful web applications with 3D visualization front and center. 57 | 58 | The following code creates a simple Trame application with a PyVista plotter embedded in the UI. 59 | This code can be used as a base for building all of your Trame applications with PyVista as it 60 | contains all of the boilerplate code needed to get started. 61 | 62 | 63 | .. tab-set:: 64 | 65 | .. tab-item:: Code 66 | 67 | .. code:: python 68 | 69 | import pyvista as pv 70 | from pyvista import examples 71 | from pyvista.trame.ui import plotter_ui 72 | from trame.app import get_server 73 | from trame.ui.vuetify3 import SinglePageLayout 74 | 75 | # Always set PyVista to plot off screen with Trame 76 | pv.OFF_SCREEN = True 77 | 78 | server = get_server() 79 | state, ctrl = server.state, server.controller 80 | 81 | mesh = examples.load_random_hills() 82 | 83 | pl = pv.Plotter() 84 | pl.add_mesh(mesh) 85 | 86 | with SinglePageLayout(server) as layout: 87 | with layout.content: 88 | # Use PyVista's Trame UI helper method 89 | # this will add UI controls 90 | view = plotter_ui(pl) 91 | 92 | server.start() 93 | 94 | .. tab-item:: Web App 95 | 96 | .. image:: ../../images/trame-pyvista.png 97 | :alt: A simple Trame application with PyVista 98 | :align: center 99 | 100 | 101 | .. note:: 102 | 103 | PyVista's Jupyter backend is powered by Trame! If you've been using 104 | PyVista in Jupyter lately, you've been using Trame all along -- our 105 | Jupyter backend is a micro Trame application. 106 | 107 | 108 | Trame applications 109 | ~~~~~~~~~~~~~~~~~~ 110 | 111 | Using an existing app 112 | 113 | .. code:: python 114 | 115 | from trame.app.demo import Cone 116 | 117 | app = Cone("demo") 118 | await app.ui.ready 119 | app.ui 120 | 121 | 122 | Try Pan3D: ``pip install pan3d`` 123 | 124 | .. code:: python 125 | 126 | from pan3d import DatasetBuilder 127 | 128 | builder = DatasetBuilder(viewer=True) 129 | 130 | builder.import_config('example_sst_xarray.json') 131 | 132 | # Show viewer in cell output 133 | await builder.viewer.ready 134 | builder.viewer.ui 135 | 136 | 137 | Exercises 138 | ~~~~~~~~~ 139 | 140 | Do not run these examples in Jupyter but rather as standalone scripts. 141 | -------------------------------------------------------------------------------- /tutorial/09_trame/a_getting_started.py: -------------------------------------------------------------------------------- 1 | # Getting started with PyVista and Trame 2 | """ 3 | Getting started 4 | ~~~~~~~~~~~~~~~ 5 | 6 | Getting started with PyVista and Trame 7 | 8 | """ 9 | 10 | import pyvista as pv 11 | from pyvista import examples 12 | 13 | ############################################################################### 14 | # PyVista's Jupyter backend is powered by **Trame**. So by default you are 15 | # using trame without knowing it. 16 | # 17 | # By default PyVista is serving you a micro trame application that let you 18 | # toggle between **Remote** and **Local** rendering along with some various 19 | # options to configure your visualization. 20 | # 21 | # **First try the Remote/Local rendering toggle and notice the differences** 22 | # 23 | # .. raw:: html 24 | # 25 | #
26 | # Look at the orientation axis between the 2 rendering modes. 27 | #
28 | # 29 | # One sends images generated on the server side while the other is sending geometry to vtk.js. 30 | dataset = examples.download_lucy() 31 | dataset.plot(smooth_shading=True, color="white") 32 | 33 | ############################################################################### 34 | # Building applications with PyVista and Trame 35 | # 36 | # Now, let's build a simple application that updates the mesh color with the click of a button. 37 | 38 | import random 39 | 40 | from pyvista.plotting.colors import hexcolors 41 | from pyvista.trame.ui import get_viewer 42 | from trame.ui.vuetify3 import SinglePageLayout 43 | from trame.widgets import vuetify3 as v3 44 | 45 | plotter = pv.Plotter() 46 | actor = plotter.add_mesh(dataset) 47 | viewer = get_viewer(plotter) 48 | view = None 49 | 50 | 51 | def change_color() -> None: 52 | actor.prop.color = random.choice(list(hexcolors.keys())) # noqa: S311 53 | view.update() 54 | 55 | 56 | # Create UI 57 | with SinglePageLayout(viewer.server) as layout: 58 | with layout.toolbar.clear() as tb: 59 | tb.density = "compact" 60 | tb.theme = "dark" 61 | viewer.ui_controls(mode="trame") 62 | v3.VBtn(icon="mdi-palette", click=change_color) 63 | with layout.content: 64 | view = viewer.ui(add_menu=False, mode="trame") 65 | 66 | 67 | # Show UI 68 | await layout.ready 69 | layout 70 | -------------------------------------------------------------------------------- /tutorial/09_trame/a_trame_simple.py: -------------------------------------------------------------------------------- 1 | """ 2 | Simple Trame App 3 | ~~~~~~~~~~~~~~~~ 4 | 5 | A simple example of how to create a Trame app with a PyVista Plotter. 6 | 7 | This example contains the boilerplate code to use anytime you are creating a 8 | new Trame application with PyVista. 9 | 10 | """ 11 | 12 | import pyvista as pv 13 | from pyvista import examples 14 | from pyvista.trame.ui import plotter_ui 15 | from trame.app import get_server 16 | from trame.ui.vuetify3 import SinglePageLayout 17 | 18 | pv.OFF_SCREEN = True 19 | 20 | server = get_server() 21 | state, ctrl = server.state, server.controller 22 | 23 | mesh = examples.load_random_hills() 24 | 25 | pl = pv.Plotter() 26 | pl.add_mesh(mesh) 27 | 28 | with SinglePageLayout(server) as layout, layout.content: 29 | view = plotter_ui(pl) 30 | 31 | # Show UI 32 | await layout.ready 33 | layout 34 | ############################################################################### 35 | # .. raw:: html 36 | # 37 | #
38 | # 39 | # Open In Colab 40 | # 41 | #
42 | -------------------------------------------------------------------------------- /tutorial/09_trame/b_trame_actor_color.py: -------------------------------------------------------------------------------- 1 | """ 2 | Control the Color of an Actor 3 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | 5 | Extending our simple example to have a dropdown menu to control the color of 6 | the actor. 7 | 8 | """ 9 | 10 | import pyvista as pv 11 | from pyvista.plotting.colors import hexcolors 12 | from pyvista.trame.ui import plotter_ui 13 | from trame.app import get_server 14 | from trame.ui.vuetify3 import SinglePageLayout 15 | from trame.widgets import vuetify3 16 | 17 | pv.OFF_SCREEN = True 18 | 19 | server = get_server() 20 | state, ctrl = server.state, server.controller 21 | 22 | mesh = pv.Cone() 23 | 24 | pl = pv.Plotter() 25 | actor = pl.add_mesh(mesh, color="seagreen") 26 | 27 | 28 | @state.change("color") 29 | def color(color="seagreen", **kwargs) -> None: 30 | actor.prop.color = color 31 | ctrl.view_update() 32 | 33 | 34 | with SinglePageLayout(server) as layout: 35 | with layout.toolbar: 36 | vuetify3.VSpacer() 37 | vuetify3.VSelect( 38 | label="Color", 39 | v_model=("color", "seagreen"), 40 | items=("array_list", list(hexcolors.keys())), 41 | hide_details=True, 42 | density="compact", 43 | outlined=True, 44 | classes="pt-1 ml-2", 45 | style="max-width: 250px", 46 | ) 47 | 48 | with ( 49 | layout.content, 50 | vuetify3.VContainer( 51 | fluid=True, 52 | classes="pa-0 fill-height", 53 | ), 54 | ): 55 | # Use PyVista UI template for Plotters 56 | view = plotter_ui(pl, default_server_rendering=False) 57 | ctrl.view_update = view.update 58 | 59 | # Show UI 60 | await layout.ready 61 | layout 62 | ############################################################################### 63 | # .. raw:: html 64 | # 65 | #
66 | # 67 | # Open In Colab 68 | # 69 | #
70 | -------------------------------------------------------------------------------- /tutorial/09_trame/b_trame_vtk.py: -------------------------------------------------------------------------------- 1 | """ 2 | Using VTK/PyVista and Trame 3 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | 5 | In this application, we will connect a VTK filter with PyVista. 6 | 7 | It will use Trame to visualize the results and interactively control 8 | parameters of the VTK filter. 9 | 10 | """ 11 | 12 | import pyvista as pv 13 | from pyvista import examples 14 | from trame.app import get_server 15 | from trame.ui.vuetify3 import VAppLayout 16 | from trame.widgets import vtk as vtk_widgets 17 | from trame.widgets import vuetify3 as v3 18 | from vtkmodules.vtkFiltersGeneral import vtkWarpScalar 19 | 20 | mesh = examples.load_random_hills() 21 | warp_by_scalar = vtkWarpScalar() 22 | warp_by_scalar.SetInputData(mesh) 23 | warp_by_scalar.SetScaleFactor(0.3) 24 | 25 | plotter = pv.Plotter() 26 | actor = plotter.add_mesh(warp_by_scalar) 27 | plotter.reset_camera() 28 | 29 | # Trame server setup 30 | server = get_server("trame_vtk_example") 31 | state, ctrl = server.state, server.controller 32 | 33 | 34 | @state.change("scale") 35 | def update_scale(scale, **kwargs) -> None: 36 | warp_by_scalar.SetScaleFactor(scale) 37 | ctrl.view_update() 38 | 39 | 40 | with VAppLayout(server, full_height=True) as layout: # noqa: SIM117 41 | with v3.VContainer(fluid=True, classes="fill-height"): 42 | with vtk_widgets.VtkRemoteView(plotter.render_window, interactive_ratio=1) as view: 43 | ctrl.view_update = view.update 44 | ctrl.view_reset_camera = view.reset_camera 45 | 46 | # Event binding 47 | v3.VBtn( 48 | icon="mdi-crop-free", 49 | click=ctrl.view_reset_camera, 50 | classes="position-absolute", 51 | style="left: 1rem; top: 1rem; z-index: 1", 52 | density="compact", 53 | ) 54 | 55 | # State binding 56 | v3.VSlider( 57 | v_model=("scale", 0.3), 58 | min=0, 59 | max=0.5, 60 | step=0.01, 61 | density="compact", 62 | classes="position-absolute", 63 | style="right: 1rem; top: 1rem; width: 400px; z-index: 1", 64 | ) 65 | 66 | # Make sure the app is running and ready 67 | await layout.ready 68 | # Show UI in result 69 | layout 70 | -------------------------------------------------------------------------------- /tutorial/09_trame/c_trame_scalars.py: -------------------------------------------------------------------------------- 1 | """ 2 | Control Scalar Array 3 | ~~~~~~~~~~~~~~~~~~~~ 4 | 5 | Extending our simple example to have a dropdown menu to control which 6 | scalar array is used to color the mesh. 7 | """ 8 | 9 | import pyvista as pv 10 | from pyvista import examples 11 | from pyvista.trame.ui import plotter_ui 12 | from trame.app import get_server 13 | from trame.ui.vuetify3 import SinglePageLayout 14 | from trame.widgets import vuetify3 15 | 16 | pv.OFF_SCREEN = True 17 | 18 | server = get_server() 19 | state, ctrl = server.state, server.controller 20 | 21 | mesh = examples.download_antarctica_velocity() 22 | 23 | pl = pv.Plotter() 24 | actor = pl.add_mesh(mesh) 25 | pl.view_xy() 26 | 27 | 28 | @state.change("scalars") 29 | def set_scalars(scalars=mesh.active_scalars_name, **kwargs) -> None: 30 | actor.mapper.array_name = scalars 31 | actor.mapper.scalar_range = mesh.get_data_range(scalars) 32 | ctrl.view_update() 33 | 34 | 35 | @state.change("log_scale") 36 | def set_log_scale(log_scale=False, **kwargs) -> None: # noqa: FBT002 37 | actor.mapper.lookup_table.log_scale = log_scale 38 | ctrl.view_update() 39 | 40 | 41 | with SinglePageLayout(server) as layout: 42 | with layout.toolbar: 43 | vuetify3.VSpacer() 44 | vuetify3.VCheckbox( 45 | label="Log Scale", 46 | v_model=("log_scale", False), 47 | hide_details=True, 48 | density="compact", 49 | outlined=True, 50 | ) 51 | vuetify3.VSelect( 52 | label="Scalars", 53 | v_model=("scalars", mesh.active_scalars_name), 54 | items=("array_list", list(mesh.point_data.keys())), 55 | hide_details=True, 56 | density="compact", 57 | outlined=True, 58 | classes="pt-1 ml-2", 59 | style="max-width: 250px", 60 | ) 61 | 62 | with ( 63 | layout.content, 64 | vuetify3.VContainer( 65 | fluid=True, 66 | classes="pa-0 fill-height", 67 | ), 68 | ): 69 | # Use PyVista UI template for Plotters 70 | view = plotter_ui(pl) 71 | ctrl.view_update = view.update 72 | 73 | # Show UI 74 | await layout.ready 75 | layout 76 | ############################################################################### 77 | # .. raw:: html 78 | # 79 | #
80 | # 81 | # Open In Colab 82 | # 83 | #
84 | -------------------------------------------------------------------------------- /tutorial/09_trame/d_trame_scalar_range.py: -------------------------------------------------------------------------------- 1 | """ 2 | Control Scalar Range 3 | ~~~~~~~~~~~~~~~~~~~~ 4 | 5 | Extending our simple example to control the color limits of the mapped scalars. 6 | """ 7 | 8 | import pyvista as pv 9 | from pyvista.trame.ui import plotter_ui 10 | from trame.app import get_server 11 | from trame.ui.vuetify3 import SinglePageLayout 12 | from trame.widgets import vuetify3 13 | 14 | pv.OFF_SCREEN = True 15 | 16 | server = get_server() 17 | state, ctrl = server.state, server.controller 18 | 19 | mesh = pv.Wavelet() 20 | 21 | pl = pv.Plotter() 22 | actor = pl.add_mesh(mesh) 23 | 24 | 25 | @state.change("scalar_range") 26 | def set_scalar_range(scalar_range=mesh.get_data_range(), **kwargs) -> None: # noqa: B008 27 | actor.mapper.scalar_range = scalar_range 28 | ctrl.view_update() 29 | 30 | 31 | with SinglePageLayout(server) as layout: 32 | with layout.toolbar: 33 | vuetify3.VSpacer() 34 | vuetify3.VRangeSlider( 35 | thumb_size=16, 36 | thumb_label=True, 37 | label="Range", 38 | v_model=("scalar_range", [0, 300]), 39 | min=("0",), 40 | max=("500",), 41 | density="compact", 42 | hide_details=True, 43 | style="max-width: 400px", 44 | ) 45 | 46 | with ( 47 | layout.content, 48 | vuetify3.VContainer( 49 | fluid=True, 50 | classes="pa-0 fill-height", 51 | ), 52 | ): 53 | # Use PyVista UI template for Plotters 54 | view = plotter_ui(pl) 55 | ctrl.view_update = view.update 56 | 57 | # Show UI 58 | await layout.ready 59 | layout 60 | ############################################################################### 61 | # .. raw:: html 62 | # 63 | #
64 | # 65 | # Open In Colab 66 | # 67 | #
68 | -------------------------------------------------------------------------------- /tutorial/09_trame/e_trame_algorithm.py: -------------------------------------------------------------------------------- 1 | """ 2 | Using VTK, PyVista, and Trame 3 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | 5 | This example demonstrates how to use VTK, PyVista, and Trame together 6 | to show how the three libraries complement each other. 7 | """ 8 | 9 | import pyvista as pv 10 | from pyvista.trame.ui import plotter_ui 11 | from trame.app import get_server 12 | from trame.ui.vuetify3 import SinglePageLayout 13 | from trame.widgets import vuetify3 14 | from vtkmodules.vtkFiltersSources import vtkConeSource 15 | 16 | pv.OFF_SCREEN = True 17 | 18 | server = get_server() 19 | state, ctrl = server.state, server.controller 20 | 21 | source = vtkConeSource() 22 | 23 | pl = pv.Plotter() 24 | pl.add_mesh(source, color="seagreen") 25 | 26 | 27 | @state.change("resolution") 28 | def update_contour(resolution, **kwargs) -> None: 29 | source.SetResolution(int(resolution)) 30 | ctrl.view_update() 31 | 32 | 33 | with SinglePageLayout(server) as layout: 34 | with layout.toolbar: 35 | vuetify3.VSpacer() 36 | vuetify3.VSlider( 37 | v_model=("resolution", 15), 38 | min=5, 39 | max=30, 40 | hide_details=True, 41 | density="compact", 42 | style="max-width: 300px", 43 | change=ctrl.view_update, 44 | ) 45 | vuetify3.VProgressLinear( 46 | indeterminate=True, 47 | absolute=True, 48 | bottom=True, 49 | active=("trame__busy",), 50 | ) 51 | 52 | with ( 53 | layout.content, 54 | vuetify3.VContainer( 55 | fluid=True, 56 | classes="pa-0 fill-height", 57 | ), 58 | ): 59 | # Use PyVista UI template for Plotters 60 | view = plotter_ui(pl) 61 | ctrl.view_update = view.update 62 | 63 | # Show UI 64 | await layout.ready 65 | layout 66 | ############################################################################### 67 | # .. raw:: html 68 | # 69 | #
70 | # 71 | # Open In Colab 72 | # 73 | #
74 | -------------------------------------------------------------------------------- /tutorial/09_trame/f_trame_open_file.py: -------------------------------------------------------------------------------- 1 | """ 2 | Open Mesh File 3 | ~~~~~~~~~~~~~~ 4 | 5 | An example of opening a mesh file from the browser and viewing it with PyVista. 6 | 7 | """ 8 | 9 | import tempfile 10 | from pathlib import Path 11 | 12 | import pyvista as pv 13 | from pyvista.trame.ui import plotter_ui 14 | from trame.app import get_server 15 | from trame.app.file_upload import ClientFile 16 | from trame.ui.vuetify3 import SinglePageLayout 17 | from trame.widgets import vuetify3 18 | 19 | pv.OFF_SCREEN = True 20 | 21 | server = get_server() 22 | state, ctrl = server.state, server.controller 23 | 24 | pl = pv.Plotter() 25 | 26 | 27 | @server.state.change("file_exchange") 28 | def handle(file_exchange, **kwargs) -> None: 29 | file = ClientFile(file_exchange) 30 | 31 | if file.content: 32 | print(file.info) # noqa: T201 33 | bytes = file.content # noqa: A001 34 | with tempfile.NamedTemporaryFile(suffix=file.name) as path: 35 | with Path(path.name).open("wb") as f: 36 | f.write(bytes) 37 | ds = pv.read(path.name) 38 | pl.add_mesh(ds, name=file.name) 39 | pl.reset_camera() 40 | else: 41 | pl.clear_actors() 42 | pl.reset_camera() 43 | 44 | 45 | with SinglePageLayout(server) as layout: 46 | with layout.toolbar: 47 | vuetify3.VSpacer() 48 | vuetify3.VFileInput( 49 | show_size=True, 50 | small_chips=True, 51 | truncate_length=25, 52 | v_model=("file_exchange", None), 53 | density="compact", 54 | hide_details=True, 55 | style="max-width: 300px;", 56 | ) 57 | vuetify3.VProgressLinear( 58 | indeterminate=True, absolute=True, bottom=True, active=("trame__busy",) 59 | ) 60 | 61 | with layout.content: # noqa: SIM117 62 | with vuetify3.VContainer( 63 | fluid=True, classes="pa-0 fill-height", style="position: relative;" 64 | ): 65 | view = plotter_ui(pl) 66 | ctrl.view_update = view.update 67 | 68 | # Show UI 69 | await layout.ready 70 | layout 71 | ############################################################################### 72 | # .. raw:: html 73 | # 74 | #
75 | # 76 | # Open In Colab 77 | # 78 | #
79 | --------------------------------------------------------------------------------