vedo.dolfin
Submodule for support of the FEniCS/Dolfin library.
Example:
import dolfin from vedo import dataurl, download from vedo.dolfin import plot fname = download(dataurl+"dolfin_fine.xml") mesh = dolfin.Mesh(fname) plot(mesh)
Find many more examples in directory vedo/examples/dolfin.
1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3import numpy as np 4 5import vedo.vtkclasses as vtki 6 7import vedo 8from vedo.colors import printc 9from vedo import utils 10from vedo import shapes 11from vedo.mesh import Mesh 12from vedo.plotter import show 13 14__docformat__ = "google" 15 16__doc__ = """ 17Submodule for support of the [FEniCS/Dolfin](https://fenicsproject.org) library. 18 19Example: 20 ```python 21 import dolfin 22 from vedo import dataurl, download 23 from vedo.dolfin import plot 24 fname = download(dataurl+"dolfin_fine.xml") 25 mesh = dolfin.Mesh(fname) 26 plot(mesh) 27 ``` 28 29![](https://user-images.githubusercontent.com/32848391/53026243-d2d31900-3462-11e9-9dde-518218c241b6.jpg) 30 31.. note:: 32 Find many more examples in directory 33 [vedo/examples/dolfin](https://github.com/marcomusy/vedo/blob/master/examples/other/dolfin). 34""" 35 36__all__ = ["plot"] 37 38 39########################################################################## 40def _inputsort(obj): 41 42 import dolfin 43 44 u = None 45 mesh = None 46 if not utils.is_sequence(obj): 47 obj = [obj] 48 49 for ob in obj: 50 inputtype = str(type(ob)) 51 52 # printc('inputtype is', inputtype, c=2) 53 54 if "vedo" in inputtype: # skip vtk objects, will be added later 55 continue 56 57 if "dolfin" in inputtype or "ufl" in inputtype: 58 if "MeshFunction" in inputtype: 59 mesh = ob.mesh() 60 61 if ob.dim() > 0: 62 printc("MeshFunction of dim>0 not supported.", c="r") 63 printc('Try e.g.: MeshFunction("size_t", mesh, 0)', c="r", italic=1) 64 printc('instead of MeshFunction("size_t", mesh, 1)', c="r", strike=1) 65 else: 66 # printc(ob.dim(), mesh.num_cells(), len(mesh.coordinates()), len(ob.array())) 67 V = dolfin.FunctionSpace(mesh, "CG", 1) 68 u = dolfin.Function(V) 69 v2d = dolfin.vertex_to_dof_map(V) 70 u.vector()[v2d] = ob.array() 71 elif "Function" in inputtype or "Expression" in inputtype: 72 u = ob 73 elif "ufl.mathfunctions" in inputtype: # not working 74 u = ob 75 elif "Mesh" in inputtype: 76 mesh = ob 77 elif "algebra" in inputtype: 78 mesh = ob.ufl_domain() 79 # print('algebra', ob.ufl_domain()) 80 81 if u and not mesh and hasattr(u, "function_space"): 82 V = u.function_space() 83 if V: 84 mesh = V.mesh() 85 if u and not mesh and hasattr(u, "mesh"): 86 mesh = u.mesh() 87 88 # printc('------------------------------------') 89 # printc('mesh.topology dim=', mesh.topology().dim()) 90 # printc('mesh.geometry dim=', mesh.geometry().dim()) 91 # if u: printc('u.value_rank()', u.value_rank()) 92 # if u and u.value_rank(): printc('u.value_dimension()', u.value_dimension(0)) # axis=0 93 ##if u: printc('u.value_shape()', u.value_shape()) 94 return (mesh, u) 95 96 97def _compute_uvalues(u, mesh): 98 # the whole purpose of this function is 99 # to have a scalar (or vector) for each point of the mesh 100 101 if not u: 102 return np.array([]) 103 # print('u',u) 104 105 if hasattr(u, "compute_vertex_values"): # old dolfin, works fine 106 u_values = u.compute_vertex_values(mesh) 107 108 if u.value_rank() and u.value_dimension(0) > 1: 109 l = u_values.shape[0] 110 u_values = u_values.reshape(u.value_dimension(0), int(l / u.value_dimension(0))).T 111 112 elif hasattr(u, "compute_point_values"): # dolfinx 113 u_values = u.compute_point_values() 114 115 try: 116 from dolfin import fem 117 118 fvec = u.vector 119 except RuntimeError: 120 fspace = u.function_space 121 try: 122 fspace = fspace.collapse() 123 except RuntimeError: 124 return [] 125 126 fvec = fem.interpolate(u, fspace).vector 127 128 tdim = mesh.topology.dim 129 130 # print('fvec.getSize', fvec.getSize(), mesh.num_entities(tdim)) 131 if fvec.getSize() == mesh.num_entities(tdim): 132 # DG0 cellwise function 133 C = fvec.get_local() 134 if C.dtype.type is np.complex128: 135 print("Plotting real part of complex data") 136 C = np.real(C) 137 138 u_values = C 139 140 else: 141 u_values = [] 142 143 if hasattr(mesh, "coordinates"): 144 coords = mesh.coordinates() 145 else: 146 coords = mesh.geometry.points 147 148 if u_values.shape[0] != coords.shape[0]: 149 vedo.logger.warning("mismatch in vedo.dolfin._compute_uvalues") 150 u_values = np.array([u(p) for p in coords]) 151 return u_values 152 153 154def plot(*inputobj, **options): 155 """ 156 Plot the object(s) provided. 157 158 Input can be any combination of: `Mesh`, `Volume`, `dolfin.Mesh`, 159 `dolfin.MeshFunction`, `dolfin.Expression` or `dolfin.Function`. 160 161 Return the current `Plotter` class instance. 162 163 Arguments: 164 mode : (str) 165 one or more of the following can be combined in any order 166 - `mesh`/`color`, will plot the mesh, by default colored with a scalar if available 167 - `displacement` show displaced mesh by solution 168 - `arrows`, mesh displacements are plotted as scaled arrows. 169 - `lines`, mesh displacements are plotted as scaled lines. 170 - `tensors`, to be implemented 171 add : (bool) 172 add the input objects without clearing the already plotted ones 173 density : (float) 174 show only a subset of lines or arrows [0-1] 175 wire[frame] : (bool) 176 visualize mesh as wireframe [False] 177 c[olor] : (color) 178 set mesh color [None] 179 exterior : (bool) 180 only show the outer surface of the mesh [False] 181 alpha : (float) 182 set object's transparency [1] 183 lw : (int) 184 line width of the mesh (set to zero to hide mesh) [0.1] 185 ps : int 186 set point size of mesh vertices [None] 187 z : (float) 188 add a constant to z-coordinate (useful to show 2D slices as function of time) 189 legend : (str) 190 add a legend to the top-right of window [None] 191 scalarbar : (bool) 192 add a scalarbar to the window ['vertical'] 193 vmin : (float) 194 set the minimum for the range of the scalar [None] 195 vmax : (float) 196 set the maximum for the range of the scalar [None] 197 scale : (float) 198 add a scaling factor to arrows and lines sizes [1] 199 cmap : (str) 200 choose a color map for scalars 201 shading : (str) 202 mesh shading ['flat', 'phong'] 203 text : (str) 204 add a gray text comment to the top-left of the window [None] 205 isolines : (dict) 206 dictionary of isolines properties 207 - n, (int) - add this number of isolines to the mesh 208 - c, - isoline color 209 - lw, (float) - isoline width 210 - z, (float) - add to the isoline z coordinate to make them more visible 211 warp_zfactor : (float) 212 elevate z-axis by scalar value (useful for 2D geometries) 213 warp_yfactor : (float) 214 elevate z-axis by scalar value (useful for 1D geometries) 215 scale_mesh_factors : (list) 216 rescale mesh by these factors [1,1,1] 217 new : (bool) 218 spawn a new instance of Plotter class, pops up a new window 219 at : (int) 220 renderer number to plot to 221 shape : (list) 222 subdvide window in (n,m) rows and columns 223 N : (int) 224 automatically subdvide window in N renderers 225 pos : (list) 226 (x,y) coordinates of the window position on screen 227 size : (list) 228 window size (x,y) 229 title : (str) 230 window title 231 bg : (color) 232 background color name of window 233 bg2 : (color) 234 second background color name to create a color gradient 235 style : (int) 236 choose a predefined style [0-4] 237 - 0, `vedo`, style (blackboard background, rainbow color map) 238 - 1, `matplotlib`, style (white background, viridis color map) 239 - 2, `paraview`, style 240 - 3, `meshlab`, style 241 - 4, `bw`, black and white style. 242 axes : (int) 243 Axes type number. 244 Axes type-1 can be fully customized by passing a dictionary `axes=dict()`. 245 - 0, no axes, 246 - 1, draw customizable grid axes (see below). 247 - 2, show cartesian axes from (0,0,0) 248 - 3, show positive range of cartesian axes from (0,0,0) 249 - 4, show a triad at bottom left 250 - 5, show a cube at bottom left 251 - 6, mark the corners of the bounding box 252 - 7, draw a simple ruler at the bottom of the window 253 - 8, show the `vtkCubeAxesActor` object, 254 - 9, show the bounding box outLine, 255 - 10, show three circles representing the maximum bounding box, 256 - 11, show a large grid on the x-y plane (use with zoom=8) 257 - 12, show polar axes. 258 infinity : (bool) 259 if True fugue point is set at infinity (no perspective effects) 260 sharecam : (bool) 261 if False each renderer will have an independent vtkCamera 262 interactive : (bool) 263 if True will stop after show() to allow interaction w/ window 264 offscreen : (bool) 265 if True will not show the rendering window 266 zoom : (float) 267 camera zooming factor 268 viewup : (list), str 269 camera view-up direction ['x','y','z', or a vector direction] 270 azimuth : (float) 271 add azimuth rotation of the scene, in degrees 272 elevation : (float) 273 add elevation rotation of the scene, in degrees 274 roll : (float) 275 add roll-type rotation of the scene, in degrees 276 camera : (dict) 277 Camera parameters can further be specified with a dictionary 278 assigned to the `camera` keyword: 279 (E.g. `show(camera={'pos':(1,2,3), 'thickness':1000,})`) 280 - `pos`, `(list)`, 281 the position of the camera in world coordinates 282 - `focal_point`, `(list)`, 283 the focal point of the camera in world coordinates 284 - `viewup`, `(list)`, 285 the view up direction for the camera 286 - `distance`, `(float)`, 287 set the focal point to the specified distance from the camera position. 288 - `clipping_range`, `(float)`, 289 distance of the near and far clipping planes along the direction of projection. 290 - `parallel_scale`, `(float)`, 291 scaling used for a parallel projection, i.e. the height of the viewport 292 in world-coordinate distances. The default is 1. Note that the "scale" parameter works as 293 an "inverse scale", larger numbers produce smaller images. 294 This method has no effect in perspective projection mode. 295 - `thickness`, `(float)`, 296 set the distance between clipping planes. This method adjusts the far clipping 297 plane to be set a distance 'thickness' beyond the near clipping plane. 298 - `view_angle`, `(float)`, 299 the camera view angle, which is the angular height of the camera view 300 measured in degrees. The default angle is 30 degrees. 301 This method has no effect in parallel projection mode. 302 The formula for setting the angle up for perfect perspective viewing is: 303 angle = 2*atan((h/2)/d) where h is the height of the RenderWindow 304 (measured by holding a ruler up to your screen) and d is the distance 305 from your eyes to the screen. 306 """ 307 if len(inputobj) == 0: 308 vedo.plotter_instance.interactive() 309 return None 310 311 if "numpy" in str(type(inputobj[0])): 312 from vedo.pyplot import plot as pyplot_plot 313 314 return pyplot_plot(*inputobj, **options) 315 316 mesh, u = _inputsort(inputobj) 317 318 mode = options.pop("mode", "mesh") 319 ttime = options.pop("z", None) 320 321 add = options.pop("add", False) 322 323 wire = options.pop("wireframe", None) 324 325 c = options.pop("c", None) 326 color = options.pop("color", None) 327 if color is not None: 328 c = color 329 330 lc = options.pop("lc", None) 331 332 alpha = options.pop("alpha", 1) 333 lw = options.pop("lw", 0.5) 334 ps = options.pop("ps", None) 335 legend = options.pop("legend", None) 336 scbar = options.pop("scalarbar", "v") 337 vmin = options.pop("vmin", None) 338 vmax = options.pop("vmax", None) 339 cmap = options.pop("cmap", None) 340 scale = options.pop("scale", 1) 341 scale_mesh_factors = options.pop("scale_mesh_factors", [1, 1, 1]) 342 shading = options.pop("shading", "phong") 343 text = options.pop("text", None) 344 style = options.pop("style", "vtk") 345 isolns = options.pop("isolines", {}) 346 warp_zfactor = options.pop("warp_zfactor", None) 347 warp_yfactor = options.pop("warp_yfactor", None) 348 lighting = options.pop("lighting", None) 349 exterior = options.pop("exterior", False) 350 returnActorsNoShow = options.pop("returnActorsNoShow", False) 351 at = options.pop("at", 0) 352 353 # refresh axes titles for axes type = 8 (vtkCubeAxesActor) 354 xtitle = options.pop("xtitle", "x") 355 ytitle = options.pop("ytitle", "y") 356 ztitle = options.pop("ztitle", "z") 357 if vedo.plotter_instance: 358 if xtitle != "x": 359 aet = vedo.plotter_instance.axes_instances 360 if len(aet) > at and isinstance(aet[at], vtki.get_class("CubeAxesActor")): 361 aet[at].SetXTitle(xtitle) 362 if ytitle != "y": 363 aet = vedo.plotter_instance.axes_instances 364 if len(aet) > at and isinstance(aet[at], vtki.get_class("CubeAxesActor")): 365 aet[at].SetYTitle(ytitle) 366 if ztitle != "z": 367 aet = vedo.plotter_instance.axes_instances 368 if len(aet) > at and isinstance(aet[at], vtki.get_class("CubeAxesActor")): 369 aet[at].SetZTitle(ztitle) 370 371 # change some default to emulate standard behaviours 372 if style in (0, "vtk"): 373 axes = options.pop("axes", None) 374 if axes is None: 375 options["axes"] = {"xygrid": False, "yzgrid": False, "zxgrid": False} 376 else: 377 options["axes"] = axes # put back 378 if cmap is None: 379 cmap = "rainbow" 380 elif style in (1, "matplotlib"): 381 bg = options.pop("bg", None) 382 if bg is None: 383 options["bg"] = "white" 384 else: 385 options["bg"] = bg 386 axes = options.pop("axes", None) 387 if axes is None: 388 options["axes"] = {"xygrid": False, "yzgrid": False, "zxgrid": False} 389 else: 390 options["axes"] = axes # put back 391 if cmap is None: 392 cmap = "viridis" 393 elif style in (2, "paraview"): 394 bg = options.pop("bg", None) 395 if bg is None: 396 options["bg"] = (82, 87, 110) 397 else: 398 options["bg"] = bg 399 if cmap is None: 400 cmap = "coolwarm" 401 elif style in (3, "meshlab"): 402 bg = options.pop("bg", None) 403 if bg is None: 404 options["bg"] = (8, 8, 16) 405 options["bg2"] = (117, 117, 234) 406 else: 407 options["bg"] = bg 408 axes = options.pop("axes", None) 409 if axes is None: 410 options["axes"] = 10 411 else: 412 options["axes"] = axes # put back 413 if cmap is None: 414 cmap = "afmhot" 415 elif style in (4, "bw"): 416 bg = options.pop("bg", None) 417 if bg is None: 418 options["bg"] = (217, 255, 238) 419 else: 420 options["bg"] = bg 421 axes = options.pop("axes", None) 422 if axes is None: 423 options["axes"] = {"xygrid": False, "yzgrid": False, "zxgrid": False} 424 else: 425 options["axes"] = axes # put back 426 if cmap is None: 427 cmap = "binary" 428 429 ################################################################# 430 actors = [] 431 if vedo.plotter_instance: 432 if add: 433 actors = vedo.plotter_instance.actors 434 435 if mesh and ("mesh" in mode or "color" in mode or "displace" in mode): 436 437 msh = IMesh(u, mesh, exterior=exterior) 438 439 msh.wireframe(wire) 440 msh.scale(scale_mesh_factors) 441 if lighting: 442 msh.lighting(lighting) 443 if ttime: 444 msh.z(ttime) 445 if legend: 446 msh.legend(legend) 447 if c: 448 msh.color(c) 449 if lc: 450 msh.linecolor(lc) 451 if alpha: 452 alpha = min(alpha, 1) 453 msh.alpha(alpha * alpha) 454 if lw: 455 msh.linewidth(lw) 456 if wire and alpha: 457 lw1 = min(lw, 1) 458 msh.alpha(alpha * lw1) 459 if ps: 460 msh.point_size(ps) 461 if shading: 462 if shading == "phong": 463 msh.phong() 464 elif shading == "flat": 465 msh.flat() 466 elif shading[0] == "g": 467 msh.phong() 468 469 if "displace" in mode: 470 msh.move(u) 471 472 if cmap and (msh.u_values is not None) and len(msh.u_values)>0 and c is None: 473 if msh.u_values.ndim > 1: 474 msh.cmap(cmap, utils.mag(msh.u_values), vmin=vmin, vmax=vmax) 475 else: 476 msh.cmap(cmap, msh.u_values, vmin=vmin, vmax=vmax) 477 478 if warp_yfactor: 479 scals = msh.pointdata[0] 480 if len(scals) > 0: 481 pts_act = msh.vertices 482 pts_act[:, 1] = scals * warp_yfactor * scale_mesh_factors[1] 483 if warp_zfactor: 484 scals = msh.pointdata[0] 485 if len(scals) > 0: 486 pts_act = msh.vertices 487 pts_act[:, 2] = scals * warp_zfactor * scale_mesh_factors[2] 488 if warp_yfactor or warp_zfactor: 489 # msh.points(pts_act) 490 msh.vertices = pts_act 491 if vmin is not None and vmax is not None: 492 msh.mapper.SetScalarRange(vmin, vmax) 493 494 if scbar and c is None: 495 if "3d" in scbar: 496 msh.add_scalarbar3d() 497 elif "h" in scbar: 498 msh.add_scalarbar(horizontal=True) 499 else: 500 msh.add_scalarbar(horizontal=False) 501 502 if len(isolns) > 0: 503 ison = isolns.pop("n", 10) 504 isocol = isolns.pop("c", "black") 505 isoalpha = isolns.pop("alpha", 1) 506 isolw = isolns.pop("lw", 1) 507 508 isos = msh.isolines(n=ison).color(isocol).lw(isolw).alpha(isoalpha) 509 510 isoz = isolns.pop("z", None) 511 if isoz is not None: # kind of hack to make isolines visible on flat meshes 512 d = isoz 513 else: 514 d = msh.diagonal_size() / 400 515 isos.z(msh.z() + d) 516 actors.append(isos) 517 518 actors.append(msh) 519 520 521 ################################################################# 522 if "arrow" in mode or "line" in mode: 523 if "arrow" in mode: 524 arrs = create_arrows(u, scale=scale) 525 else: 526 arrs = create_lines(u, scale=scale) 527 528 if arrs: 529 if legend and "mesh" not in mode: 530 arrs.legend(legend) 531 if c: 532 arrs.color(c) 533 arrs.color(c) 534 if alpha: 535 arrs.alpha(alpha) 536 actors.append(arrs) 537 538 ################################################################# 539 for ob in inputobj: 540 inputtype = str(type(ob)) 541 if "vedo" in inputtype: 542 actors.append(ob) 543 544 if text: 545 actors.append(text) 546 547 if "at" in options and "interactive" not in options: 548 if vedo.plotter_instance: 549 N = vedo.plotter_instance.shape[0] * vedo.plotter_instance.shape[1] 550 if options["at"] == N - 1: 551 options["interactive"] = True 552 553 if len(actors) == 0: 554 print('Warning: no objects to show, check mode in plot(mode="...")') 555 556 if returnActorsNoShow: 557 return actors 558 559 return show(actors, **options) 560 561 562################################################################################### 563class IMesh(Mesh): 564 """Interface Mesh representation for dolfin.""" 565 566 def __init__(self, *inputobj, **options): 567 """A `vedo.Mesh` derived object for dolfin support.""" 568 569 c = options.pop("c", None) 570 alpha = options.pop("alpha", 1) 571 exterior = options.pop("exterior", False) 572 compute_normals = options.pop("compute_normals", False) 573 574 mesh, u = _inputsort(inputobj) 575 if not mesh: 576 return 577 578 if exterior: 579 import dolfin 580 581 meshc = dolfin.BoundaryMesh(mesh, "exterior") 582 else: 583 meshc = mesh 584 585 if hasattr(mesh, "coordinates"): 586 coords = mesh.coordinates() 587 else: 588 coords = mesh.geometry.points 589 590 cells = meshc.cells() 591 592 if cells.shape[1] == 4: 593 poly = vtki.vtkPolyData() 594 595 source_points = vtki.vtkPoints() 596 source_points.SetData(utils.numpy2vtk(coords, dtype=np.float32)) 597 poly.SetPoints(source_points) 598 599 source_polygons = vtki.vtkCellArray() 600 for f in cells: 601 # do not use vtkTetra() because it fails 602 # with dolfin faces orientation 603 ele0 = vtki.vtkTriangle() 604 ele1 = vtki.vtkTriangle() 605 ele2 = vtki.vtkTriangle() 606 ele3 = vtki.vtkTriangle() 607 608 f0, f1, f2, f3 = f 609 pid0 = ele0.GetPointIds() 610 pid1 = ele1.GetPointIds() 611 pid2 = ele2.GetPointIds() 612 pid3 = ele3.GetPointIds() 613 614 pid0.SetId(0, f0) 615 pid0.SetId(1, f1) 616 pid0.SetId(2, f2) 617 618 pid1.SetId(0, f0) 619 pid1.SetId(1, f1) 620 pid1.SetId(2, f3) 621 622 pid2.SetId(0, f1) 623 pid2.SetId(1, f2) 624 pid2.SetId(2, f3) 625 626 pid3.SetId(0, f2) 627 pid3.SetId(1, f3) 628 pid3.SetId(2, f0) 629 630 source_polygons.InsertNextCell(ele0) 631 source_polygons.InsertNextCell(ele1) 632 source_polygons.InsertNextCell(ele2) 633 source_polygons.InsertNextCell(ele3) 634 635 poly.SetPolys(source_polygons) 636 637 else: 638 poly = utils.buildPolyData(coords, cells) 639 640 super().__init__(poly, c, alpha) 641 642 if compute_normals: 643 self.compute_normals() 644 645 self.mesh = mesh # holds a dolfin Mesh obj 646 self.u = u # holds a dolfin function_data 647 # holds the actual values of u on the mesh 648 self.u_values = _compute_uvalues(u, mesh) 649 650 ##################################### 651 def move(self, u=None, deltas=None): 652 """Move mesh according to solution `u` or from calculated vertex displacements `deltas`.""" 653 if u is None: 654 u = self.u 655 if deltas is None: 656 if self.u_values is not None: 657 deltas = self.u_values 658 else: 659 deltas = _compute_uvalues(u, self.mesh) 660 self.u_values = deltas 661 662 if hasattr(self.mesh, "coordinates"): 663 coords = self.mesh.coordinates() 664 else: 665 coords = self.mesh.geometry.points 666 667 if coords.shape != deltas.shape: 668 vedo.logger.error( 669 f"Try to move mesh with wrong solution type shape {coords.shape} vs {deltas.shape}" 670 ) 671 vedo.logger.error("Mesh is not moved. Try mode='color' in plot().") 672 return 673 674 movedpts = coords + deltas 675 if movedpts.shape[1] == 2: # 2d 676 movedpts = np.c_[movedpts, np.zeros(movedpts.shape[0])] 677 self.dataset.GetPoints().SetData(utils.numpy2vtk(movedpts, dtype=np.float32)) 678 self.dataset.GetPoints().Modified() 679 680################################################################################### 681def create_lines(*inputobj, **options): 682 """ 683 Build the line segments between two lists of points `start_points` and `end_points`. 684 `start_points` can be also passed in the form `[[point1, point2], ...]`. 685 686 A dolfin `Mesh` that was deformed/modified by a function can be 687 passed together as inputs. 688 689 Use `scale` to apply a rescaling factor to the length 690 """ 691 scale = options.pop("scale", 1) 692 lw = options.pop("lw", 1) 693 c = options.pop("c", "grey") 694 alpha = options.pop("alpha", 1) 695 696 mesh, u = _inputsort(inputobj) 697 if not mesh: 698 return None 699 700 if hasattr(mesh, "coordinates"): 701 start_points = mesh.coordinates() 702 else: 703 start_points = mesh.geometry.points 704 705 u_values = _compute_uvalues(u, mesh) 706 if not utils.is_sequence(u_values[0]): 707 vedo.logger.error("cannot show Lines for 1D scalar values") 708 raise RuntimeError() 709 710 end_points = start_points + u_values 711 if u_values.shape[1] == 2: # u_values is 2D 712 u_values = np.insert(u_values, 2, 0, axis=1) # make it 3d 713 start_points = np.insert(start_points, 2, 0, axis=1) # make it 3d 714 end_points = np.insert(end_points, 2, 0, axis=1) # make it 3d 715 716 lines = shapes.Lines(start_points, end_points, scale=scale, lw=lw, c=c, alpha=alpha) 717 718 lines.mesh = mesh 719 lines.u = u 720 lines.u_values = u_values 721 return lines 722 723################################################################################### 724def create_arrows(*inputobj, **options): 725 """Build arrows representing displacements.""" 726 s = options.pop("s", None) 727 c = options.pop("c", "k3") 728 scale = options.pop("scale", 1) 729 alpha = options.pop("alpha", 1) 730 res = options.pop("res", 12) 731 732 mesh, u = _inputsort(inputobj) 733 if not mesh: 734 return None 735 736 if hasattr(mesh, "coordinates"): 737 start_points = mesh.coordinates() 738 else: 739 start_points = mesh.geometry.points 740 741 u_values = _compute_uvalues(u, mesh) 742 if not utils.is_sequence(u_values[0]): 743 vedo.logger.error("cannot show Arrows for 1D scalar values") 744 raise RuntimeError() 745 746 end_points = start_points + u_values * scale 747 if u_values.shape[1] == 2: # u_values is 2D 748 u_values = np.insert(u_values, 2, 0, axis=1) # make it 3d 749 start_points = np.insert(start_points, 2, 0, axis=1) # make it 3d 750 end_points = np.insert(end_points, 2, 0, axis=1) # make it 3d 751 752 obj = shapes.Arrows(start_points, end_points, s=s, alpha=alpha, c=c, res=res) 753 obj.mesh = mesh 754 obj.u = u 755 obj.u_values = u_values 756 return obj
def
plot(*inputobj, **options):
155def plot(*inputobj, **options): 156 """ 157 Plot the object(s) provided. 158 159 Input can be any combination of: `Mesh`, `Volume`, `dolfin.Mesh`, 160 `dolfin.MeshFunction`, `dolfin.Expression` or `dolfin.Function`. 161 162 Return the current `Plotter` class instance. 163 164 Arguments: 165 mode : (str) 166 one or more of the following can be combined in any order 167 - `mesh`/`color`, will plot the mesh, by default colored with a scalar if available 168 - `displacement` show displaced mesh by solution 169 - `arrows`, mesh displacements are plotted as scaled arrows. 170 - `lines`, mesh displacements are plotted as scaled lines. 171 - `tensors`, to be implemented 172 add : (bool) 173 add the input objects without clearing the already plotted ones 174 density : (float) 175 show only a subset of lines or arrows [0-1] 176 wire[frame] : (bool) 177 visualize mesh as wireframe [False] 178 c[olor] : (color) 179 set mesh color [None] 180 exterior : (bool) 181 only show the outer surface of the mesh [False] 182 alpha : (float) 183 set object's transparency [1] 184 lw : (int) 185 line width of the mesh (set to zero to hide mesh) [0.1] 186 ps : int 187 set point size of mesh vertices [None] 188 z : (float) 189 add a constant to z-coordinate (useful to show 2D slices as function of time) 190 legend : (str) 191 add a legend to the top-right of window [None] 192 scalarbar : (bool) 193 add a scalarbar to the window ['vertical'] 194 vmin : (float) 195 set the minimum for the range of the scalar [None] 196 vmax : (float) 197 set the maximum for the range of the scalar [None] 198 scale : (float) 199 add a scaling factor to arrows and lines sizes [1] 200 cmap : (str) 201 choose a color map for scalars 202 shading : (str) 203 mesh shading ['flat', 'phong'] 204 text : (str) 205 add a gray text comment to the top-left of the window [None] 206 isolines : (dict) 207 dictionary of isolines properties 208 - n, (int) - add this number of isolines to the mesh 209 - c, - isoline color 210 - lw, (float) - isoline width 211 - z, (float) - add to the isoline z coordinate to make them more visible 212 warp_zfactor : (float) 213 elevate z-axis by scalar value (useful for 2D geometries) 214 warp_yfactor : (float) 215 elevate z-axis by scalar value (useful for 1D geometries) 216 scale_mesh_factors : (list) 217 rescale mesh by these factors [1,1,1] 218 new : (bool) 219 spawn a new instance of Plotter class, pops up a new window 220 at : (int) 221 renderer number to plot to 222 shape : (list) 223 subdvide window in (n,m) rows and columns 224 N : (int) 225 automatically subdvide window in N renderers 226 pos : (list) 227 (x,y) coordinates of the window position on screen 228 size : (list) 229 window size (x,y) 230 title : (str) 231 window title 232 bg : (color) 233 background color name of window 234 bg2 : (color) 235 second background color name to create a color gradient 236 style : (int) 237 choose a predefined style [0-4] 238 - 0, `vedo`, style (blackboard background, rainbow color map) 239 - 1, `matplotlib`, style (white background, viridis color map) 240 - 2, `paraview`, style 241 - 3, `meshlab`, style 242 - 4, `bw`, black and white style. 243 axes : (int) 244 Axes type number. 245 Axes type-1 can be fully customized by passing a dictionary `axes=dict()`. 246 - 0, no axes, 247 - 1, draw customizable grid axes (see below). 248 - 2, show cartesian axes from (0,0,0) 249 - 3, show positive range of cartesian axes from (0,0,0) 250 - 4, show a triad at bottom left 251 - 5, show a cube at bottom left 252 - 6, mark the corners of the bounding box 253 - 7, draw a simple ruler at the bottom of the window 254 - 8, show the `vtkCubeAxesActor` object, 255 - 9, show the bounding box outLine, 256 - 10, show three circles representing the maximum bounding box, 257 - 11, show a large grid on the x-y plane (use with zoom=8) 258 - 12, show polar axes. 259 infinity : (bool) 260 if True fugue point is set at infinity (no perspective effects) 261 sharecam : (bool) 262 if False each renderer will have an independent vtkCamera 263 interactive : (bool) 264 if True will stop after show() to allow interaction w/ window 265 offscreen : (bool) 266 if True will not show the rendering window 267 zoom : (float) 268 camera zooming factor 269 viewup : (list), str 270 camera view-up direction ['x','y','z', or a vector direction] 271 azimuth : (float) 272 add azimuth rotation of the scene, in degrees 273 elevation : (float) 274 add elevation rotation of the scene, in degrees 275 roll : (float) 276 add roll-type rotation of the scene, in degrees 277 camera : (dict) 278 Camera parameters can further be specified with a dictionary 279 assigned to the `camera` keyword: 280 (E.g. `show(camera={'pos':(1,2,3), 'thickness':1000,})`) 281 - `pos`, `(list)`, 282 the position of the camera in world coordinates 283 - `focal_point`, `(list)`, 284 the focal point of the camera in world coordinates 285 - `viewup`, `(list)`, 286 the view up direction for the camera 287 - `distance`, `(float)`, 288 set the focal point to the specified distance from the camera position. 289 - `clipping_range`, `(float)`, 290 distance of the near and far clipping planes along the direction of projection. 291 - `parallel_scale`, `(float)`, 292 scaling used for a parallel projection, i.e. the height of the viewport 293 in world-coordinate distances. The default is 1. Note that the "scale" parameter works as 294 an "inverse scale", larger numbers produce smaller images. 295 This method has no effect in perspective projection mode. 296 - `thickness`, `(float)`, 297 set the distance between clipping planes. This method adjusts the far clipping 298 plane to be set a distance 'thickness' beyond the near clipping plane. 299 - `view_angle`, `(float)`, 300 the camera view angle, which is the angular height of the camera view 301 measured in degrees. The default angle is 30 degrees. 302 This method has no effect in parallel projection mode. 303 The formula for setting the angle up for perfect perspective viewing is: 304 angle = 2*atan((h/2)/d) where h is the height of the RenderWindow 305 (measured by holding a ruler up to your screen) and d is the distance 306 from your eyes to the screen. 307 """ 308 if len(inputobj) == 0: 309 vedo.plotter_instance.interactive() 310 return None 311 312 if "numpy" in str(type(inputobj[0])): 313 from vedo.pyplot import plot as pyplot_plot 314 315 return pyplot_plot(*inputobj, **options) 316 317 mesh, u = _inputsort(inputobj) 318 319 mode = options.pop("mode", "mesh") 320 ttime = options.pop("z", None) 321 322 add = options.pop("add", False) 323 324 wire = options.pop("wireframe", None) 325 326 c = options.pop("c", None) 327 color = options.pop("color", None) 328 if color is not None: 329 c = color 330 331 lc = options.pop("lc", None) 332 333 alpha = options.pop("alpha", 1) 334 lw = options.pop("lw", 0.5) 335 ps = options.pop("ps", None) 336 legend = options.pop("legend", None) 337 scbar = options.pop("scalarbar", "v") 338 vmin = options.pop("vmin", None) 339 vmax = options.pop("vmax", None) 340 cmap = options.pop("cmap", None) 341 scale = options.pop("scale", 1) 342 scale_mesh_factors = options.pop("scale_mesh_factors", [1, 1, 1]) 343 shading = options.pop("shading", "phong") 344 text = options.pop("text", None) 345 style = options.pop("style", "vtk") 346 isolns = options.pop("isolines", {}) 347 warp_zfactor = options.pop("warp_zfactor", None) 348 warp_yfactor = options.pop("warp_yfactor", None) 349 lighting = options.pop("lighting", None) 350 exterior = options.pop("exterior", False) 351 returnActorsNoShow = options.pop("returnActorsNoShow", False) 352 at = options.pop("at", 0) 353 354 # refresh axes titles for axes type = 8 (vtkCubeAxesActor) 355 xtitle = options.pop("xtitle", "x") 356 ytitle = options.pop("ytitle", "y") 357 ztitle = options.pop("ztitle", "z") 358 if vedo.plotter_instance: 359 if xtitle != "x": 360 aet = vedo.plotter_instance.axes_instances 361 if len(aet) > at and isinstance(aet[at], vtki.get_class("CubeAxesActor")): 362 aet[at].SetXTitle(xtitle) 363 if ytitle != "y": 364 aet = vedo.plotter_instance.axes_instances 365 if len(aet) > at and isinstance(aet[at], vtki.get_class("CubeAxesActor")): 366 aet[at].SetYTitle(ytitle) 367 if ztitle != "z": 368 aet = vedo.plotter_instance.axes_instances 369 if len(aet) > at and isinstance(aet[at], vtki.get_class("CubeAxesActor")): 370 aet[at].SetZTitle(ztitle) 371 372 # change some default to emulate standard behaviours 373 if style in (0, "vtk"): 374 axes = options.pop("axes", None) 375 if axes is None: 376 options["axes"] = {"xygrid": False, "yzgrid": False, "zxgrid": False} 377 else: 378 options["axes"] = axes # put back 379 if cmap is None: 380 cmap = "rainbow" 381 elif style in (1, "matplotlib"): 382 bg = options.pop("bg", None) 383 if bg is None: 384 options["bg"] = "white" 385 else: 386 options["bg"] = bg 387 axes = options.pop("axes", None) 388 if axes is None: 389 options["axes"] = {"xygrid": False, "yzgrid": False, "zxgrid": False} 390 else: 391 options["axes"] = axes # put back 392 if cmap is None: 393 cmap = "viridis" 394 elif style in (2, "paraview"): 395 bg = options.pop("bg", None) 396 if bg is None: 397 options["bg"] = (82, 87, 110) 398 else: 399 options["bg"] = bg 400 if cmap is None: 401 cmap = "coolwarm" 402 elif style in (3, "meshlab"): 403 bg = options.pop("bg", None) 404 if bg is None: 405 options["bg"] = (8, 8, 16) 406 options["bg2"] = (117, 117, 234) 407 else: 408 options["bg"] = bg 409 axes = options.pop("axes", None) 410 if axes is None: 411 options["axes"] = 10 412 else: 413 options["axes"] = axes # put back 414 if cmap is None: 415 cmap = "afmhot" 416 elif style in (4, "bw"): 417 bg = options.pop("bg", None) 418 if bg is None: 419 options["bg"] = (217, 255, 238) 420 else: 421 options["bg"] = bg 422 axes = options.pop("axes", None) 423 if axes is None: 424 options["axes"] = {"xygrid": False, "yzgrid": False, "zxgrid": False} 425 else: 426 options["axes"] = axes # put back 427 if cmap is None: 428 cmap = "binary" 429 430 ################################################################# 431 actors = [] 432 if vedo.plotter_instance: 433 if add: 434 actors = vedo.plotter_instance.actors 435 436 if mesh and ("mesh" in mode or "color" in mode or "displace" in mode): 437 438 msh = IMesh(u, mesh, exterior=exterior) 439 440 msh.wireframe(wire) 441 msh.scale(scale_mesh_factors) 442 if lighting: 443 msh.lighting(lighting) 444 if ttime: 445 msh.z(ttime) 446 if legend: 447 msh.legend(legend) 448 if c: 449 msh.color(c) 450 if lc: 451 msh.linecolor(lc) 452 if alpha: 453 alpha = min(alpha, 1) 454 msh.alpha(alpha * alpha) 455 if lw: 456 msh.linewidth(lw) 457 if wire and alpha: 458 lw1 = min(lw, 1) 459 msh.alpha(alpha * lw1) 460 if ps: 461 msh.point_size(ps) 462 if shading: 463 if shading == "phong": 464 msh.phong() 465 elif shading == "flat": 466 msh.flat() 467 elif shading[0] == "g": 468 msh.phong() 469 470 if "displace" in mode: 471 msh.move(u) 472 473 if cmap and (msh.u_values is not None) and len(msh.u_values)>0 and c is None: 474 if msh.u_values.ndim > 1: 475 msh.cmap(cmap, utils.mag(msh.u_values), vmin=vmin, vmax=vmax) 476 else: 477 msh.cmap(cmap, msh.u_values, vmin=vmin, vmax=vmax) 478 479 if warp_yfactor: 480 scals = msh.pointdata[0] 481 if len(scals) > 0: 482 pts_act = msh.vertices 483 pts_act[:, 1] = scals * warp_yfactor * scale_mesh_factors[1] 484 if warp_zfactor: 485 scals = msh.pointdata[0] 486 if len(scals) > 0: 487 pts_act = msh.vertices 488 pts_act[:, 2] = scals * warp_zfactor * scale_mesh_factors[2] 489 if warp_yfactor or warp_zfactor: 490 # msh.points(pts_act) 491 msh.vertices = pts_act 492 if vmin is not None and vmax is not None: 493 msh.mapper.SetScalarRange(vmin, vmax) 494 495 if scbar and c is None: 496 if "3d" in scbar: 497 msh.add_scalarbar3d() 498 elif "h" in scbar: 499 msh.add_scalarbar(horizontal=True) 500 else: 501 msh.add_scalarbar(horizontal=False) 502 503 if len(isolns) > 0: 504 ison = isolns.pop("n", 10) 505 isocol = isolns.pop("c", "black") 506 isoalpha = isolns.pop("alpha", 1) 507 isolw = isolns.pop("lw", 1) 508 509 isos = msh.isolines(n=ison).color(isocol).lw(isolw).alpha(isoalpha) 510 511 isoz = isolns.pop("z", None) 512 if isoz is not None: # kind of hack to make isolines visible on flat meshes 513 d = isoz 514 else: 515 d = msh.diagonal_size() / 400 516 isos.z(msh.z() + d) 517 actors.append(isos) 518 519 actors.append(msh) 520 521 522 ################################################################# 523 if "arrow" in mode or "line" in mode: 524 if "arrow" in mode: 525 arrs = create_arrows(u, scale=scale) 526 else: 527 arrs = create_lines(u, scale=scale) 528 529 if arrs: 530 if legend and "mesh" not in mode: 531 arrs.legend(legend) 532 if c: 533 arrs.color(c) 534 arrs.color(c) 535 if alpha: 536 arrs.alpha(alpha) 537 actors.append(arrs) 538 539 ################################################################# 540 for ob in inputobj: 541 inputtype = str(type(ob)) 542 if "vedo" in inputtype: 543 actors.append(ob) 544 545 if text: 546 actors.append(text) 547 548 if "at" in options and "interactive" not in options: 549 if vedo.plotter_instance: 550 N = vedo.plotter_instance.shape[0] * vedo.plotter_instance.shape[1] 551 if options["at"] == N - 1: 552 options["interactive"] = True 553 554 if len(actors) == 0: 555 print('Warning: no objects to show, check mode in plot(mode="...")') 556 557 if returnActorsNoShow: 558 return actors 559 560 return show(actors, **options)
Plot the object(s) provided.
Input can be any combination of: Mesh
, Volume
, dolfin.Mesh
,
dolfin.MeshFunction
, dolfin.Expression
or dolfin.Function
.
Return the current Plotter
class instance.
Arguments:
- mode : (str)
one or more of the following can be combined in any order
mesh
/color
, will plot the mesh, by default colored with a scalar if availabledisplacement
show displaced mesh by solutionarrows
, mesh displacements are plotted as scaled arrows.lines
, mesh displacements are plotted as scaled lines.tensors
, to be implemented
- add : (bool) add the input objects without clearing the already plotted ones
- density : (float) show only a subset of lines or arrows [0-1]
- wire[frame] : (bool) visualize mesh as wireframe [False]
- c[olor] : (color) set mesh color [None]
- exterior : (bool) only show the outer surface of the mesh [False]
- alpha : (float) set object's transparency [1]
- lw : (int) line width of the mesh (set to zero to hide mesh) [0.1]
- ps : int set point size of mesh vertices [None]
- z : (float) add a constant to z-coordinate (useful to show 2D slices as function of time)
- legend : (str) add a legend to the top-right of window [None]
- scalarbar : (bool) add a scalarbar to the window ['vertical']
- vmin : (float) set the minimum for the range of the scalar [None]
- vmax : (float) set the maximum for the range of the scalar [None]
- scale : (float) add a scaling factor to arrows and lines sizes [1]
- cmap : (str) choose a color map for scalars
- shading : (str) mesh shading ['flat', 'phong']
- text : (str) add a gray text comment to the top-left of the window [None]
- isolines : (dict)
dictionary of isolines properties
- n, (int) - add this number of isolines to the mesh
- c, - isoline color
- lw, (float) - isoline width
- z, (float) - add to the isoline z coordinate to make them more visible
- warp_zfactor : (float) elevate z-axis by scalar value (useful for 2D geometries)
- warp_yfactor : (float) elevate z-axis by scalar value (useful for 1D geometries)
- scale_mesh_factors : (list) rescale mesh by these factors [1,1,1]
- new : (bool) spawn a new instance of Plotter class, pops up a new window
- at : (int) renderer number to plot to
- shape : (list) subdvide window in (n,m) rows and columns
- N : (int) automatically subdvide window in N renderers
- pos : (list) (x,y) coordinates of the window position on screen
- size : (list) window size (x,y)
- title : (str) window title
- bg : (color) background color name of window
- bg2 : (color) second background color name to create a color gradient
- style : (int)
choose a predefined style [0-4]
- 0,
vedo
, style (blackboard background, rainbow color map) - 1,
matplotlib
, style (white background, viridis color map) - 2,
paraview
, style - 3,
meshlab
, style - 4,
bw
, black and white style.
- 0,
- axes : (int)
Axes type number.
Axes type-1 can be fully customized by passing a dictionary
axes=dict()
.- 0, no axes,
- 1, draw customizable grid axes (see below).
- 2, show cartesian axes from (0,0,0)
- 3, show positive range of cartesian axes from (0,0,0)
- 4, show a triad at bottom left
- 5, show a cube at bottom left
- 6, mark the corners of the bounding box
- 7, draw a simple ruler at the bottom of the window
- 8, show the
vtkCubeAxesActor
object, - 9, show the bounding box outLine,
- 10, show three circles representing the maximum bounding box,
- 11, show a large grid on the x-y plane (use with zoom=8)
- 12, show polar axes.
- infinity : (bool) if True fugue point is set at infinity (no perspective effects)
- sharecam : (bool) if False each renderer will have an independent vtkCamera
- interactive : (bool) if True will stop after show() to allow interaction w/ window
- offscreen : (bool) if True will not show the rendering window
- zoom : (float) camera zooming factor
- viewup : (list), str camera view-up direction ['x','y','z', or a vector direction]
- azimuth : (float) add azimuth rotation of the scene, in degrees
- elevation : (float) add elevation rotation of the scene, in degrees
- roll : (float) add roll-type rotation of the scene, in degrees
- camera : (dict)
Camera parameters can further be specified with a dictionary
assigned to the
camera
keyword: (E.g.show(camera={'pos':(1,2,3), 'thickness':1000,})
)pos
,(list)
, the position of the camera in world coordinatesfocal_point
,(list)
, the focal point of the camera in world coordinatesviewup
,(list)
, the view up direction for the cameradistance
,(float)
, set the focal point to the specified distance from the camera position.clipping_range
,(float)
, distance of the near and far clipping planes along the direction of projection.parallel_scale
,(float)
, scaling used for a parallel projection, i.e. the height of the viewport in world-coordinate distances. The default is 1. Note that the "scale" parameter works as an "inverse scale", larger numbers produce smaller images. This method has no effect in perspective projection mode.thickness
,(float)
, set the distance between clipping planes. This method adjusts the far clipping plane to be set a distance 'thickness' beyond the near clipping plane.view_angle
,(float)
, the camera view angle, which is the angular height of the camera view measured in degrees. The default angle is 30 degrees. This method has no effect in parallel projection mode. The formula for setting the angle up for perfect perspective viewing is: angle = 2*atan((h/2)/d) where h is the height of the RenderWindow (measured by holding a ruler up to your screen) and d is the distance from your eyes to the screen.