from types import SimpleNamespace
from typing import TypedDict
import matplotlib.pyplot as plt
import numpy as np
import plotly.graph_objs as go
from matplotlib.colors import to_hex
from typing_extensions import Unpack
from ...utils import OPS_ELE_TYPES
default_cmap = [
[0.0, "rgb(165,0,38)"],
[0.1111111111111111, "rgb(215,48,39)"],
[0.2222222222222222, "rgb(244,109,67)"],
[0.3333333333333333, "rgb(253,174,97)"],
[0.4444444444444444, "rgb(254,224,144)"],
[0.5555555555555556, "rgb(224,243,248)"],
[0.6666666666666666, "rgb(171,217,233)"],
[0.7777777777777778, "rgb(116,173,209)"],
[0.8888888888888888, "rgb(69,117,180)"],
[1.0, "rgb(49,54,149)"],
]
default_cmap = [[1.0 - x[0], x[1]] for x in default_cmap[::-1]]
class _PLOT_ARGS_TYPES1(TypedDict, total=False):
point_size: float
line_width: float
theme: str
scale_factor: float
show_mesh_edges: bool
mesh_edge_color: str
mesh_edge_width: float
mesh_opacity: float
font_size: int
title_font_size: int
font_family: str
window_size: tuple[int | None, int | None]
cmap: list | None | str # or str for named colorscale, default is default_cmap
cmap_model: list | None | str # or str for named colorscale, default is None
class _PLOT_ARGS_TYPES2(TypedDict, total=False):
point: str
frame: str
beam: str
truss: str
link: str
shell: str
plane: str
brick: str
tet: str
joint: str
contact: str
pfem: str
constraint: str
bc: str
cmap: list | None | str # or str for named colorscale, default is default_cmap
cmap_model: list | None | str # or str for named colorscale, default is None
PLOT_ARGS_DEFAULT = {
"point_size": 3.0,
"line_width": 5.0,
"theme": "plotly",
"scale_factor": 1 / 15,
"show_mesh_edges": True,
"mesh_edge_color": "black",
"mesh_edge_width": 1.0,
"mesh_opacity": 1.0,
"font_size": 15,
"title_font_size": 18,
"font_family": "Arial, sans-serif",
"window_size": (None, None),
# ------------------------------
"color_point": "#580f41",
"color_frame": "#0652ff",
"color_beam": "#0652ff",
"color_truss": "#FF8C00",
"color_link": "#39FF14",
"color_shell": "#76b852",
"color_plane": "#00FFFF",
"color_brick": "#FF4500",
"color_tet": "#FFFF33",
"color_joint": "#7FFF00",
"color_contact": "#ff9408",
"color_pfem": "#8080FF",
"color_constraint": "#FF1493",
"color_bc": "#15b01a",
"cmap": default_cmap, # "plasma",
"cmap_model": None,
}
PLOT_ARGS = SimpleNamespace()
for key, value in PLOT_ARGS_DEFAULT.items():
setattr(PLOT_ARGS, key, value)
def reset_plot_props():
"""
Reset ploting properties to default values.
Returns
-------
None
"""
for key, value in PLOT_ARGS_DEFAULT.items():
setattr(PLOT_ARGS, key, value)
[docs]
def set_plot_props(**kwargs: Unpack[_PLOT_ARGS_TYPES1]):
"""
Set ploting properties.
Parameters
----------
kwargs: optional keyword arguments, including:
* point_size : float, optional
Point size of any nodes. Default ``5.0``
* line_width : float, optional
Thickness of line elements. Only valid for wireframe and surface
representations. Default ``3.0``.
* cmap : str, list, optional, default: None
One of the following named colorscales: ["aggrnyl", "agsunset", "algae", "amp", "armyrose",
"balance", "blackbody", "bluered", "blues", "blugrn", "bluyl", "brbg", "brwnyl", "bugn",
"bupu", "burg", "burgyl", "cividis", "curl", "darkmint", "deep", "delta", "dense",
"earth", "edge", "electric", "emrld", "fall", "geyser", "gnbu", "gray", "greens", "greys",
"haline", "hot", "hsv", "ice", "icefire", "inferno", "jet", "magenta", "magma", "matter",
"mint", "mrybm", "mygbm", "oranges", "orrd", "oryel", "oxy", "peach", "phase", "picnic",
"pinkyl", "piyg", "plasma", "plotly3", "portland", "prgn", "pubu", "pubugn", "puor", "purd",
"purp", "purples", "purpor", "rainbow", "rdbu", "rdgy", "rdpu", "rdylbu", "rdylgn", "redor",
"reds", "solar", "spectral", "speed", "sunset", "sunsetdark", "teal", "tealgrn", "tealrose", "tempo",
"temps", "thermal", "tropic", "turbid", "turbo", "twilight",
"viridis", "ylgn", "ylgnbu", "ylorbr", "ylorrd"].
Appending "_r" to a named colorscale reverses it.
* cmap_model : str, list, optional, default=None
Matplotlib colormap used for geometry model visualization.
Same as ``cmap``, except that this parameter will be used
for geometry model visualization and will be automatically mapped
according to different element types.
If None, If None, the color specified in the function``set_plot_colors``
will be used.
Available color maps are shown in
`Colormaps in Matplotlib <https://matplotlib.org/stable/users/explain/colors/colormaps.html>`_
* theme : str, optional, default: "plotly"
Available theme templates for plotly:
['ggplot2', 'seaborn', 'simple_white', 'plotly', 'plotly_white',
'plotly_dark', 'presentation', 'xgridoff', 'ygridoff', 'gridon', 'none']
* window_size : list, optional
Window size in pixels. Default to ``(None, None)``
* show_mesh_edges: bool, default: True
Whether to display the mesh edges of ``planes``, ``plates``, ``shells``, and ``solid`` elements.
* mesh_edge_color: str, default: black
Color of the mesh edges for ``planes``, ``plates``, ``shells``, and ``solid`` elements.
* mesh_edge_width: float, default: 1.0
Width of the mesh edges for ``planes``, ``plates``, ``shells``, and ``solid`` elements.
* mesh_opacity: float, default: 1.0
Display opacity for ``planes``, ``plates``, ``shells``, and ``solid`` elements.
* font_family : str, optional, default: "Arial, sans-serif"
HTML font family - the typeface that will be applied by the web browser.
The web browser will only be able to apply a font if it is available on the system which it operates.
Provide multiple font families, separated by commas, to indicate the preference in which to apply fonts
if they aren"t available on the system.
The Chart Studio Cloud (at https://chart-studio.plotly.com or on-premise) generates images on a server,
where only a select number of fonts are installed and supported.
These include “Arial”, “Balto”, “Courier New”, “Droid Sans”, “Droid Serif”, “Droid Sans Mono”, “Gravitas One”,
“Old Standard TT”, “Open Sans”, “Overpass”, “PT Sans Narrow”, “Raleway”, “Times New Roman”.
* scale_factor : float, optional
Scale factor between the maximum deformation of the model and the maximum boundary size.
Default ``1 / 20``.
* font_size: int, default: 15
Font size of labels.
* title_font_size: int, default: 18
Font size of title.
Returns
-------
None
"""
for key, value in kwargs.items():
setattr(PLOT_ARGS, key, value)
[docs]
def set_plot_colors(**kwargs: Unpack[_PLOT_ARGS_TYPES2]):
"""
Set the display color of various element types.
Parameters
----------
kwargs : optional keyword arguments, including:
* point : str, list[int, int, int], optional
Color for nodal points.
Either a string, RGB list, or hex color string. For example,
``point='white'``, ``point='w'``, ``point=[1, 1, 1]``, or
``point='#FFFFFF'``.
frame : str, list[int, int, int], optional
Color for frame elements.
* frame : str, list[int, int, int], optional
Color for frame elements.
* truss : str, list[int, int, int], optional
Color for truss elements.
* link : str, list[int, int, int], optional
Color for link elements.
* shell : str, list[int, int, int], optional
Color for shell elements.
* plane : str, list[int, int, int], optional
Color for plane elements.
* brick : str, list[int, int, int], optional
Color for brick (solid) elements.
* tet : str, list[int, int, int], optional
Color for tetrahedral (solid) elements.
* joint : str, list[int, int, int], optional
Color for beam-column joint elements.
* contact : str, list[int, int, int], optional
Color for contact elements.
* pfem : str, list[int, int, int], optional
Color for PFEM elements.
* constraint : str, list[int, int, int], optional
Color for constraint.
* bc : str, list[int, int, int], optional
Color for boundary conditions.
* cmap : str, list, optional, default: "plasma"
One of the following named colorscales: ["aggrnyl", "agsunset", "algae", "amp", "armyrose",
"balance", "blackbody", "bluered", "blues", "blugrn", "bluyl", "brbg", "brwnyl", "bugn",
"bupu", "burg", "burgyl", "cividis", "curl", "darkmint", "deep", "delta", "dense",
"earth", "edge", "electric", "emrld", "fall", "geyser", "gnbu", "gray", "greens", "greys",
"haline", "hot", "hsv", "ice", "icefire", "inferno", "jet", "magenta", "magma", "matter",
"mint", "mrybm", "mygbm", "oranges", "orrd", "oryel", "oxy", "peach", "phase", "picnic",
"pinkyl", "piyg", "plasma", "plotly3", "portland", "prgn", "pubu", "pubugn", "puor", "purd",
"purp", "purples", "purpor", "rainbow", "rdbu", "rdgy", "rdpu", "rdylbu", "rdylgn", "redor",
"reds", "solar", "spectral", "speed", "sunset", "sunsetdark", "teal", "tealgrn", "tealrose", "tempo",
"temps", "thermal", "tropic", "turbid", "turbo", "twilight",
"viridis", "ylgn", "ylgnbu", "ylorbr", "ylorrd"].
Appending "_r" to a named colorscale reverses it.
* cmap_model : str, list, optional, default=None
Matplotlib colormap used for geometry model visualization.
Same as ``cmap``, except that this parameter will be used
for geometry model visualization and will be automatically mapped
according to different element types.
If None, If None, the color specified in the function``set_plot_colors``
will be used.
Available color maps are shown in
`Colormaps in Matplotlib <https://matplotlib.org/stable/users/explain/colors/colormaps.html>`_
Returns
-------
None
"""
for key, value in kwargs.items():
if key in ["cmap", "cmap_model"]:
setattr(PLOT_ARGS, key, value)
else:
setattr(PLOT_ARGS, "color_" + key, value)
if "frame" in kwargs:
PLOT_ARGS.color_beam = kwargs["frame"]
def _get_ele_color(ele_types: list[str]):
if PLOT_ARGS.cmap_model:
cmap = plt.get_cmap(PLOT_ARGS.cmap_model)
colors = cmap(np.linspace(0, 1, len(ele_types)))
colors = [to_hex(color) for color in colors]
else:
colors = ["#01153e"] * len(ele_types)
for i, ele_type in enumerate(ele_types):
if ele_type in OPS_ELE_TYPES.Beam:
colors[i] = PLOT_ARGS.color_frame
elif ele_type in OPS_ELE_TYPES.Truss:
colors[i] = PLOT_ARGS.color_truss
elif ele_type in OPS_ELE_TYPES.Link:
colors[i] = PLOT_ARGS.color_link
elif ele_type in OPS_ELE_TYPES.Plane:
colors[i] = PLOT_ARGS.color_plane
elif ele_type in OPS_ELE_TYPES.Shell:
colors[i] = PLOT_ARGS.color_shell
elif ele_type in OPS_ELE_TYPES.Tet:
colors[i] = PLOT_ARGS.color_tet
elif ele_type in OPS_ELE_TYPES.Brick:
colors[i] = PLOT_ARGS.color_brick
elif ele_type in OPS_ELE_TYPES.PFEM:
colors[i] = PLOT_ARGS.color_pfem
elif ele_type in OPS_ELE_TYPES.Joint:
colors[i] = PLOT_ARGS.color_joint
elif ele_type in OPS_ELE_TYPES.Contact:
colors[i] = PLOT_ARGS.color_contact
return colors
# -------------------------------------------------------------------------
# ---------------------------- Plotting Functions -------------------------
# -------------------------------------------------------------------------
class _VTKElementTriangulator:
# https://www.weiy.city/2019/10/check-cells-in-model/
# https://examples.vtk.org/site/Cxx/GeometricObjects/IsoparametricCellsDemo/
def __init__(self, points, scalars=None, scalars_by_element=False):
self.points = points
self.face_points = []
self.face_line_points = []
self.face_mid_points = []
self.veci = []
self.vecj = []
self.veck = []
self.scalars = scalars
self.face_scalars = []
self.face_line_scalars = []
self.by_ele = scalars_by_element
self.scalars_idx_by_ele = 0
def add_cell(self, cell_type, cell):
data = self.points[cell[1:], :]
self.face_mid_points.append(np.mean(data, axis=0))
self.face_points.extend(data)
if self.scalars is not None:
if self.by_ele:
idx = self.scalars_idx_by_ele
self.face_scalars.extend([self.scalars[idx]] * len(data))
self.scalars_idx_by_ele += 1
else:
self.face_scalars.extend(self.scalars[cell[1:]])
self._add_vectors(cell_type, len(self.face_points) - len(data))
def _add_vectors(self, cell_type, base_idx):
if cell_type == 5: # VTK_TRIANGLE
self._add_triangle(base_idx)
elif cell_type == 22: # QUADRATIC_TRIANGLE
self._add_quadratic_triangle(base_idx)
elif cell_type == 34: # BIQUADRATIC_TRIANGLE
self._add_biquadratic_triangle(base_idx)
elif cell_type == 9: # VTK_QUAD
self._add_quad(base_idx)
elif cell_type == 23: # QUADRATIC_QUAD
self._add_quadratic_quad(base_idx)
elif cell_type == 28: # BIQUADRATIC_QUAD
self._add_biquadratic_quad(base_idx)
elif cell_type == 10: # VTK_TETRA
self._add_tetra(base_idx)
elif cell_type == 24: # QUADRATIC_TETRA
self._add_quadratic_tetra(base_idx)
elif cell_type == 12: # VTK_HEXAHEDRON
self._add_hexahedron(base_idx)
elif cell_type == 25: # QUADRATIC_HEXAHEDRON
self._add_quadratic_hexahedron(base_idx)
elif cell_type == 29: # TRIQUADRATIC_HEXAHEDRON
self._add_triquadratic_hexahedron(base_idx)
def _add_triangle(self, idx):
self._add_vectors_from_tuples(idx, [(0, 1, 2)])
self._add_line_points(idx, [(0, 1, 2, 0)])
def _add_quadratic_triangle(self, idx):
connections = [(0, 3, 5), (1, 4, 3), (2, 5, 4), (3, 4, 5)]
self._add_vectors_from_tuples(idx, connections)
self._add_line_points(idx, [(0, 3, 1, 4, 2, 5, 0)])
def _add_biquadratic_triangle(self, idx):
connections = [(0, 3, 6), (3, 4, 6), (3, 1, 4), (0, 6, 5), (4, 5, 6), (2, 5, 4)]
self._add_vectors_from_tuples(idx, connections)
self._add_line_points(idx, [(0, 3, 1, 4, 2, 5, 0)])
def _add_quad(self, idx):
connections = [(0, 1, 2), (0, 2, 3)]
self._add_vectors_from_tuples(idx, connections)
self._add_line_points(idx, [(0, 1, 2, 3, 0)])
def _add_quadratic_quad(self, idx):
connections = [(0, 4, 7), (1, 5, 4), (2, 6, 5), (3, 7, 6), (4, 6, 7), (4, 5, 6)]
self._add_vectors_from_tuples(idx, connections)
self._add_line_points(idx, [(0, 4, 1, 5, 2, 6, 3, 7, 0)])
def _add_biquadratic_quad(self, idx):
connections = [
(0, 4, 7),
(1, 5, 4),
(2, 6, 5),
(3, 7, 6),
(6, 7, 8),
(5, 6, 8),
(7, 4, 8),
(4, 5, 8),
]
self._add_vectors_from_tuples(idx, connections)
self._add_line_points(idx, [(0, 4, 1, 5, 2, 6, 3, 7, 0)])
def _add_tetra(self, idx):
connections = [(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)]
self._add_vectors_from_tuples(idx, connections)
self._add_line_points(idx, [(0, 1, 2, 0), (0, 1, 3, 0), (0, 2, 3, 0), (1, 2, 3, 1)])
def _add_quadratic_tetra(self, idx):
connections = [
(0, 4, 7),
(1, 8, 4),
(3, 7, 8),
(4, 8, 7),
(1, 8, 5),
(3, 9, 8),
(2, 5, 9),
(5, 8, 9),
(0, 7, 6),
(2, 6, 9),
(3, 9, 7),
(6, 7, 9),
(0, 4, 6),
(1, 5, 4),
(2, 6, 5),
(4, 5, 6),
]
self._add_vectors_from_tuples(idx, connections)
self._add_line_points(
idx,
[
(0, 4, 1, 5, 2, 6, 0),
(0, 4, 1, 8, 3, 7, 0),
(0, 7, 3, 9, 2, 6, 0),
(1, 8, 3, 9, 2, 5, 1),
],
)
def _add_hexahedron(self, idx):
connections = [
(0, 1, 2),
(0, 2, 3),
(0, 3, 7),
(0, 7, 4),
(0, 1, 5),
(0, 5, 4),
(1, 2, 6),
(1, 6, 5),
(2, 6, 3),
(3, 6, 7),
(4, 5, 6),
(4, 6, 7),
]
self._add_vectors_from_tuples(idx, connections)
self._add_line_points(
idx,
[
(0, 1, 2, 3, 0),
(0, 1, 5, 4, 0),
(0, 3, 7, 4, 0),
(1, 2, 6, 5, 1),
(2, 3, 7, 6, 2),
(4, 5, 6, 7, 4),
],
)
def _add_quadratic_hexahedron(self, idx):
connections = [
(0, 8, 11),
(1, 9, 8),
(2, 10, 9),
(3, 11, 10),
(9, 10, 11),
(8, 9, 11),
(0, 16, 8),
(4, 12, 16),
(5, 17, 12),
(1, 8, 17),
(8, 12, 17),
(8, 16, 12),
(0, 16, 11),
(4, 15, 16),
(7, 19, 15),
(3, 11, 19),
(11, 19, 16),
(15, 19, 16),
(4, 12, 15),
(5, 13, 12),
(6, 14, 13),
(7, 15, 14),
(12, 14, 15),
(12, 13, 14),
(3, 19, 10),
(7, 14, 19),
(6, 18, 14),
(2, 10, 18),
(10, 19, 18),
(14, 18, 19),
(1, 17, 9),
(5, 13, 17),
(6, 18, 13),
(2, 9, 18),
(9, 13, 18),
(9, 17, 13),
]
self._add_vectors_from_tuples(idx, connections)
self._add_line_points(
idx,
[
(0, 8, 1, 9, 2, 10, 3, 11, 0),
(0, 16, 4, 12, 5, 17, 1, 8, 0),
(0, 16, 4, 15, 7, 19, 3, 11, 0),
(4, 12, 5, 13, 6, 14, 7, 15, 4),
(3, 19, 7, 14, 6, 18, 2, 10, 3),
(1, 17, 5, 13, 6, 18, 2, 9, 1),
],
)
def _add_triquadratic_hexahedron(self, idx):
connections = [
# Bottom face (nodes: 0, 1, 2, 3, 8, 9, 10, 11, 24)
(0, 8, 24),
(8, 1, 24),
(1, 9, 24),
(9, 2, 24),
(2, 10, 24),
(10, 3, 24),
(3, 11, 24),
(11, 0, 24),
# Top face (nodes: 4, 5, 6, 7, 12, 13, 14, 15, 25)
(4, 12, 25),
(12, 5, 25),
(5, 13, 25),
(13, 6, 25),
(6, 14, 25),
(14, 7, 25),
(7, 15, 25),
(15, 4, 25),
# Front face (nodes: 0, 1, 5, 4, 8, 16, 12, 17, 26)
(0, 8, 26),
(8, 1, 26),
(1, 16, 26),
(16, 5, 26),
(5, 12, 26),
(12, 4, 26),
(4, 17, 26),
(17, 0, 26),
# Right face (nodes: 1, 2, 6, 5, 9, 18, 13, 16, 26)
(1, 9, 26),
(9, 2, 26),
(2, 18, 26),
(18, 6, 26),
(6, 13, 26),
(13, 5, 26),
(5, 16, 26),
(16, 1, 26),
# Back face (nodes: 2, 3, 7, 6, 10, 19, 14, 18, 26)
(2, 10, 26),
(10, 3, 26),
(3, 19, 26),
(19, 7, 26),
(7, 14, 26),
(14, 6, 26),
(6, 18, 26),
(18, 2, 26),
# Left face (nodes: 3, 0, 4, 7, 11, 17, 15, 19, 26)
(3, 11, 26),
(11, 0, 26),
(0, 17, 26),
(17, 4, 26),
(4, 15, 26),
(15, 7, 26),
(7, 19, 26),
(19, 3, 26),
]
self._add_vectors_from_tuples(idx, connections)
self._add_line_points(
idx,
[
(0, 8, 1, 9, 2, 10, 3, 11, 0),
(0, 16, 4, 12, 5, 17, 1, 8, 0),
(0, 16, 4, 15, 7, 19, 3, 11, 0),
(4, 12, 5, 13, 6, 14, 7, 15, 4),
(3, 19, 7, 14, 6, 18, 2, 10, 3),
(1, 17, 5, 13, 6, 18, 2, 9, 1),
],
)
def _add_vectors_from_tuples(self, idx, connections):
for i, j, k in connections:
self.veci.append(idx + i)
self.vecj.append(idx + j)
self.veck.append(idx + k)
def _add_line_points(self, idx, connections):
for cell in np.array(connections):
data0 = [self.face_points[idx + cell_] for cell_ in cell]
data1 = [[np.nan, np.nan, np.nan]]
self.face_line_points.extend(data0 + data1)
if self.scalars is not None:
data0 = [self.face_scalars[idx + cell_] for cell_ in cell]
data1 = [np.nan]
self.face_line_scalars.extend(data0 + data1)
def _get_results(self):
if self.scalars is None:
return (
self.face_points,
self.face_line_points,
self.face_mid_points,
self.veci,
self.vecj,
self.veck,
)
else:
return (
self.face_points,
self.face_line_points,
self.face_mid_points,
self.veci,
self.vecj,
self.veck,
self.face_scalars,
self.face_line_scalars,
)
def get_results(self):
output = self._get_results()
output = [np.array(data) for data in output]
return output
# Usage
# grid = VTKUnstructuredGrid(points)
# for cell_type, cell in zip(cell_types, cells):
# grid.add_cell(cell_type, cell)
# face_points, face_line_points, face_mid_points, veci, vecj, veck = grid.get_results()
def _make_lines_plotly(points, cells, scalars=None):
line_points = []
line_mid_points = []
line_scalars = []
for cell in cells:
data0 = points[cell[1:], :]
data1 = [np.nan, np.nan, np.nan]
data = np.vstack([data0, data1])
line_points.extend(data)
line_mid_points.append(np.mean(data0, axis=0))
if scalars is not None:
line_scalars.extend(scalars[cell[1:]])
line_scalars.append(np.nan)
line_points = np.array(line_points)
line_mid_points = np.array(line_mid_points)
line_scalars = np.array(line_scalars)
if scalars is None:
return line_points, line_mid_points
else:
return line_points, line_mid_points, line_scalars
def _plot_points(
plotter: list,
pos,
color: str = "black",
size: float = 3.0,
symbol: str = "circle",
name="Node",
customdata=None,
hovertemplate=None,
):
if len(pos) > 0 and size > 0:
x, y, z = [pos[:, j] for j in range(3)]
point_plot = go.Scatter3d(
x=x,
y=y,
z=z,
marker={"size": size, "color": color, "symbol": symbol},
mode="markers",
name=name,
customdata=customdata,
hovertemplate=hovertemplate,
# hovertemplate="<b>x: %{x}</b><br>y: %{y}<br>z: %{z} <br>tag: %{customdata}",
)
plotter.append(point_plot)
return point_plot
else:
return None
def _plot_points_cmap(
plotter: list,
pos,
scalars,
clim=None,
coloraxis=None,
size: float = 3.0,
name="",
show_hover: bool = True,
color=None,
):
if len(pos) > 0 and size > 0:
if clim is None:
clim = [np.min(scalars), np.max(scalars)]
if show_hover:
hover_kargs = {"customdata": scalars, "hovertemplate": "<b>%{customdata:.4E}</b>"}
else:
hover_kargs = {"hoverinfo": "skip"}
if color is None:
marker = {"size": size, "color": scalars, "coloraxis": coloraxis, "cmin": clim[0], "cmax": clim[1]}
else:
marker = {"size": size, "color": color}
point_plot = go.Scatter3d(
x=pos[:, 0],
y=pos[:, 1],
z=pos[:, 2],
marker=marker,
mode="markers",
name=name,
**hover_kargs,
)
plotter.append(point_plot)
return point_plot
else:
return None
def _plot_lines(
plotter: list,
pos,
width=1.0,
color="blue",
name="Line",
customdata=None,
hovertemplate=None,
hoverinfo=None,
):
if len(pos) > 0:
x, y, z = [pos[:, j] for j in range(3)]
line_plot = go.Scatter3d(
x=x,
y=y,
z=z,
line={"color": color, "width": width},
mode="lines",
name=name,
customdata=customdata,
hovertemplate=hovertemplate,
connectgaps=False,
hoverinfo=hoverinfo,
# hoverinfo="skip",
)
plotter.append(line_plot)
return line_plot
else:
return None
def _plot_lines_cmap(plotter: list, pos, scalars, coloraxis=None, width=1.0, clim=None, color=None):
if len(pos) > 0:
if clim is None:
clim = [scalars.min(), scalars.max()]
if color is None:
line_dict = {
"color": scalars,
"width": width,
"cmin": clim[0],
"cmax": clim[1],
"coloraxis": coloraxis,
}
else:
line_dict = {"color": color, "width": width}
line_plot = go.Scatter3d(
x=pos[:, 0],
y=pos[:, 1],
z=pos[:, 2],
line=line_dict,
mode="lines",
connectgaps=False,
hoverinfo="skip",
)
plotter.append(line_plot)
return line_plot
else:
return None
def _plot_unstru(
plotter: list,
pos,
veci,
vecj,
veck,
color="gray",
name=None,
customdata=None,
hovertemplate=None,
hoverinfo=None,
opacity=1.0,
style="surface",
line_width: float = 2.0,
show_edges: bool = True,
edge_color: str = " black",
edge_width: float = 1.0,
edge_points: np.ndarray = None,
):
"""plot the unstructured grid."""
if style.lower() == "surface":
if len(pos) > 0:
x, y, z = [pos[:, j] for j in range(3)]
grid = go.Mesh3d(
x=x,
y=y,
z=z,
i=veci,
j=vecj,
k=veck,
name=name,
color=color,
opacity=opacity,
customdata=customdata,
hovertemplate=hovertemplate,
hoverinfo=hoverinfo,
# hoverinfo="skip",
)
plotter.append(grid)
if show_edges:
_plot_lines(
plotter,
pos=edge_points,
color=edge_color,
width=edge_width,
name="Edge",
hoverinfo="skip",
)
else:
_plot_lines(
plotter,
pos=edge_points,
color=color,
width=line_width,
name=name,
customdata=customdata,
hovertemplate=hovertemplate,
hoverinfo=hoverinfo,
)
def _plot_unstru_cmap(
plotter: list,
pos,
veci,
vecj,
veck,
scalars,
clim=None,
coloraxis=None,
opacity=1.0,
style="surface",
color=None,
line_width: float = 2.0,
show_edges: bool = True,
edge_color: str = "black",
edge_width: float = 1.0,
edge_scalars: np.ndarray = None,
edge_points: np.ndarray = None,
):
if clim is None:
clim = [scalars.min(), scalars.max()]
if style.lower() == "surface":
if len(pos) > 0:
if color is None:
kargs = {
"text": scalars,
"intensity": scalars,
"cmin": clim[0],
"cmax": clim[1],
"coloraxis": coloraxis,
}
else:
kargs = {"color": color}
grid = go.Mesh3d(
x=pos[:, 0],
y=pos[:, 1],
z=pos[:, 2],
i=veci,
j=vecj,
k=veck,
opacity=opacity,
hoverinfo="skip",
**kargs,
)
plotter.append(grid)
if show_edges:
_plot_lines(
plotter,
pos=edge_points,
color=edge_color,
width=edge_width,
name="Edge",
hoverinfo="skip",
)
else:
_plot_lines_cmap(
plotter,
pos=edge_points,
scalars=edge_scalars,
clim=clim,
coloraxis=coloraxis,
width=line_width,
color=color,
)
def _plot_all_mesh(
plotter: list,
line_points,
unstru_line_points,
color="gray",
width=1.5,
):
if len(line_points) > 0:
_plot_lines(
plotter,
pos=line_points,
color=color,
name="",
width=width,
hoverinfo="skip",
)
if len(unstru_line_points) > 0:
_plot_lines(
plotter,
pos=unstru_line_points,
color=color,
name="",
width=width,
hoverinfo="skip",
)
def _plot_all_mesh_cmap(
plotter: list,
points,
point_scalars,
line_points,
line_scalars,
unstru_points,
unstru_scalars,
unstru_veci,
unstru_vecj,
unstru_veck,
coloraxis=None,
clim=None,
point_size=0,
line_width=1.0,
opacity=1.0,
show_edges: bool = True,
edge_color: str = "black",
edge_width: float = 1.0,
edge_scalars: np.ndarray = None,
edge_points: np.ndarray = None,
):
if point_size > 1e-3:
_plot_points_cmap(
plotter,
pos=points,
scalars=point_scalars,
coloraxis=coloraxis,
size=point_size,
)
_plot_lines_cmap(
plotter,
pos=line_points,
scalars=line_scalars,
coloraxis=coloraxis,
clim=clim,
width=line_width,
)
_plot_unstru_cmap(
plotter,
pos=unstru_points,
veci=unstru_veci,
vecj=unstru_vecj,
veck=unstru_veck,
scalars=unstru_scalars,
clim=clim,
coloraxis=coloraxis,
opacity=opacity,
show_edges=show_edges,
edge_color=edge_color,
edge_width=edge_width,
edge_scalars=edge_scalars,
edge_points=edge_points,
)
return None
# def group_cells(cells):
# line_cells, line_cells_type = [], []
# unstru_cells, unstru_cells_type = [], []
# cells_vtk = cells.ELE_CELLS["VTK"]
# cells_type_vtk = cells.ELE_CELLS["VTKType"]
# for name in cells_vtk.keys():
# for cell_, cell_type_ in zip(cells_vtk[name], cells_type_vtk[name]):
# if cell_[0][0] == 2:
# line_cells.append(cell_)
# line_cells_type.append(cell_type_)
# else:
# unstru_cells.append(cell_)
# unstru_cells_type.append(cell_type_)
# return line_cells, line_cells_type, unstru_cells, unstru_cells_type