visualdynamics.viz.geometry¶
geometry
¶
Building the PyVista scene for a geometry.
Coordinates are stored in SI and converted to the display unit system when the scene is built, so changing the unit system rebuilds the scene and leaves the data alone.
Line elements are drawn in direct colors, grouped by color index, except when the scene is colored by value.
Functions:
| Name | Description |
|---|---|
color_name |
The name of a color index ('gray', 'blue', ...), wrapping past 9. |
color_rgb |
The RGB triple (0 to 1) of a color index, wrapping past 9. |
axis_unit_text |
The unit text the labeled axes show, such as |
display_points |
The coordinates to draw for a geometry, and the axis unit text. |
element_cells |
How the elements are drawn: (faces, lines, points), each keyed by |
drawn_nodes |
A mask over the nodes of the ones a scene draws as points when |
geometry_scene |
Build a PyVista plotter showing the geometry, or add it to |
print_plotter |
An off-screen plotter for a figure |
annotate_scene |
Add or remove the scene's two annotations. |
shared_points |
A vtkPoints that every mesh can share, and a writable numpy view of it. |
dof_axis |
0, 1 or 2 for the axis of a DOF direction, or None if it has none. |
dof_arrow_vectors |
For each DOF, (node row, global direction, axis) for its arrow, or |
dof_arrow_length |
One length for every arrow on a plot: 12 % of |
add_dof_arrows |
Labeled arrows marking DOFs on the geometry. |
add_coordinate_system |
Draw one coordinate system: three arrows, with angular directions |
shared_scalars |
A numpy view of a new VTK point-data array, and the array itself. |
label_choices |
|
labels_fit |
Whether captioning this kind stays within |
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 it to the file |
plot_dofs |
The geometry with labeled arrows at every DOF that |
channel_dofs |
The DOFs of a channel table's channels in |
plot_channels |
The geometry with labeled arrows at a channel table's DOFs: the |
transformation_arrows |
A row of a transformation ( |
plot_transformation |
The geometry with one row of a transformation drawn on it as |
Classes¶
Functions:¶
color_name
¶
color_rgb
¶
axis_unit_text
¶
axis_unit_text(geometry: Geometry, unit_system: UnitSystem) -> str
The unit text the labeled axes show, such as '[mm]'. A
geometry whose units are undefined shows '[units undefined]'
instead of a unit.
Source code in src/visualdynamics/viz/geometry.py
display_points
¶
display_points(geometry: Geometry, unit_system: UnitSystem) -> tuple[ndarray, str]
The coordinates to draw for a geometry, and the axis unit text.
Coordinates are converted from SI to unit_system. A geometry whose
units are undefined is drawn with the file's raw coordinates, because
converting them would scale values whose unit is unknown, and its
axis text says the units are undefined.
Source code in src/visualdynamics/viz/geometry.py
element_cells
¶
element_cells(geometry: Geometry, indices: Sequence[int] | None = None, separate_skins: bool = False) -> tuple
How the elements are drawn: (faces, lines, points), each keyed by
element color, with every entry given as node rows (positions in
node_id), not node ids; with separate_skins, (faces, lines,
points, skins), the solids' skins kept apart from the face elements
so a scene can draw them see-through.
A face element is drawn as its corner nodes (face_corners), since
a quad8's midside nodes are not corners of the outline. A solid is
drawn as the outer surface of its color: each cell's faces
(solid_faces), less every face that two cells share. A line
element is its first two nodes, and a point element is its nodes.
The 3-D view, the report's scenes and the HTML export all use this
one function.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
geometry
|
Geometry
|
The geometry. |
required |
indices
|
sequence of int
|
Which elements, by row; every element when omitted. |
None
|
separate_skins
|
bool
|
Return the solids' skins as a fourth dict instead of among the faces. |
False
|
Returns:
| Type | Description |
|---|---|
tuple of dict
|
Faces and lines as lists of row lists, points as a row list, each by element color; and the skins, when asked for. |
Source code in src/visualdynamics/viz/geometry.py
drawn_nodes
¶
drawn_nodes(geometry: Geometry) -> ndarray
A mask over the nodes of the ones a scene draws as points when nothing more specific is asked for: the nodes no element uses, which nothing else would show, and the nodes of line and point elements, where a beam's end or a mass's place is read. A plate's or a solid's nodes sit at the corners of the faces drawn and are not drawn again; a brick model's are mostly inside it, and drawn they were more than half of a frame (PLAN.md "The skin see-through, the nodes that mean something"). A pick still draws the nodes picked, and the Nodes row draws them all.
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 a PyVista plotter showing the geometry, or add it to plotter.
theme is 'light', 'dark' or a colors dict, and sets the scene
background and the annotation color. components limits what is
drawn to any of 'nodes', 'elements' and 'coordinate_systems' (the
default is nodes and elements); selecting one of them in the project
tree shows only that part. labels names the kinds to caption with
their ids (add_geometry). node_size and line_width are in
pixels, and scale multiplies every size given in pixels (nodes,
lines, the bounds' labels) for a render at print resolution
(print_plotter). bounds and orientation turn on the labeled
box and the corner triad (annotate_scene); a print figure may want
neither. A new plotter is made off screen when off_screen is true.
Returns the plotter. Call .show() on it, or .screenshot()
when it is 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 to draw every pixel size in it at.
The window is the printed size in pixels, and the render window's
DPI is set so that a text actor's size in points prints in points.
The returned scale is how many print pixels one screen pixel
becomes (dpi / 96). Multiply the sizes VTK takes in pixels (nodes,
lines, the bounds' labels) by it, and the figure prints the way 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)
|
The plotter and the pixel scale. |
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
Add or remove the scene's two annotations.
bounds is the labeled box around the geometry, its titles carrying
axis_unit, and orientation is the small triad in the corner; the
3-D view's toolbar turns each on and off separately. Turned off, an
annotation already in the scene is removed. A scale other than one
means a print render (print_plotter): the box's labels, which are
sized in screen pixels, are set to print at the size of the scene's
other labels (PRINT_BOUNDS_SIZE).
Source code in src/visualdynamics/viz/geometry.py
shared_points
¶
A vtkPoints that every mesh can share, and a writable numpy view of it.
The points are a copy of points. Writing through the view and
calling Modified() on the vtkPoints moves every mesh at once, so
a frame is one upload rather than one per mesh.
Source code in src/visualdynamics/viz/geometry.py
dof_axis
¶
0, 1 or 2 for the axis of a DOF direction, or None if it has none.
A rotation counts as its axis: 'RZ-' is 2, and draws blue like 'Z+'.
Source code in src/visualdynamics/viz/geometry.py
dof_arrow_vectors
¶
dof_arrow_vectors(geometry: Geometry, dofs: Sequence[str]) -> list[tuple[int, ndarray, int] | None]
For each DOF, (node row, global direction, axis) for its arrow, or None for a DOF at a node the geometry lacks or with no axis.
The direction is turned by the node's displacement coordinate
system the same way the animation turns the motion
(deform.dof_directions), so '101X+' on a node measured in a turned
system points along that system's X. A rotational DOF points along
its axis, turned the same way. The axis, which picks the color, is
the DOF's own letter, not the nearest global axis.
Source code in src/visualdynamics/viz/geometry.py
dof_arrow_length
¶
One length for every arrow on a plot: 12 % of extent, reduced to
0.9 times the closest spacing of the arrowed points so that arrows
on closely spaced nodes do not overlap.
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 | Sequence[bool] = False, name: str | None = None, scales: Sequence[float] | None = None) -> int
Labeled arrows marking DOFs on the geometry.
One arrow per DOF, colored by its axis: X red, Y green, Z blue, the
same colors as the orientation triad. It points along that axis of
the node's displacement coordinate system (dof_arrow_vectors). The
arrows of one color are built into one mesh, so ten thousand arrows
are three actors. A response arrow starts at the node and points
outward, with its label at the tip; with incoming (forces) the
arrow ends on the node instead, with its label at the base;
incoming is one flag for every arrow or one per DOF. All
arrows have one length (dof_arrow_length), unless scales gives
each DOF's arrow its own: a share of that length, the arrow pointing
the other way when the share is negative, and no arrow for a zero or
NaN, so a row of a transformation reads as weights on its DOFs
(transformation_arrows). Labels are drawn only
when there are at most DOF_LABEL_LIMIT arrows. A DOF at a node the
geometry does not have, or with a direction that is not a
translation or rotation, is skipped. Given a name, the actors are
named from it, so drawing again replaces them.
Returns how many arrows were drawn.
Source code in src/visualdynamics/viz/geometry.py
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 | |
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
Draw one coordinate system: three arrows, with angular directions drawn as arcs.
matrix holds the three direction vectors in its first three rows,
and length is the arrow length. The arrows show the type even
without names: a cylindrical system has one arc and a spherical one
has two. When label (the system's id) is given, it is written at
the origin and each direction's name, from the type (X/Y/Z, R/theta/Z
or R/theta/phi), is written at the tip of its arrow in text_color.
Without a label, only the arrows are drawn.
Given a name, every actor is named from it, so drawing again
replaces the drawing instead of adding another on top. That is what
lets a frame be rotated live without rebuilding the rest of the
scene.
Source code in src/visualdynamics/viz/geometry.py
shared_scalars
¶
A numpy view of a new VTK point-data array, and the array itself.
The array holds count zeros and is named name. It does for color
what shared_points does for position: every mesh in the scene uses
the one array, so writing it once per frame recolors all of them.
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 form: {kind: the ids to caption, or None}.
Two forms are accepted. A script passes a list of kinds, such as
labels=['nodes'], meaning the nodes that are drawn. The window,
which knows what was picked, passes a dict, such as
labels={'groups': [3]}. None as a value means every entity of
that kind that is drawn. labels of None gives an empty dict.
Source code in src/visualdynamics/viz/geometry.py
labels_fit
¶
labels_fit(geometry: Geometry, kind: str, chosen: Sequence[int] | None = None) -> bool
Whether captioning this kind stays within ENTITY_LABEL_LIMIT.
Counts chosen when it is given, else every entity of the kind. The
window asks before it turns labels on, so a selection too large to
caption is reported in the status bar instead of silently drawing no
labels.
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.
kind is 'nodes', 'elements' or 'groups'; any other kind gets no
captions (a coordinate system's triad writes its own id). points
is the geometry's nodes as drawn, so a caption is in the same units
and frame as what it names. A node is captioned at the node. An
element is captioned at the mean of its nodes, and an element group
at the mean of its elements' nodes, so the number stays off the
vertices, which carry the node ids when both are shown. A group is
captioned with its name when it has one, else its id.
chosen is the ids (nodes, element groups) or the indices
(elements) to caption; None captions every one of the kind. Nothing
is returned 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 draws the whole geometry in one color, which is how
several geometries overlaid in one scene are told apart. entities
limits the 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 is highlighted.
components limits it to whole kinds instead (geometry_scene).
labels names the kinds to caption with their ids, any of 'nodes',
'coordinate_systems', 'elements' and 'groups' (label_choices).
Captions follow entities when it limits the drawing, so labeling a
picked element names that element only, and a kind with more than
ENTITY_LABEL_LIMIT entities is not captioned (labels_fit).
Captions are drawn in text_color.
points_source is a shared vtkPoints (shared_points) for the
meshes to use instead of a new one, and each mesh made is appended to
meshes when a list is given; the animator uses both to move the
scene. scalars is a VTK point-data array (shared_scalars) shared
by every mesh, coloring the geometry by value instead of by its color
indices, and clim fixes the values at the two ends of the color
map. node_size and line_width are in pixels.
Returns the axis unit text.
Source code in src/visualdynamics/viz/geometry.py
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 | |
place_view
¶
Turn the camera to view (a geometry's View, or the default
isometric view when None) and fit everything the plotter holds.
Every 3-D view of a geometry is opened through this function: 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. render renders after the camera moves.
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 it to the file
screenshot with no window.
Shown, it opens in the app's own 3-D pane, with the labeled axes and
the orientation triad as toggles on the bar above it, as in the
window. Returns the pane (its .plotter is the PyVista one), or the
image array when rendering to a file. For print, dpi renders the
file at its printed size (print_plotter), size_in inches (6 by
4.5 by default), with every label and line at the size the screen
shows it; size_in is used only with dpi. The camera opens on the
geometry's own view. Other keyword arguments go to
geometry_scene.
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 that source
measures as quantity: the app's DOF-arrows toggle, from a script.
Force arrows end on their node with the label at the base, and
response arrows start at it with the label at the tip, as the app
draws them (add_dof_arrows). source is a data object, or a list
or tuple of them. Shown or rendered to screenshot as
plot_geometry does, including size_in and dpi for print; other
keyword arguments go to geometry_scene.
Source code in src/visualdynamics/viz/geometry.py
channel_dofs
¶
The DOFs of a channel table's channels in role, each with
whether its arrow points in.
role is one of CHANNEL_ROLES: 'control' is the channels with
Control checked, whatever their role. A channel measuring an excitation
(a force or a drive voltage) points in, as a force record's arrows
do. Channels are kept even when they cannot be drawn yet (no node,
no direction, or a node the geometry lacks), so the count of what
was asked for is still known; add_dof_arrows skips them.
Source code in src/visualdynamics/viz/geometry.py
plot_channels
¶
plot_channels(geometry: Geometry, table: Any, role: str = 'all', 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, sensors: bool = False, sensor_size: float = 1.0, **kwargs: Any) -> Any
The geometry with labeled arrows at a channel table's DOFs: the app's view of a channel table selected with a geometry, from a script.
role limits the arrows to the references, responses or monitors
(channel_dofs). With sensors, the bodies of the sensors the
table places are drawn at their nodes too (viz.sensors),
sensor_size times true size. Shown or rendered to screenshot as
plot_dofs is; other keyword arguments go to geometry_scene.
Source code in src/visualdynamics/viz/geometry.py
transformation_arrows
¶
A row of a transformation (core.transform.matrix_at, rows the
modes and columns the DOFs) as arrows: its DOFs, each with its value
as a share of the row's largest, so that value is a full-length
arrow and a negative one points the other way (add_dof_arrows's
scales). A row is scaled on its own, so a rotation's row, whose
values are lever arms, reads as well as a translation's. A DOF the
set lacks has a NaN and no arrow.
Source code in src/visualdynamics/viz/geometry.py
plot_transformation
¶
plot_transformation(geometry: Geometry, view: Any, row: int = 0, 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 one row of a transformation drawn on it as
arrows (transformation_arrows): the app's Shape Values view with
a transformation picked, from a script. Shown or rendered to
screenshot as plot_dofs is; other keyword arguments go to
geometry_scene.