visualdynamics.viz.geometry¶
geometry
¶
PyVista scene construction for Geometry.
Coordinates are converted from stored SI to the display unit system at scene build time — switching unit systems rebuilds the scene, never the data.
Line elements are drawn with direct colors, grouped by color index, except when the scene is colored by value (see docs/colormap.md). An older note here warned that macOS VTK silently drops scalar-mapped line cells; that was measured against pyvista 0.48.4 / VTK 9.6.2 and does not reproduce — see the same doc for the numbers.
Functions:
| Name | Description |
|---|---|
axis_unit_text |
What the labeled axes say. A geometry whose units are undefined |
display_points |
(coordinates to draw, axis unit text) for a geometry. |
solid_faces |
The faces of a solid cell of this many corners, each as |
geometry_scene |
Build (or add to) a PyVista plotter showing the geometry. |
print_plotter |
An off-screen plotter for a figure |
annotate_scene |
Scene annotations, each independently switchable. |
shared_points |
A vtkPoints every mesh can share, plus a writable numpy view of it. |
dof_axis |
0/1/2 for a DOF direction's axis — 'RZ-' is a Z, so blue. |
dof_arrow_length |
One length for every arrow on a plot: 12% of the geometry's |
add_dof_arrows |
Labeled arrows marking DOFs on the geometry. |
add_coordinate_system |
One coordinate system: three directions, named, with angles curved. |
shared_scalars |
A VTK point-data array every mesh can share, and a numpy view of it. |
label_choices |
|
labels_fit |
Would captioning this kind stay under |
label_spots |
(positions, texts) captioning one kind of entity with its id. |
add_geometry |
Add one geometry's meshes to an existing plotter. |
place_view |
Turn the camera to |
plot_geometry |
Show the geometry interactively, or render to |
plot_dofs |
The geometry with labeled arrows at every DOF |
Classes¶
Functions:¶
axis_unit_text
¶
axis_unit_text(geometry: Geometry, unit_system: UnitSystem) -> str
What the labeled axes say. A geometry whose units are undefined says so rather than naming one.
Source code in src/visualdynamics/viz/geometry.py
display_points
¶
display_points(geometry: Geometry, unit_system: UnitSystem) -> tuple[ndarray, str]
(coordinates to draw, axis unit text) for a geometry.
A geometry whose units are undefined is drawn with the file's raw coordinates — converting them would silently scale unknown values — and its axes say so rather than naming a unit.
Source code in src/visualdynamics/viz/geometry.py
solid_faces
¶
The faces of a solid cell of this many corners, each as positions into the cell's node list; a higher-order cell draws by its corners, which come first.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
node_count
|
int
|
How many nodes the cell names. |
required |
Returns:
| Type | Description |
|---|---|
tuple of tuple of int
|
|
Source code in src/visualdynamics/viz/geometry.py
geometry_scene
¶
geometry_scene(geometry: Geometry, unit_system: UnitSystem | None = None, plotter: Any = None, node_size: float = 8.0, line_width: float = 2.0, show_edges: bool = True, opacity: float = 1.0, labels: Sequence[str] | None = None, off_screen: bool = False, theme: Any = None, components: Sequence[str] | None = None, scale: float = 1.0, bounds: bool = True, orientation: bool = True) -> Any
Build (or add to) a PyVista plotter showing the geometry.
theme is 'light', 'dark', or a colors dict; it sets the scene
background and annotation color. components limits what is drawn to a
subset of {'nodes', 'elements'} — selecting one in the
project tree shows just that part. scale multiplies every size
given in pixels — nodes, lines, the bounds' labels — for a render at
print resolution (print_plotter). bounds and orientation are
the labeled box and the corner triad (annotate_scene); a print
figure may want neither. Returns the plotter; call .show() on it (or
.screenshot() if off_screen).
Source code in src/visualdynamics/viz/geometry.py
print_plotter
¶
An off-screen plotter for a figure size_in inches at dpi, and
the scale every pixel size in it is to be drawn at.
A 3-D screenshot at print resolution came out with its labels at
about 2 pt, and screenshot(scale=) dropped the point labels and
swelled the axis triad (the band-average paper, 2026-09-26). Here the
window is the printed size in pixels, the render window's DPI makes
every text actor's points print as points, and the returned scale —
how many print pixels a screen pixel becomes — is what the sizes VTK
takes in pixels (nodes, lines, the bounds' labels) are multiplied
by, so the figure prints as the screen shows it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
size_in
|
(float, float)
|
Width and height of the printed figure, in inches. |
required |
dpi
|
float
|
Its resolution. |
required |
Returns:
| Type | Description |
|---|---|
(Plotter, float)
|
|
Source code in src/visualdynamics/viz/geometry.py
annotate_scene
¶
annotate_scene(plotter: Any, axis_unit: str, colors: Mapping[str, str], bounds: bool = True, orientation: bool = True, scale: float = 1.0) -> None
Scene annotations, each independently switchable.
bounds is the labeled box drawn around the geometry; orientation is
the small triad in the corner. The 3D view toolbar toggles them
separately. scale other than one is a print render
(print_plotter): the box's labels, sized in screen pixels, are set
to print at the size the scene's other labels print
(PRINT_BOUNDS_SIZE).
Source code in src/visualdynamics/viz/geometry.py
shared_points
¶
A vtkPoints every mesh can share, plus a writable numpy view of it.
Writing through the view and calling Modified() moves every mesh at once — the difference between one upload per frame and one per mesh.
Source code in src/visualdynamics/viz/geometry.py
dof_axis
¶
0/1/2 for a DOF direction's axis — 'RZ-' is a Z, so blue.
dof_arrow_length
¶
One length for every arrow on a plot: 12% of the geometry's extent, shrunk to the closest spacing of the arrowed nodes so a dense set of arrows never overlaps its neighbors.
Source code in src/visualdynamics/viz/geometry.py
add_dof_arrows
¶
add_dof_arrows(plotter: Any, geometry: Geometry, dofs: Sequence[str], unit_system: UnitSystem | None = None, incoming: bool = False, name: str | None = None) -> int
Labeled arrows marking DOFs on the geometry.
One arrow per DOF (built into one mesh per color, so ten thousand
cost what ten do), colored by the axis it points along — X red,
Y green, Z blue, the orientation marker's own convention. Response
style starts at the node and points outward, label at the tip;
incoming (forces) ends on the node instead, label at the base.
All arrows share one length: 12% of the geometry's extent, shrunk
to the closest node spacing so dense sets never overlap. DOFs at
nodes the geometry does not have are skipped. Returns how many
were drawn.
Source code in src/visualdynamics/viz/geometry.py
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 | |
add_coordinate_system
¶
add_coordinate_system(plotter: Any, origin: ArrayLike, matrix: ArrayLike, cs_type: int, length: float, text_color: str = '#000000', label: str | None = None, name: str | None = None) -> None
One coordinate system: three directions, named, with angles curved.
label (the system's id) is written at the origin. Direction names come
from the type — X/Y/Z, R/theta/Z, or R/theta/phi — and each is written
at the tip of its own arrow, so a cylindrical system is tellable from a
cartesian one at a glance rather than by consulting the table.
Given a name, every actor is named from it, so drawing again replaces
the drawing instead of piling another one on top — which is what lets a
frame be turned live without rebuilding the scene around it.
Source code in src/visualdynamics/viz/geometry.py
shared_scalars
¶
A VTK point-data array every mesh can share, and a numpy view of it.
The color twin of shared_points: one array, written once per frame,
recolors every mesh in the scene at once.
Source code in src/visualdynamics/viz/geometry.py
label_choices
¶
label_choices(labels: Sequence[str] | Mapping[str, Sequence[int] | None] | None) -> dict[str, Sequence[int] | None]
labels in one shape: {kind: the ids to caption, or None}.
Both spellings read naturally where they are used. A script says
labels=['nodes'] and means the nodes that are drawn; the window,
which knows exactly what the user picked, says
labels={'groups': [3]}. None means "whatever this kind draws",
which is the right answer for both.
Source code in src/visualdynamics/viz/geometry.py
labels_fit
¶
labels_fit(geometry: Geometry, kind: str, chosen: Sequence[int] | None = None) -> bool
Would captioning this kind stay under ENTITY_LABEL_LIMIT?
Asked by the window before it turns labels on, so a selection too large to caption says so in the status bar rather than drawing nothing and leaving the user to wonder.
Source code in src/visualdynamics/viz/geometry.py
label_spots
¶
label_spots(geometry: Geometry, points: ndarray, kind: str, chosen: Sequence[int] | None = None) -> tuple[ndarray, list[str]]
(positions, texts) captioning one kind of entity with its id.
points is the geometry's nodes as drawn, so a caption lands in the
same units and the same frame as the thing it names. Everything but
a node is captioned at the centroid of its own nodes: the middle
of an element's corners, of an element group's
elements. That is where a reader looks for the name of a shape, and
it keeps the number off the vertices, which are already carrying
node ids whenever both are shown.
chosen is the ids (nodes, coordinate systems, element groups) or indices
(elements) to caption; None captions every one of the
kind. Returns nothing past ENTITY_LABEL_LIMIT; see labels_fit.
Source code in src/visualdynamics/viz/geometry.py
add_geometry
¶
add_geometry(plotter: Any, geometry: Geometry, unit_system: UnitSystem | None = None, node_size: float = 8.0, line_width: float = 2.0, show_edges: bool = True, opacity: float = 1.0, labels: Sequence[str] | Mapping[str, Sequence[int] | None] | None = None, components: Sequence[str] | None = None, color_override: Any = None, text_color: str = '#000000', entities: Mapping[str, Sequence[int]] | None = None, points_source: Any = None, meshes: list[Any] | None = None, scalars: Any = None, clim: tuple[float, float] | None = None) -> str
Add one geometry's meshes to an existing plotter.
color_override paints the whole geometry one color, which is how
several geometries overlaid in one scene stay tellable apart.
entities restricts drawing to specific items, as a dict with any of
'nodes' (node ids), 'coordinate_systems' (ids)
and 'elements' (indices) — that is how a single node or element picked
in the tree gets highlighted.
labels names the kinds to caption with their ids — any of 'nodes',
'coordinate_systems', 'elements', 'groups'. Captions
follow entities when it restricts the drawing, so labeling a
picked element names that one and not all of them, and a kind with
more than ENTITY_LABEL_LIMIT of them is left uncaptioned (see
labels_fit).
scalars is a VTK point-data array shared by every mesh, coloring the
whole geometry by value instead of by the geometry's own color indices;
clim fixes what the ends of the color map mean. One array serves all
the meshes, so a frame writes it once. Returns the axis unit text.
Source code in src/visualdynamics/viz/geometry.py
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 | |
place_view
¶
Turn the camera to view — a geometry's View, or the default
isometric when None — and fit what the plotter holds.
The one way a 3-D view of a geometry is opened: the app when it first
shows one and on Reset View, the script windows, the animations and
every exported figure, so a geometry opens the same way wherever it
is drawn. The report's scenes open on the same view through
View.basis.
Source code in src/visualdynamics/viz/geometry.py
plot_geometry
¶
plot_geometry(geometry: Geometry, unit_system: UnitSystem | None = None, screenshot: str | None = None, theme: Any = None, show: bool = True, size_in: tuple[float, float] | None = None, dpi: float | None = None, **kwargs: Any) -> Any
Show the geometry interactively, or render to screenshot headlessly.
Shown, it comes up in the app's own 3-D pane — the labeled axes and
the orientation triad are toggles on the bar over it, exactly as in
the window. Returns the pane (its .plotter is the PyVista one), or
the image array when rendering to a file. For print, size_in and
dpi render the figure at its printed size (print_plotter), every
label and line at the size the screen shows it.
Source code in src/visualdynamics/viz/geometry.py
plot_dofs
¶
plot_dofs(geometry: Geometry, source: Any, quantity: str, unit_system: UnitSystem | None = None, screenshot: str | None = None, theme: Any = None, show: bool = True, size_in: tuple[float, float] | None = None, dpi: float | None = None, **kwargs: Any) -> Any
The geometry with labeled arrows at every DOF source measures
as quantity — the GUI's DOF-arrows toggle, from a script.
Forces end on their node with the label at the base, responses
leave it with the label at the tip, exactly as the desktop draws
them. source is a data object (or several). For print, size_in
and dpi render at the printed size, as plot_geometry does.