init
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
"""PyVista Demos."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pyvista.demos.demos import glyphs as glyphs
|
||||
from pyvista.demos.demos import orientation_cube as orientation_cube
|
||||
from pyvista.demos.demos import orientation_plotter as orientation_plotter
|
||||
from pyvista.demos.demos import plot_ants_plane as plot_ants_plane
|
||||
from pyvista.demos.demos import plot_beam as plot_beam
|
||||
from pyvista.demos.demos import plot_datasets as plot_datasets
|
||||
from pyvista.demos.demos import plot_glyphs as plot_glyphs
|
||||
from pyvista.demos.demos import plot_wave as plot_wave
|
||||
from pyvista.demos.logo import logo_atomized as logo_atomized
|
||||
from pyvista.demos.logo import logo_basic as logo_basic
|
||||
from pyvista.demos.logo import logo_letters as logo_letters
|
||||
from pyvista.demos.logo import logo_voxel as logo_voxel
|
||||
from pyvista.demos.logo import plot_logo as plot_logo
|
||||
@@ -0,0 +1,575 @@
|
||||
"""Demos to show off the functionality of PyVista."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
|
||||
import numpy as np
|
||||
|
||||
import pyvista
|
||||
from pyvista import examples
|
||||
from pyvista._deprecate_positional_args import _deprecate_positional_args
|
||||
|
||||
from .logo import text_3d
|
||||
|
||||
|
||||
def glyphs(grid_sz=3):
|
||||
"""Create several parametric supertoroids using VTK's glyph table functionality.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
grid_sz : int, default: 3
|
||||
Create ``grid_sz x grid_sz`` supertoroids.
|
||||
|
||||
Returns
|
||||
-------
|
||||
pyvista.PolyData
|
||||
Mesh of supertoroids.
|
||||
|
||||
See Also
|
||||
--------
|
||||
plot_glyphs
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from pyvista import demos
|
||||
>>> mesh = demos.glyphs()
|
||||
>>> mesh.plot()
|
||||
|
||||
"""
|
||||
# Seed rng for reproducible plots
|
||||
rng = np.random.default_rng(seed=0)
|
||||
|
||||
n = 10
|
||||
values = np.arange(n) # values for scalars to look up glyphs by
|
||||
|
||||
# taken from:
|
||||
params = rng.uniform(0.5, 2, size=(n, 2)) # (n1, n2) parameters for the toroids
|
||||
|
||||
geoms = [pyvista.ParametricSuperToroid(n1=n1, n2=n2) for n1, n2 in params]
|
||||
|
||||
# get dataset where to put glyphs
|
||||
grid_sz = float(grid_sz)
|
||||
x, y, z = np.mgrid[:grid_sz, :grid_sz, :grid_sz]
|
||||
mesh = pyvista.StructuredGrid(x, y, z)
|
||||
|
||||
# add random scalars
|
||||
rng_int = rng.integers(0, n, size=x.size)
|
||||
mesh.point_data['scalars'] = rng_int
|
||||
|
||||
# construct the glyphs on top of the mesh; don't scale by scalars now
|
||||
return mesh.glyph(
|
||||
geom=geoms,
|
||||
indices=values,
|
||||
scale=False,
|
||||
factor=0.3,
|
||||
rng=(0, n - 1),
|
||||
orient=False,
|
||||
)
|
||||
|
||||
|
||||
def plot_glyphs(grid_sz=3, **kwargs):
|
||||
"""Plot several parametric supertoroids using VTK's glyph table functionality.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
grid_sz : int, default: 3
|
||||
Create ``grid_sz x grid_sz`` supertoroids.
|
||||
|
||||
**kwargs : dict, optional
|
||||
All additional keyword arguments will be passed to
|
||||
:func:`pyvista.Plotter.add_mesh`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
list | np.ndarray | ipywidgets.Widget
|
||||
See :func:`show <pyvista.Plotter.show>`.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from pyvista import demos
|
||||
>>> demos.plot_glyphs()
|
||||
|
||||
"""
|
||||
# construct the glyphs on top of the mesh; don't scale by scalars now
|
||||
mesh = glyphs(grid_sz)
|
||||
|
||||
kwargs.setdefault('specular', 1)
|
||||
kwargs.setdefault('specular_power', 15)
|
||||
kwargs.setdefault('smooth_shading', True)
|
||||
|
||||
# create plotter and add our glyphs with some nontrivial lighting
|
||||
plotter = pyvista.Plotter()
|
||||
plotter.add_mesh(mesh, show_scalar_bar=False, **kwargs)
|
||||
return plotter.show()
|
||||
|
||||
|
||||
def orientation_cube():
|
||||
"""Return a dictionary containing the meshes composing an orientation cube.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
Dictionary containing the meshes composing an orientation cube.
|
||||
|
||||
Examples
|
||||
--------
|
||||
Load the cube mesh and plot it
|
||||
|
||||
>>> import pyvista as pv
|
||||
>>> from pyvista import demos
|
||||
>>> ocube = demos.orientation_cube()
|
||||
>>> pl = pv.Plotter()
|
||||
>>> _ = pl.add_mesh(ocube['cube'], show_edges=True)
|
||||
>>> _ = pl.add_mesh(ocube['x_p'], color='blue')
|
||||
>>> _ = pl.add_mesh(ocube['x_n'], color='blue')
|
||||
>>> _ = pl.add_mesh(ocube['y_p'], color='green')
|
||||
>>> _ = pl.add_mesh(ocube['y_n'], color='green')
|
||||
>>> _ = pl.add_mesh(ocube['z_p'], color='red')
|
||||
>>> _ = pl.add_mesh(ocube['z_n'], color='red')
|
||||
>>> pl.show_axes()
|
||||
>>> pl.show()
|
||||
|
||||
"""
|
||||
cube = pyvista.Cube()
|
||||
|
||||
x_p = text_3d('X+', depth=0.2)
|
||||
x_p.points *= 0.45
|
||||
x_p.rotate_y(90, inplace=True)
|
||||
x_p.rotate_x(90, inplace=True)
|
||||
x_p.translate(-np.array(x_p.center), inplace=True)
|
||||
x_p.translate([0.5, 0, 0], inplace=True)
|
||||
# x_p.point_data['mesh'] = 1
|
||||
|
||||
x_n = text_3d('X-', depth=0.2)
|
||||
x_n.points *= 0.45
|
||||
x_n.rotate_y(90, inplace=True)
|
||||
x_n.rotate_x(90, inplace=True)
|
||||
x_n.rotate_z(180, inplace=True)
|
||||
x_n.translate(-np.array(x_n.center), inplace=True)
|
||||
x_n.translate([-0.5, 0, 0], inplace=True)
|
||||
# x_n.point_data['mesh'] = 2
|
||||
|
||||
y_p = text_3d('Y+', depth=0.2)
|
||||
y_p.points *= 0.45
|
||||
y_p.rotate_x(90, inplace=True)
|
||||
y_p.rotate_z(180, inplace=True)
|
||||
y_p.translate(-np.array(y_p.center), inplace=True)
|
||||
y_p.translate([0, 0.5, 0], inplace=True)
|
||||
# y_p.point_data['mesh'] = 3
|
||||
|
||||
y_n = text_3d('Y-', depth=0.2)
|
||||
y_n.points *= 0.45
|
||||
y_n.rotate_x(90, inplace=True)
|
||||
y_n.translate(-np.array(y_n.center), inplace=True)
|
||||
y_n.translate([0, -0.5, 0], inplace=True)
|
||||
# y_n.point_data['mesh'] = 4
|
||||
|
||||
z_p = text_3d('Z+', depth=0.2)
|
||||
z_p.points *= 0.45
|
||||
z_p.rotate_z(90, inplace=True)
|
||||
z_p.translate(-np.array(z_p.center), inplace=True)
|
||||
z_p.translate([0, 0, 0.5], inplace=True)
|
||||
# z_p.point_data['mesh'] = 5
|
||||
|
||||
z_n = text_3d('Z-', depth=0.2)
|
||||
z_n.points *= 0.45
|
||||
z_n.rotate_x(180, inplace=True)
|
||||
z_n.translate(-np.array(z_n.center), inplace=True)
|
||||
z_n.translate([0, 0, -0.5], inplace=True)
|
||||
|
||||
return {
|
||||
'cube': cube,
|
||||
'x_p': x_p,
|
||||
'x_n': x_n,
|
||||
'y_p': y_p,
|
||||
'y_n': y_n,
|
||||
'z_p': z_p,
|
||||
'z_n': z_n,
|
||||
}
|
||||
|
||||
|
||||
def orientation_plotter():
|
||||
"""Return a plotter containing the orientation cube.
|
||||
|
||||
Returns
|
||||
-------
|
||||
pyvista.Plotter
|
||||
Orientation cube plotter.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from pyvista import demos
|
||||
>>> plotter = demos.orientation_plotter()
|
||||
>>> plotter.show()
|
||||
|
||||
"""
|
||||
ocube = orientation_cube()
|
||||
pl = pyvista.Plotter()
|
||||
pl.add_mesh(ocube['cube'], show_edges=True)
|
||||
pl.add_mesh(ocube['x_p'], color='blue')
|
||||
pl.add_mesh(ocube['x_n'], color='blue')
|
||||
pl.add_mesh(ocube['y_p'], color='green')
|
||||
pl.add_mesh(ocube['y_n'], color='green')
|
||||
pl.add_mesh(ocube['z_p'], color='red')
|
||||
pl.add_mesh(ocube['z_n'], color='red')
|
||||
pl.show_axes() # type: ignore[call-arg]
|
||||
return pl
|
||||
|
||||
|
||||
@_deprecate_positional_args
|
||||
def plot_wave(fps=30, frequency=1, wavetime=3, notebook=None): # noqa: PLR0917
|
||||
"""Plot a 3D moving wave in a render window.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fps : int, default: 30
|
||||
Maximum frames per second to display.
|
||||
|
||||
frequency : float, default: 1.0
|
||||
Wave cycles per second (Hz).
|
||||
|
||||
wavetime : float, default: 3.0
|
||||
The desired total display time in seconds.
|
||||
|
||||
notebook : bool, optional
|
||||
When ``True``, the resulting plot is placed inline a jupyter
|
||||
notebook. Assumes a jupyter console is active.
|
||||
|
||||
Returns
|
||||
-------
|
||||
numpy.ndarray
|
||||
Position of points at last frame.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from pyvista import demos
|
||||
>>> out = demos.plot_wave()
|
||||
|
||||
"""
|
||||
# camera position
|
||||
cpos = [
|
||||
(6.879481857604187, -32.143727535933195, 23.05622921691103),
|
||||
(-0.2336056403734026, -0.6960083534590372, -0.7226721553894022),
|
||||
(-0.008900669873416645, 0.6018246347860926, 0.7985786667826725),
|
||||
]
|
||||
|
||||
# Make data
|
||||
X = np.arange(-10, 10, 0.25)
|
||||
Y = np.arange(-10, 10, 0.25)
|
||||
X, Y = np.meshgrid(X, Y)
|
||||
R = np.sqrt(X**2 + Y**2)
|
||||
Z = np.sin(R)
|
||||
|
||||
# Create and plot structured grid
|
||||
sgrid = pyvista.StructuredGrid(X, Y, Z)
|
||||
|
||||
mesh = sgrid.extract_surface()
|
||||
mesh['Height'] = Z.ravel()
|
||||
|
||||
# Start a plotter object and set the scalars to the Z height
|
||||
plotter = pyvista.Plotter(notebook=notebook)
|
||||
plotter.add_mesh(mesh, scalars='Height', show_scalar_bar=False, smooth_shading=True)
|
||||
plotter.camera_position = cpos
|
||||
plotter.show(
|
||||
title='Wave Example',
|
||||
window_size=[800, 600],
|
||||
auto_close=False,
|
||||
interactive_update=True,
|
||||
)
|
||||
|
||||
# Update Z and display a frame for each updated position
|
||||
tdelay = 1.0 / fps
|
||||
tlast = time.time()
|
||||
tstart = time.time()
|
||||
while time.time() - tstart < wavetime:
|
||||
# get phase from start
|
||||
telap = time.time() - tstart
|
||||
phase = telap * 2 * np.pi * frequency
|
||||
Z = np.sin(R + phase)
|
||||
mesh.points[:, -1] = Z.ravel()
|
||||
mesh['Height'] = Z.ravel()
|
||||
|
||||
mesh.compute_normals(inplace=True)
|
||||
|
||||
# Render and get time to render
|
||||
plotter.update()
|
||||
|
||||
# time delay
|
||||
tpast = time.time() - tlast
|
||||
if tpast < tdelay and tpast >= 0 and not plotter.off_screen:
|
||||
time.sleep(tdelay - tpast)
|
||||
|
||||
# store when rendering complete
|
||||
tlast = time.time()
|
||||
|
||||
# Close movie and delete object
|
||||
plotter.close()
|
||||
return mesh.points
|
||||
|
||||
|
||||
def plot_ants_plane(notebook=None):
|
||||
"""Plot two ants and airplane.
|
||||
|
||||
Demonstrate how to create a plot class to plot multiple meshes while
|
||||
adding scalars and text.
|
||||
|
||||
This example plots the following:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import pyvista as pv
|
||||
>>> from pyvista import examples
|
||||
|
||||
Load and shrink airplane
|
||||
|
||||
>>> airplane = examples.load_airplane()
|
||||
>>> airplane.points /= 10
|
||||
|
||||
Rotate and translate ant so it is on the plane.
|
||||
|
||||
>>> ant = examples.load_ant()
|
||||
>>> _ = ant.rotate_x(90, inplace=True)
|
||||
>>> _ = ant.translate([90, 60, 15], inplace=True)
|
||||
|
||||
Make a copy and add another ant.
|
||||
|
||||
>>> ant_copy = ant.translate([30, 0, -10], inplace=False)
|
||||
|
||||
Create plotting object.
|
||||
|
||||
>>> plotter = pv.Plotter()
|
||||
>>> _ = plotter.add_mesh(ant, color='r')
|
||||
>>> _ = plotter.add_mesh(ant_copy, color='b')
|
||||
|
||||
Add airplane mesh and make the color equal to the Y position.
|
||||
|
||||
>>> plane_scalars = airplane.points[:, 1]
|
||||
>>> _ = plotter.add_mesh(
|
||||
... airplane,
|
||||
... scalars=plane_scalars,
|
||||
... scalar_bar_args={'title': 'Plane Y Location'},
|
||||
... )
|
||||
>>> _ = plotter.add_text('Ants and Plane Example')
|
||||
>>> plotter.show()
|
||||
|
||||
Parameters
|
||||
----------
|
||||
notebook : bool, optional
|
||||
When ``True``, the resulting plot is placed inline a jupyter
|
||||
notebook. Assumes a jupyter console is active.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from pyvista import demos
|
||||
>>> demos.plot_ants_plane()
|
||||
|
||||
"""
|
||||
# load and shrink airplane
|
||||
airplane = examples.load_airplane()
|
||||
airplane.points /= 10
|
||||
|
||||
# rotate and translate ant so it is on the plane
|
||||
ant = examples.load_ant()
|
||||
ant.rotate_x(90, inplace=True)
|
||||
ant.translate([90, 60, 15], inplace=True)
|
||||
|
||||
# Make a copy and add another ant
|
||||
ant_copy = ant.copy()
|
||||
ant_copy.translate([30, 0, -10], inplace=True)
|
||||
|
||||
# Create plotting object
|
||||
plotter = pyvista.Plotter(notebook=notebook)
|
||||
plotter.add_mesh(ant, color='r')
|
||||
plotter.add_mesh(ant_copy, color='b')
|
||||
|
||||
# Add airplane mesh and make the color equal to the Y position
|
||||
plane_scalars = airplane.points[:, 1]
|
||||
plotter.add_mesh(
|
||||
airplane,
|
||||
scalars=plane_scalars,
|
||||
scalar_bar_args={'title': 'Plane Y\nLocation'},
|
||||
)
|
||||
plotter.add_text('Ants and Plane Example')
|
||||
plotter.show()
|
||||
|
||||
|
||||
def plot_beam(notebook=None):
|
||||
"""Plot a beam with displacement.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
notebook : bool, optional
|
||||
When ``True``, the resulting plot is placed inline a jupyter
|
||||
notebook. Assumes a jupyter console is active.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from pyvista import demos
|
||||
>>> demos.plot_beam()
|
||||
|
||||
"""
|
||||
# Create fiticious displacements as a function of Z location
|
||||
grid = examples.load_hexbeam()
|
||||
d = grid.points[:, 2] ** 3 / 250
|
||||
grid.points[:, 1] += d
|
||||
|
||||
# Camera position
|
||||
cpos = [
|
||||
(11.915126303095157, 6.11392754955802, 3.6124956735471914),
|
||||
(0.0, 0.375, 2.0),
|
||||
(-0.42546442225230097, 0.9024244135964158, -0.06789847673314177),
|
||||
]
|
||||
|
||||
cmap = 'bwr'
|
||||
|
||||
# plot this displaced beam
|
||||
plotter = pyvista.Plotter(notebook=notebook)
|
||||
plotter.add_mesh(
|
||||
grid,
|
||||
scalars=d,
|
||||
scalar_bar_args={'title': 'Y Displacement'},
|
||||
rng=[-d.max(), d.max()],
|
||||
cmap=cmap, # type: ignore[arg-type]
|
||||
)
|
||||
plotter.camera_position = cpos
|
||||
plotter.add_text('Static Beam Example')
|
||||
plotter.show()
|
||||
|
||||
|
||||
def plot_datasets(dataset_type=None):
|
||||
"""Plot the pyvista dataset types.
|
||||
|
||||
This demo plots the following PyVista dataset types:
|
||||
|
||||
* :class:`pyvista.PolyData`
|
||||
* :class:`pyvista.UnstructuredGrid`
|
||||
* :class:`pyvista.ImageData`
|
||||
* :class:`pyvista.RectilinearGrid`
|
||||
* :class:`pyvista.StructuredGrid`
|
||||
|
||||
Parameters
|
||||
----------
|
||||
dataset_type : str, optional
|
||||
If set, plot just that dataset. Must be one of the following:
|
||||
|
||||
* ``'PolyData'``
|
||||
* ``'UnstructuredGrid'``
|
||||
* ``'ImageData'``
|
||||
* ``'RectilinearGrid'``
|
||||
* ``'StructuredGrid'``
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from pyvista import demos
|
||||
>>> demos.plot_datasets()
|
||||
|
||||
"""
|
||||
allowable_types = [
|
||||
'PolyData',
|
||||
'UnstructuredGrid',
|
||||
'ImageData',
|
||||
'RectilinearGrid',
|
||||
'StructuredGrid',
|
||||
]
|
||||
if dataset_type is not None and dataset_type not in allowable_types:
|
||||
msg = (
|
||||
f'Invalid dataset_type {dataset_type}. '
|
||||
f'Must be one of the following: {allowable_types}'
|
||||
)
|
||||
raise ValueError(msg)
|
||||
|
||||
###########################################################################
|
||||
# uniform grid
|
||||
image = pyvista.ImageData(dimensions=(6, 6, 1))
|
||||
image.spacing = (3, 2, 1)
|
||||
|
||||
###########################################################################
|
||||
# RectilinearGrid
|
||||
xrng = np.array([0, 0.3, 1, 4, 5, 6, 6.2, 6.6])
|
||||
yrng = np.linspace(-2, 2, 5)
|
||||
zrng = [1]
|
||||
rec_grid = pyvista.RectilinearGrid(xrng, yrng, zrng)
|
||||
|
||||
###########################################################################
|
||||
# structured grid
|
||||
ang = np.linspace(0, np.pi / 2, 10)
|
||||
r = np.linspace(6, 10, 8)
|
||||
z = [0]
|
||||
ang, r, z = np.meshgrid(ang, r, z) # type: ignore[assignment]
|
||||
|
||||
x = r * np.sin(ang)
|
||||
y = r * np.cos(ang)
|
||||
|
||||
struct_grid = pyvista.StructuredGrid(x[::-1], y[::-1], z[::-1])
|
||||
|
||||
###########################################################################
|
||||
# polydata
|
||||
points = pyvista.PolyData([[1.0, 2.0, 2.0], [2.0, 2.0, 2.0]])
|
||||
|
||||
line = pyvista.Line()
|
||||
line.points += np.array((2, 0, 0))
|
||||
line.clear_data()
|
||||
|
||||
tri = pyvista.Triangle()
|
||||
tri.points += np.array([0, 1, 0])
|
||||
circ = pyvista.Circle()
|
||||
circ.points += np.array([1.5, 1.5, 0])
|
||||
|
||||
poly = tri + circ
|
||||
|
||||
###########################################################################
|
||||
# unstructuredgrid
|
||||
pyr = pyvista.Pyramid()
|
||||
pyr.points *= 0.7
|
||||
cube = pyvista.Cube(center=(2, 0, 0))
|
||||
ugrid = circ + pyr + cube + tri
|
||||
|
||||
pl = pyvista.Plotter() if dataset_type is not None else pyvista.Plotter(shape='3/2')
|
||||
|
||||
# polydata
|
||||
if dataset_type is None:
|
||||
pl.subplot(0)
|
||||
pl.add_text('4. PolyData')
|
||||
if dataset_type in [None, 'PolyData']:
|
||||
pl.add_points(points, point_size=20)
|
||||
pl.add_mesh(line, line_width=5)
|
||||
pl.add_mesh(poly)
|
||||
pl.add_mesh(poly.extract_all_edges(), line_width=2, color='k')
|
||||
|
||||
# unstructuredgrid
|
||||
if dataset_type is None:
|
||||
pl.subplot(1)
|
||||
pl.add_text('5. UnstructuredGrid')
|
||||
if dataset_type in [None, 'UnstructuredGrid']:
|
||||
pl.add_mesh(ugrid)
|
||||
pl.add_mesh(ugrid.extract_all_edges(), line_width=2, color='k')
|
||||
|
||||
# ImageData
|
||||
if dataset_type is None:
|
||||
pl.subplot(2)
|
||||
pl.add_text('1. ImageData')
|
||||
if dataset_type in [None, 'ImageData']:
|
||||
pl.add_mesh(image)
|
||||
pl.add_mesh(image.extract_all_edges(), color='k', style='wireframe', line_width=2)
|
||||
pl.camera_position = 'xy'
|
||||
|
||||
# RectilinearGrid
|
||||
if dataset_type is None:
|
||||
pl.subplot(3)
|
||||
pl.add_text('2. RectilinearGrid')
|
||||
if dataset_type in [None, 'RectilinearGrid']:
|
||||
pl.add_mesh(rec_grid)
|
||||
pl.add_mesh(rec_grid.extract_all_edges(), color='k', style='wireframe', line_width=2)
|
||||
pl.camera_position = 'xy'
|
||||
|
||||
# StructuredGrid
|
||||
if dataset_type is None:
|
||||
pl.subplot(4)
|
||||
pl.add_text('3. StructuredGrid')
|
||||
if dataset_type in [None, 'StructuredGrid']:
|
||||
pl.add_mesh(struct_grid)
|
||||
pl.add_mesh(struct_grid.extract_all_edges(), color='k', style='wireframe', line_width=2)
|
||||
pl.camera_position = 'xy'
|
||||
|
||||
pl.show()
|
||||
@@ -0,0 +1,362 @@
|
||||
"""Generate the pyvista logo.
|
||||
|
||||
Logos generated with:
|
||||
plot_logo(screenshot='pyvista_logo.png', window_size=(1920, 1080))
|
||||
plot_logo(screenshot='pyvista_logo_sm.png', window_size=(960, 400), off_screen=True)
|
||||
|
||||
# different camera angle for square plot
|
||||
cpos = [(-0.3654543687422538, 1.1098808905156292, 9.073223697728247),
|
||||
(2.553950615449191, 0.34145688392081264, 0.06127122762851659),
|
||||
(0.019308531920309947, 0.996708840795678, -0.07873161547192065)]
|
||||
|
||||
plot_logo(screenshot='pyvista_logo_sm_sq.png', window_size=(960, 960), cpos=cpos,
|
||||
off_screen=True)
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
|
||||
import pyvista
|
||||
from pyvista import examples
|
||||
from pyvista._deprecate_positional_args import _deprecate_positional_args
|
||||
from pyvista.core import _vtk_core as _vtk
|
||||
from pyvista.core.utilities.features import _voxelize_legacy
|
||||
|
||||
THIS_PATH = str(Path(os.path.realpath(__file__)).parent)
|
||||
|
||||
LOGO_TITLE = 'PyVista'
|
||||
|
||||
|
||||
def atomize(grid, shift_fac=0.1, scale=0.9):
|
||||
"""Break apart and shrink and/or scale the individual cells of a mesh.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
grid : pyvista.UnstructuredGrid
|
||||
The input mesh to atomize.
|
||||
shift_fac : float, default: 0.1
|
||||
Factor by which to shift the individual cells apart.
|
||||
scale : float, default: 0.9
|
||||
Factor by which to scale the individual cells.
|
||||
|
||||
Returns
|
||||
-------
|
||||
pyvista.UnstructuredGrid
|
||||
The atomized mesh with individually shifted and scaled cells.
|
||||
|
||||
"""
|
||||
cent = grid.center
|
||||
cells = []
|
||||
for i in range(grid.n_cells):
|
||||
cell = grid.extract_cells(i)
|
||||
ccent = np.array(cell.center)
|
||||
cell.points[:] = (cell.points - ccent) * scale + ccent
|
||||
cell.points += (ccent - np.array(cent)) * shift_fac
|
||||
cells.append(cell)
|
||||
|
||||
return cells[0].merge(cells[1:])
|
||||
|
||||
|
||||
def text_3d(string, depth=0.5):
|
||||
"""Create 3D text from a given string.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
string : str
|
||||
The string of text to convert into 3D text.
|
||||
|
||||
depth : float, default: 0.5
|
||||
The depth of the extrusion used to create the 3D text.
|
||||
|
||||
Returns
|
||||
-------
|
||||
pyvista.DataSet
|
||||
The 3D text in the form of a PyVista DataSet.
|
||||
|
||||
See Also
|
||||
--------
|
||||
:ref:`create_pixel_art_example`
|
||||
|
||||
"""
|
||||
from vtkmodules.vtkRenderingFreeType import vtkVectorText # noqa: PLC0415
|
||||
|
||||
vec_text = vtkVectorText()
|
||||
vec_text.SetText(string)
|
||||
|
||||
extrude = _vtk.vtkLinearExtrusionFilter()
|
||||
extrude.SetInputConnection(vec_text.GetOutputPort())
|
||||
extrude.SetExtrusionTypeToNormalExtrusion()
|
||||
extrude.SetVector(0, 0, 1)
|
||||
extrude.SetScaleFactor(depth)
|
||||
|
||||
tri_filter = _vtk.vtkTriangleFilter()
|
||||
tri_filter.SetInputConnection(extrude.GetOutputPort())
|
||||
tri_filter.Update()
|
||||
return pyvista.wrap(tri_filter.GetOutput())
|
||||
|
||||
|
||||
@_deprecate_positional_args
|
||||
def logo_letters(merge=False, depth=0.3): # noqa: FBT002
|
||||
"""Generate a mesh for each letter in "PyVista".
|
||||
|
||||
Parameters
|
||||
----------
|
||||
merge : bool, optional
|
||||
If ``True``, merge the meshes of the individual letters into a single
|
||||
mesh. If ``False``, return a dictionary where the keys are the letters
|
||||
and the values are the respective meshes.
|
||||
depth : float, optional
|
||||
The depth of the extrusion for each letter in the mesh.
|
||||
|
||||
Returns
|
||||
-------
|
||||
pyvista.PolyData or dict[str, pyvista.PolyData]
|
||||
If merge is ``True``, returns a single merged mesh containing all the
|
||||
letters in "PyVista". If merge is ``False``, returns a dictionary where
|
||||
the keys are the letters and the values are the respective meshes.
|
||||
|
||||
"""
|
||||
mesh_letters = pyvista.PolyData() if merge else {} # type: ignore[var-annotated]
|
||||
|
||||
# spacing between letters
|
||||
space_factor = 0.9
|
||||
width = 0
|
||||
for letter in LOGO_TITLE:
|
||||
mesh_letter = text_3d(letter, depth=depth)
|
||||
this_letter_width = mesh_letter.points[:, 0].max()
|
||||
mesh_letter.translate([width * space_factor, 0, 0.0], inplace=True)
|
||||
width += this_letter_width
|
||||
if merge:
|
||||
mesh_letters += mesh_letter
|
||||
else:
|
||||
mesh_letters[letter] = mesh_letter
|
||||
|
||||
return mesh_letters
|
||||
|
||||
|
||||
def logo_voxel(density=0.03):
|
||||
"""Create a voxelized PyVista logo.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
density : float, default: 0.03
|
||||
Density of the voxelization.
|
||||
|
||||
Returns
|
||||
-------
|
||||
pyvista.UnstructuredGrid
|
||||
Voxelized PyVista logo as an unstructured grid.
|
||||
|
||||
"""
|
||||
return _voxelize_legacy(text_3d(LOGO_TITLE, depth=0.3), density=density)
|
||||
|
||||
|
||||
def logo_basic():
|
||||
"""Create a basic pyvista logo.
|
||||
|
||||
Returns
|
||||
-------
|
||||
pyvista.UnstructuredGrid
|
||||
Grid containing the pyvista letters.
|
||||
|
||||
Examples
|
||||
--------
|
||||
Plot the basic pyvista logo.
|
||||
|
||||
>>> from pyvista import demos
|
||||
>>> logo = demos.logo_basic()
|
||||
>>> cpos = logo.plot(smooth_shading=True)
|
||||
|
||||
Add scalars and plot the logo.
|
||||
|
||||
>>> logo['x_coord'] = logo.points[:, 0]
|
||||
>>> cpos = logo.plot(
|
||||
... scalars='x_coord',
|
||||
... cmap='Spectral',
|
||||
... smooth_shading=True,
|
||||
... cpos='xy',
|
||||
... )
|
||||
|
||||
"""
|
||||
return logo_letters(merge=True).compute_normals(split_vertices=True)
|
||||
|
||||
|
||||
@_deprecate_positional_args
|
||||
def plot_logo( # noqa: PLR0917
|
||||
window_size=None,
|
||||
off_screen=None,
|
||||
screenshot=None,
|
||||
cpos=None,
|
||||
just_return_plotter=False, # noqa: FBT002
|
||||
show_note=False, # noqa: FBT002
|
||||
**kwargs,
|
||||
):
|
||||
"""Plot the stylized PyVista logo.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
window_size : sequence[int], optional
|
||||
Size of the window in the format ``[width, height]``.
|
||||
off_screen : bool, optional
|
||||
Renders off screen when ``True``.
|
||||
screenshot : str, optional
|
||||
Save screenshot to path when specified.
|
||||
cpos : list or str, optional
|
||||
Camera position to use.
|
||||
just_return_plotter : bool, default: False
|
||||
Return the plotter instance without rendering.
|
||||
show_note : bool, default: False
|
||||
Show a text in the plot when ``True``.
|
||||
**kwargs : dict, optional
|
||||
Additional keyword arguments.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Plotter or camera position
|
||||
Returns the plotter instance if ``just_return_plotter`` is ``True``,
|
||||
otherwise returns the camera position if ``screenshot`` is specified,
|
||||
otherwise shows the plot.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from pyvista import demos
|
||||
>>> cpos = demos.plot_logo()
|
||||
|
||||
"""
|
||||
# initialize plotter
|
||||
if window_size is None:
|
||||
window_size = [960, 400]
|
||||
plotter = pyvista.Plotter(window_size=window_size, off_screen=off_screen)
|
||||
|
||||
mesh_letters = logo_letters()
|
||||
|
||||
# letter 'P'
|
||||
p_mesh = mesh_letters['P'].compute_normals(split_vertices=True)
|
||||
plotter.add_mesh(p_mesh, color='#376fa0', smooth_shading=True)
|
||||
|
||||
# letter 'y'
|
||||
y_mesh = mesh_letters['y'].compute_normals(split_vertices=True)
|
||||
plotter.add_mesh(y_mesh, color='#ffd040', smooth_shading=True)
|
||||
|
||||
# letter 'V'
|
||||
v_grid = _voxelize_legacy(mesh_letters['V'], density=0.08)
|
||||
v_grid_atom = atomize(v_grid)
|
||||
v_grid_atom['scalars'] = v_grid_atom.points[:, 0]
|
||||
v_grid_atom_surf = v_grid_atom.extract_surface()
|
||||
faces = v_grid_atom_surf.faces.reshape(-1, 5).copy()
|
||||
faces[:, 1:] = faces[:, 1:][:, ::-1]
|
||||
v_grid_atom_surf.faces = faces
|
||||
plotter.add_mesh(
|
||||
v_grid_atom_surf,
|
||||
scalars='scalars',
|
||||
show_edges=True,
|
||||
cmap='winter',
|
||||
show_scalar_bar=False,
|
||||
)
|
||||
|
||||
# letter 'i'
|
||||
i_grid = _voxelize_legacy(mesh_letters['i'], density=0.1)
|
||||
|
||||
plotter.add_mesh(
|
||||
i_grid.extract_surface(),
|
||||
style='points',
|
||||
color='r',
|
||||
render_points_as_spheres=True,
|
||||
point_size=14,
|
||||
)
|
||||
plotter.add_mesh(i_grid, style='wireframe', color='k', line_width=4)
|
||||
|
||||
# letter 's'
|
||||
mesh = mesh_letters['s']
|
||||
mesh['scalars'] = mesh.points[:, 0]
|
||||
plotter.add_mesh(
|
||||
mesh,
|
||||
scalars='scalars',
|
||||
style='wireframe',
|
||||
line_width=2,
|
||||
cmap='gist_heat',
|
||||
backface_culling=True,
|
||||
render_lines_as_tubes=True,
|
||||
show_scalar_bar=False,
|
||||
)
|
||||
|
||||
# letter 't'
|
||||
mesh = mesh_letters['t'].clean().compute_normals()
|
||||
scalars = mesh.points[:, 0]
|
||||
plotter.add_mesh(mesh, scalars=scalars, show_edges=True, cmap='autumn', show_scalar_bar=False)
|
||||
|
||||
# letter 'a'
|
||||
grid = examples.download_letter_a()
|
||||
grid.points[:, 0] += mesh_letters['a'].center[0] - grid.center[0]
|
||||
|
||||
# select some cells from grid
|
||||
cells = grid.cells.reshape(-1, 5)
|
||||
mask = grid.points[cells[:, 1:], 2] < 0.2
|
||||
mask = mask.all(1)
|
||||
|
||||
a_part = grid.extract_cells(mask)
|
||||
|
||||
cells = a_part.cells.reshape(-1, 5)
|
||||
scalars = grid.points[cells[:, 1], 1]
|
||||
plotter.add_mesh(
|
||||
a_part, scalars=scalars, show_edges=True, cmap='Greens', show_scalar_bar=False
|
||||
)
|
||||
|
||||
if show_note:
|
||||
text = text_3d('You can move me!', depth=0.1)
|
||||
text.points *= 0.1
|
||||
text.translate([4.0, -0.3, 0], inplace=True)
|
||||
plotter.add_mesh(text, color='black')
|
||||
|
||||
# finalize plot and show it
|
||||
plotter.set_background(kwargs.pop('background', 'white'))
|
||||
plotter.camera_position = 'xy'
|
||||
if 'zoom' in kwargs:
|
||||
plotter.camera.zoom(kwargs.pop('zoom'))
|
||||
|
||||
# plotter.remove_scalar_bar()
|
||||
plotter.enable_anti_aliasing()
|
||||
|
||||
if just_return_plotter:
|
||||
return plotter
|
||||
|
||||
if screenshot: # pragma: no cover
|
||||
plotter.show(cpos=cpos, auto_close=False)
|
||||
plotter.screenshot(screenshot, True)
|
||||
cpos_final = plotter.camera_position
|
||||
plotter.close()
|
||||
return cpos_final
|
||||
else:
|
||||
return plotter.show(cpos=cpos, **kwargs)
|
||||
|
||||
|
||||
def logo_atomized(density=0.05, scale=0.6, depth=0.05):
|
||||
"""Generate a voxelized pyvista logo with intra-cell spacing.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
density : float, default: 0.05
|
||||
The spacing between voxels in the generated PyVista logo.
|
||||
scale : float, default: 0.6
|
||||
The scaling factor for the generated PyVista logo.
|
||||
depth : float, default: 0.05
|
||||
The depth of the generated PyVista logo.
|
||||
|
||||
Returns
|
||||
-------
|
||||
pyvista.UnstructuredGrid
|
||||
A merged UnstructuredGrid representing the voxelized PyVista logo.
|
||||
|
||||
"""
|
||||
mesh_letters = logo_letters(depth=depth)
|
||||
grids = []
|
||||
for letter in mesh_letters.values():
|
||||
grid = _voxelize_legacy(letter, density=density)
|
||||
grids.append(atomize(grid, scale=scale))
|
||||
|
||||
return grids[0].merge(grids[1:])
|
||||
Reference in New Issue
Block a user