ansys-fluent-visualization 0.16.dev0__tar.gz → 0.17.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/PKG-INFO +10 -7
  2. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/README.rst +1 -1
  3. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/pyproject.toml +8 -5
  4. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/__init__.py +2 -1
  5. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/_config.py +4 -1
  6. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/graphics/graphics_windows.py +33 -14
  7. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/graphics/graphics_windows_manager.py +81 -9
  8. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/graphics/pyvista/graphics_defns.py +65 -5
  9. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/plotter/matplotlib/plotter_defns.py +19 -2
  10. ansys_fluent_visualization-0.17.dev0/src/ansys/fluent/visualization/plotter/plotly/plotter_defns.py +176 -0
  11. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/plotter/plotter_windows.py +13 -15
  12. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/plotter/plotter_windows_manager.py +46 -30
  13. ansys_fluent_visualization-0.17.dev0/src/ansys/fluent/visualization/plotter/pyvista/__init__.py +0 -0
  14. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/AUTHORS +0 -0
  15. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/LICENSE +0 -0
  16. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/containers.py +0 -0
  17. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/contour.py +0 -0
  18. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/graphics/__init__.py +0 -0
  19. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/graphics/abstract_graphics_defns.py +0 -0
  20. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/graphics/graphics_objects.py +0 -0
  21. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/graphics/pyvista/__init__.py +0 -0
  22. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/matplotlib/__init__.py +0 -0
  23. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/plotter/__init__.py +0 -0
  24. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/plotter/abstract_plotter_defns.py +0 -0
  25. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/plotter/matplotlib/__init__.py +0 -0
  26. {ansys_fluent_visualization-0.16.dev0/src/ansys/fluent/visualization/plotter/pyvista → ansys_fluent_visualization-0.17.dev0/src/ansys/fluent/visualization/plotter/plotly}/__init__.py +0 -0
  27. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/plotter/plotter_objects.py +0 -0
  28. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/plotter/pyvista/plotter_defns.py +0 -0
  29. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/post_data_extractor.py +0 -0
  30. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/post_windows_manager.py +0 -0
  31. {ansys_fluent_visualization-0.16.dev0 → ansys_fluent_visualization-0.17.dev0}/src/ansys/fluent/visualization/pyvista/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: ansys-fluent-visualization
3
- Version: 0.16.dev0
3
+ Version: 0.17.dev0
4
4
  Summary: A python wrapper for ansys Fluent visualization
5
5
  Home-page: https://github.com/ansys/pyfluent-visualization
6
6
  License: MIT
@@ -17,12 +17,15 @@ Classifier: Programming Language :: Python :: 3.10
17
17
  Classifier: Programming Language :: Python :: 3.11
18
18
  Classifier: Programming Language :: Python :: 3.12
19
19
  Classifier: Programming Language :: Python :: 3.13
20
- Requires-Dist: ansys-fluent-core (>=0.28.dev0,<1.0)
20
+ Requires-Dist: ansys-fluent-core (>=0.29.dev0,<1.0)
21
+ Requires-Dist: imageio (>=2.36.1)
21
22
  Requires-Dist: importlib-metadata (>=4.0,<5.0) ; python_version < "3.9"
22
- Requires-Dist: matplotlib (>=3.9.0)
23
- Requires-Dist: pyside6 (>=6.7.2,<6.8.0)
24
- Requires-Dist: pyvista (>=0.44.1,<0.45.0)
23
+ Requires-Dist: matplotlib (>=3.6.0)
24
+ Requires-Dist: plotly (>=5.24.0)
25
+ Requires-Dist: pyside6 (>=6.8.1,<6.9.0)
26
+ Requires-Dist: pyvista[jupyter] (>=0.44.0)
25
27
  Requires-Dist: pyvistaqt (>=0.11.1,<0.12.0)
28
+ Requires-Dist: vtk (<9.4.0) ; python_version < "3.13"
26
29
  Project-URL: Documentation, https://visualization.fluent.docs.pyansys.com/
27
30
  Project-URL: Repository, https://github.com/ansys/pyfluent-visualization
28
31
  Project-URL: Source, https://github.com/ansys/pyfluent-visualization
@@ -82,7 +85,7 @@ the project support team, email `pyansys.core@ansys.com <pyansys.core@ansys.com>
82
85
  Installation
83
86
  ------------
84
87
  The ``ansys-fluent-visualization`` package supports Python 3.10 through Python
85
- 3.12 on Windows and Linux.
88
+ 3.13 on Windows and Linux.
86
89
 
87
90
  If you are using Python 3.10, download and install the wheel file for the ``vtk`` package from
88
91
  `here for Windows <https://github.com/pyvista/pyvista-wheels/raw/main/vtk-9.1.0.dev0-cp310-cp310-win_amd64.whl>`_
@@ -51,7 +51,7 @@ the project support team, email `pyansys.core@ansys.com <pyansys.core@ansys.com>
51
51
  Installation
52
52
  ------------
53
53
  The ``ansys-fluent-visualization`` package supports Python 3.10 through Python
54
- 3.12 on Windows and Linux.
54
+ 3.13 on Windows and Linux.
55
55
 
56
56
  If you are using Python 3.10, download and install the wheel file for the ``vtk`` package from
57
57
  `here for Windows <https://github.com/pyvista/pyvista-wheels/raw/main/vtk-9.1.0.dev0-cp310-cp310-win_amd64.whl>`_
@@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api"
5
5
  [tool.poetry]
6
6
  # Check https://python-poetry.org/docs/pyproject/ for all available sections
7
7
  name = "ansys-fluent-visualization"
8
- version = "0.16.dev0"
8
+ version = "0.17.dev0"
9
9
  description = "A python wrapper for ansys Fluent visualization"
10
10
  license = "MIT"
11
11
  authors = ["ANSYS, Inc. <ansys.support@ansys.com>"]
@@ -25,11 +25,14 @@ packages = [
25
25
  [tool.poetry.dependencies]
26
26
  python = ">=3.10,<4.0"
27
27
  importlib-metadata = {version = "^4.0", python = "<3.9"}
28
- ansys-fluent-core = "~=0.28.dev0"
29
- pyvista = "~=0.44.1"
28
+ ansys-fluent-core = "~=0.29.dev0"
29
+ pyvista = { version = ">=0.44.0", extras = ["jupyter"]}
30
+ matplotlib = ">=3.6.0"
31
+ vtk = {version = "<9.4.0", python = "<3.13"}
30
32
  pyvistaqt = "~=0.11.1"
31
- pyside6 = "~=6.7.2"
32
- matplotlib = ">=3.9.0"
33
+ pyside6 = "~=6.8.1"
34
+ plotly = ">=5.24.0"
35
+ imageio= ">=2.36.1"
33
36
 
34
37
  [tool.poetry.urls]
35
38
  "Documentation" = "https://visualization.fluent.docs.pyansys.com/"
@@ -5,9 +5,10 @@ try:
5
5
  except ModuleNotFoundError:
6
6
  import importlib_metadata
7
7
 
8
- _VERSION_INFO = "Build date: November 28, 2024 14:47 UTC ShaID: 463438b"
8
+ _VERSION_INFO = "Build date: January 06, 2025 09:12 UTC ShaID: a7bfb72"
9
9
  __version__ = importlib_metadata.version(__name__.replace(".", "-"))
10
10
  PLOTTER = "matplotlib"
11
+ INTERACTIVE = False
11
12
 
12
13
 
13
14
  def version_info() -> str:
@@ -11,10 +11,13 @@ def get_config() -> dict:
11
11
  config : dict
12
12
  Keys are parameter names that can be passed to :func:`set_config`.
13
13
  """
14
+ import ansys.fluent.visualization as pyviz
15
+
16
+ _global_config["blocking"] = not pyviz.INTERACTIVE
14
17
  return _global_config.copy()
15
18
 
16
19
 
17
- def set_config(blocking: bool = True, set_view_on_display: str = "isometric"):
20
+ def set_config(blocking: bool = False, set_view_on_display: str = "isometric"):
18
21
  """Set visualization configuration.
19
22
 
20
23
  Parameters
@@ -1,6 +1,8 @@
1
1
  """A wrapper to improve the user interface of graphics."""
2
2
 
3
+ from ansys.fluent.visualization import get_config
3
4
  from ansys.fluent.visualization.graphics import graphics_windows_manager
5
+ from ansys.fluent.visualization.plotter.plotter_windows import PlotterWindow
4
6
 
5
7
 
6
8
  class GraphicsWindow:
@@ -14,6 +16,7 @@ class GraphicsWindow:
14
16
  object,
15
17
  position: tuple = (0, 0),
16
18
  opacity: float = 1,
19
+ title: str = "",
17
20
  ) -> None:
18
21
  """Add data to a plot.
19
22
 
@@ -25,27 +28,43 @@ class GraphicsWindow:
25
28
  Position of the sub-plot.
26
29
  opacity: float, optional
27
30
  Transparency of the sub-plot.
31
+ title: str, optional
32
+ Title of the sub-plot (only for plots).
28
33
  """
29
34
  self._graphics_objs.append({**locals()})
30
35
 
36
+ def _all_plt_objs(self):
37
+ from ansys.fluent.core.post_objects.post_object_definitions import PlotDefn
38
+
39
+ for obj in self._graphics_objs:
40
+ if not isinstance(obj["object"].obj, PlotDefn):
41
+ return False
42
+ return True
43
+
31
44
  def show(self) -> None:
32
45
  """Render the objects in window and display the same."""
33
46
  self.window_id = graphics_windows_manager.open_window(grid=self._grid)
34
- self.graphics_window = graphics_windows_manager._post_windows.get(
35
- self.window_id
36
- )
37
- self._renderer = self.graphics_window.renderer
38
- self.plotter = self.graphics_window.renderer.plotter
39
- for i in range(len(self._graphics_objs)):
40
- graphics_windows_manager.add_graphics(
41
- object=self._graphics_objs[i]["object"].obj,
42
- window_id=self.window_id,
43
- fetch_data=True,
44
- overlay=True,
45
- position=self._graphics_objs[i]["position"],
46
- opacity=self._graphics_objs[i]["opacity"],
47
+ if self._all_plt_objs() and get_config()["blocking"]:
48
+ p = PlotterWindow(grid=self._grid)
49
+ for obj in self._graphics_objs:
50
+ p.add_plots(obj["object"], position=obj["position"], title=obj["title"])
51
+ p.show(self.window_id)
52
+ else:
53
+ self.graphics_window = graphics_windows_manager._post_windows.get(
54
+ self.window_id
47
55
  )
48
- graphics_windows_manager.show_graphics(self.window_id)
56
+ self._renderer = self.graphics_window.renderer
57
+ self.plotter = self.graphics_window.renderer.plotter
58
+ for i in range(len(self._graphics_objs)):
59
+ graphics_windows_manager.add_graphics(
60
+ object=self._graphics_objs[i]["object"].obj,
61
+ window_id=self.window_id,
62
+ fetch_data=True,
63
+ overlay=True,
64
+ position=self._graphics_objs[i]["position"],
65
+ opacity=self._graphics_objs[i]["opacity"],
66
+ )
67
+ graphics_windows_manager.show_graphics(self.window_id)
49
68
 
50
69
  def save_graphic(
51
70
  self,
@@ -2,19 +2,30 @@
2
2
 
3
3
  from enum import Enum
4
4
  import itertools
5
+ import os
5
6
  import threading
6
7
  from typing import Dict, List, Optional, Union
7
8
 
8
9
  from ansys.fluent.core.fluent_connection import FluentConnection
9
10
  from ansys.fluent.core.post_objects.check_in_notebook import in_notebook
10
- from ansys.fluent.core.post_objects.post_object_definitions import GraphicsDefn
11
+ from ansys.fluent.core.post_objects.post_object_definitions import (
12
+ GraphicsDefn,
13
+ PlotDefn,
14
+ )
11
15
  from ansys.fluent.core.post_objects.singleton_meta import AbstractSingletonMeta
12
16
  import numpy as np
13
17
  import pyvista as pv
14
- from pyvistaqt import BackgroundPlotter
18
+
19
+ try:
20
+ from pyvistaqt import BackgroundPlotter
21
+ except ModuleNotFoundError:
22
+ BackgroundPlotter = None
15
23
 
16
24
  from ansys.fluent.visualization import get_config
17
- from ansys.fluent.visualization.post_data_extractor import FieldDataExtractor
25
+ from ansys.fluent.visualization.post_data_extractor import (
26
+ FieldDataExtractor,
27
+ XYPlotDataExtractor,
28
+ )
18
29
  from ansys.fluent.visualization.post_windows_manager import (
19
30
  PostWindow,
20
31
  PostWindowsManager,
@@ -74,6 +85,10 @@ class GraphicsWindow(PostWindow):
74
85
  obj = self.post_object
75
86
  if obj.__class__.__name__ == "Surface":
76
87
  self._fetch_surface(obj)
88
+ elif obj.__class__.__name__ == "XYPlot":
89
+ self._fetch_xy_data(obj)
90
+ elif obj.__class__.__name__ == "MonitorPlot":
91
+ self._fetch_monitor_data(obj)
77
92
  else:
78
93
  self._fetch_data(obj, FieldDataType(obj.__class__.__name__))
79
94
 
@@ -106,6 +121,10 @@ class GraphicsWindow(PostWindow):
106
121
  self._display_vector(obj, position, opacity)
107
122
  elif obj.__class__.__name__ == "Pathlines":
108
123
  self._display_pathlines(obj, position, opacity)
124
+ elif obj.__class__.__name__ == "XYPlot":
125
+ self._display_xy_plot(position, opacity)
126
+ elif obj.__class__.__name__ == "MonitorPlot":
127
+ self._display_monitor_plot(position, opacity)
109
128
  if self.animate:
110
129
  self.renderer.write_frame()
111
130
  self.renderer._set_camera(get_config()["set_view_on_display"])
@@ -162,6 +181,31 @@ class GraphicsWindow(PostWindow):
162
181
  def _fetch_surface(self, obj):
163
182
  self._fetch_or_display_surface(obj, fetch=True)
164
183
 
184
+ def _fetch_xy_data(self, obj):
185
+ self._data["XYPlot"] = XYPlotDataExtractor(obj).fetch_data()
186
+ self._data["XYPlot"]["properties"] = {
187
+ "curves": list(self._data["XYPlot"]),
188
+ "title": "XY Plot",
189
+ "xlabel": "position",
190
+ "ylabel": obj.y_axis_function(),
191
+ }
192
+
193
+ def _fetch_monitor_data(self, obj):
194
+ monitors = obj._api_helper.monitors
195
+ indices, columns_data = monitors.get_monitor_set_data(obj.monitor_set_name())
196
+ xy_data = {}
197
+ for column_name, column_data in columns_data.items():
198
+ xy_data[column_name] = {"xvalues": indices, "yvalues": column_data}
199
+ monitor_set_name = obj.monitor_set_name()
200
+ self._data["MonitorPlot"] = xy_data
201
+ self._data["MonitorPlot"]["properties"] = {
202
+ "curves": list(xy_data.keys()),
203
+ "title": monitor_set_name,
204
+ "xlabel": monitors.get_monitor_set_prop(monitor_set_name, "xlabel"),
205
+ "ylabel": monitors.get_monitor_set_prop(monitor_set_name, "ylabel"),
206
+ "yscale": "log" if monitor_set_name == "residual" else "linear",
207
+ }
208
+
165
209
  def _resolve_mesh_data(self, mesh_data):
166
210
  topology = "line" if mesh_data["faces"][0] == 2 else "face"
167
211
  if topology == "line":
@@ -412,6 +456,18 @@ class GraphicsWindow(PostWindow):
412
456
  opacity=opacity,
413
457
  )
414
458
 
459
+ def _display_xy_plot(self, position=(0, 0), opacity=1):
460
+ self.renderer.render(
461
+ self._data["XYPlot"],
462
+ position=position,
463
+ )
464
+
465
+ def _display_monitor_plot(self, position=(0, 0), opacity=1):
466
+ self.renderer.render(
467
+ self._data["MonitorPlot"],
468
+ position=position,
469
+ )
470
+
415
471
  def _get_refresh_for_plotter(self, window: "GraphicsWindow"):
416
472
  def refresh():
417
473
  with GraphicsWindowsManager._condition:
@@ -498,7 +554,11 @@ class GraphicsWindowsManager(PostWindowsManager, metaclass=AbstractSingletonMeta
498
554
  with self._condition:
499
555
  if not window_id:
500
556
  window_id = self._get_unique_window_id()
501
- if in_notebook() or get_config()["blocking"]:
557
+ if (
558
+ in_notebook()
559
+ or get_config()["blocking"]
560
+ or os.getenv("FLUENT_PROD_DIR")
561
+ ):
502
562
  self._open_window_notebook(window_id, grid)
503
563
  else:
504
564
  self._open_and_plot_console(None, window_id, grid=grid)
@@ -552,12 +612,16 @@ class GraphicsWindowsManager(PostWindowsManager, metaclass=AbstractSingletonMeta
552
612
  RuntimeError
553
613
  If the window does not support the object.
554
614
  """
555
- if not isinstance(object, GraphicsDefn):
615
+ if not isinstance(object, (GraphicsDefn, PlotDefn)):
556
616
  raise RuntimeError("Object type currently not supported.")
557
617
  with self._condition:
558
618
  if not window_id:
559
619
  window_id = self._get_unique_window_id()
560
- if in_notebook() or get_config()["blocking"]:
620
+ if (
621
+ in_notebook()
622
+ or get_config()["blocking"]
623
+ or os.getenv("FLUENT_PROD_DIR")
624
+ ):
561
625
  self._plot_notebook(object, window_id, fetch_data, overlay)
562
626
  else:
563
627
  self._open_and_plot_console(object, window_id, fetch_data, overlay)
@@ -593,10 +657,14 @@ class GraphicsWindowsManager(PostWindowsManager, metaclass=AbstractSingletonMeta
593
657
  RuntimeError
594
658
  If the window does not support the object.
595
659
  """
596
- if not isinstance(object, GraphicsDefn):
660
+ if not isinstance(object, (GraphicsDefn, PlotDefn)):
597
661
  raise RuntimeError("Object type currently not supported.")
598
662
  with self._condition:
599
- if in_notebook() or get_config()["blocking"]:
663
+ if (
664
+ in_notebook()
665
+ or get_config()["blocking"]
666
+ or os.getenv("FLUENT_PROD_DIR")
667
+ ):
600
668
  self._add_graphics_in_notebook(
601
669
  object, window_id, fetch_data, overlay, position, opacity
602
670
  )
@@ -608,7 +676,11 @@ class GraphicsWindowsManager(PostWindowsManager, metaclass=AbstractSingletonMeta
608
676
  def show_graphics(self, window_id: str):
609
677
  """Display the graphics window."""
610
678
  with self._condition:
611
- if in_notebook() or get_config()["blocking"]:
679
+ if (
680
+ in_notebook()
681
+ or get_config()["blocking"]
682
+ or os.getenv("FLUENT_PROD_DIR")
683
+ ):
612
684
  self._show_graphics_in_notebook(window_id)
613
685
 
614
686
  def save_graphic(
@@ -1,7 +1,12 @@
1
1
  """Module for pyVista windows management."""
2
2
 
3
+ import numpy as np
3
4
  import pyvista as pv
4
- from pyvistaqt import BackgroundPlotter
5
+
6
+ try:
7
+ from pyvistaqt import BackgroundPlotter
8
+ except ModuleNotFoundError:
9
+ BackgroundPlotter = None
5
10
 
6
11
  from ansys.fluent.visualization.graphics.abstract_graphics_defns import AbstractRenderer
7
12
 
@@ -14,7 +19,7 @@ class Renderer(AbstractRenderer):
14
19
  non_interactive: bool,
15
20
  grid: tuple | None = (1, 1),
16
21
  ):
17
- self.plotter: Union[BackgroundPlotter, pv.Plotter] = (
22
+ self.plotter: BackgroundPlotter | pv.Plotter = (
18
23
  pv.Plotter(title=f"PyFluent ({win_id})", shape=grid)
19
24
  if in_notebook or non_interactive
20
25
  else BackgroundPlotter(title=f"PyFluent ({win_id})", shape=grid)
@@ -59,7 +64,7 @@ class Renderer(AbstractRenderer):
59
64
 
60
65
  def _clear_plotter(self, in_notebook):
61
66
  if in_notebook and self.plotter.theme._jupyter_backend == "pythreejs":
62
- self.plotter.remove_actor(plotter.renderer.actors.copy())
67
+ self.plotter.remove_actor(self.plotter.renderer.actors.copy())
63
68
  else:
64
69
  self.plotter.clear()
65
70
 
@@ -83,13 +88,68 @@ class Renderer(AbstractRenderer):
83
88
 
84
89
  Parameters
85
90
  ----------
86
- mesh : pyvista.DataSet
91
+ mesh : pyvista.DataSet | dict
87
92
  Any PyVista or VTK mesh is supported.
88
93
  """
89
94
  if "position" in kwargs:
90
95
  self.plotter.subplot(kwargs["position"][0], kwargs["position"][1])
91
96
  del kwargs["position"]
92
- self.plotter.add_mesh(mesh, **kwargs)
97
+ if isinstance(mesh, pv.DataSet):
98
+ self.plotter.add_mesh(mesh, **kwargs)
99
+ else:
100
+ y_range = None
101
+ chart = pv.Chart2D()
102
+ chart.title = mesh["properties"].get("title") or ""
103
+ chart.x_label = mesh["properties"].get("xlabel") or ""
104
+ chart.y_label = mesh["properties"].get("ylabel") or ""
105
+ if mesh["properties"].get("yscale") == "log":
106
+ chart.y_axis.log_scale = True
107
+ y_range = 0
108
+ del mesh["properties"]
109
+
110
+ color_list = ["b", "r", "g", "c", "m", "y", "k"]
111
+ style_list = ["-", "--", "-.", "-.."]
112
+
113
+ min_y_value = max_y_value = min_x_value = max_x_value = None
114
+ for count, curve in enumerate(mesh):
115
+ chart.line(
116
+ mesh[curve]["xvalues"].tolist(),
117
+ mesh[curve]["yvalues"].tolist(),
118
+ width=2.5,
119
+ color=color_list[count % len(color_list)],
120
+ style=style_list[count % len(style_list)],
121
+ label=curve,
122
+ )
123
+ min_y_value = (
124
+ min(np.amin(mesh[curve]["yvalues"]), min_y_value)
125
+ if min_y_value
126
+ else np.amin(mesh[curve]["yvalues"])
127
+ )
128
+ max_y_value = (
129
+ max(np.amax(mesh[curve]["yvalues"]), max_y_value)
130
+ if max_y_value
131
+ else np.amax(mesh[curve]["yvalues"])
132
+ )
133
+ min_x_value = (
134
+ min(np.amin(mesh[curve]["xvalues"]), min_x_value)
135
+ if min_x_value
136
+ else np.amin(mesh[curve]["xvalues"])
137
+ )
138
+ max_x_value = (
139
+ max(np.amax(mesh[curve]["xvalues"]), max_x_value)
140
+ if max_x_value
141
+ else np.amax(mesh[curve]["xvalues"])
142
+ )
143
+ if min_x_value and max_x_value:
144
+ chart.x_range = [min_x_value, max_x_value]
145
+ if min_y_value and max_y_value:
146
+ if y_range is None:
147
+ y_range = max_y_value - min_y_value
148
+ chart.y_range = [
149
+ min_y_value - y_range * 0.2,
150
+ max_y_value + y_range * 0.2,
151
+ ]
152
+ self.plotter.add_chart(chart, **kwargs)
93
153
 
94
154
  def save_graphic(self, file_name: str):
95
155
  """Save graphics to the specified file.
@@ -57,7 +57,21 @@ class Plotter(AbstractPlotter):
57
57
  self._remote_process = remote_process
58
58
  self.fig = None
59
59
 
60
- def plot(self, data: dict, grid=(1, 1), position=0, show=True) -> None:
60
+ @staticmethod
61
+ def _compute_position(position: tuple) -> int:
62
+ x = position[0]
63
+ y = position[1]
64
+ if x == y == 0:
65
+ ret = 0
66
+ elif x < y:
67
+ ret = x + y
68
+ else:
69
+ ret = x + y + 1
70
+ return ret
71
+
72
+ def plot(
73
+ self, data: dict, grid=(1, 1), position=0, show=True, subplot_titles=[]
74
+ ) -> None:
61
75
  """Draw plot in window.
62
76
 
63
77
  Parameters
@@ -82,7 +96,10 @@ class Plotter(AbstractPlotter):
82
96
 
83
97
  if not self._remote_process:
84
98
  self.fig = plt.figure(num=self._window_id)
85
- self.ax = self.fig.add_subplot(grid[0], grid[1], position + 1)
99
+
100
+ self.ax = self.fig.add_subplot(
101
+ grid[0], grid[1], self._compute_position(position) + 1
102
+ )
86
103
  if self._yscale:
87
104
  self.ax.set_yscale(self._yscale)
88
105
  self.fig.canvas.manager.set_window_title("PyFluent [" + self._window_id + "]")
@@ -0,0 +1,176 @@
1
+ import numpy as np
2
+ import plotly.graph_objects as go
3
+ from plotly.subplots import make_subplots
4
+
5
+ from ansys.fluent.visualization.plotter.abstract_plotter_defns import AbstractPlotter
6
+
7
+
8
+ class Plotter(AbstractPlotter):
9
+ """Class for matplotlib plotter."""
10
+
11
+ def __init__(
12
+ self,
13
+ window_id: str,
14
+ curves: list[str] | None = None,
15
+ title: str | None = "XY Plot",
16
+ xlabel: str | None = "position",
17
+ ylabel: str | None = "",
18
+ remote_process: bool | None = False,
19
+ ):
20
+ """Instantiate a matplotlib plotter.
21
+
22
+ Parameters
23
+ ----------
24
+ window_id : str
25
+ Window id.
26
+ curves : List[str], optional
27
+ List of curves name.
28
+ title : str, optional
29
+ Plot title.
30
+ xlabel : str, optional
31
+ X axis label.
32
+ ylabel : str, optional
33
+ Y axis label.
34
+ figure : str, optional
35
+ Matplot lib figure.
36
+ axis : str, optional
37
+ Subplot indices.
38
+ remote_process: bool, optional
39
+ Is remote process.
40
+ """
41
+ self._curves = [] if curves is None else curves
42
+ self._title = title
43
+ self._xlabel = xlabel
44
+ self._ylabel = ylabel
45
+ self._window_id = window_id
46
+ self._min_y = None
47
+ self._max_y = None
48
+ self._min_x = None
49
+ self._max_x = None
50
+ self._yscale = None
51
+ self._data = {}
52
+ self._closed = False
53
+ self._visible = False
54
+ self._remote_process = remote_process
55
+ self.fig = None
56
+
57
+ def plot(
58
+ self, data: dict, grid=(1, 1), position=(0, 0), show=True, subplot_titles=[]
59
+ ) -> None:
60
+ """Draw plot in window.
61
+
62
+ Parameters
63
+ ----------
64
+ data : dict
65
+ Data to plot. Data consists the list of x and y
66
+ values for each curve.
67
+ """
68
+ if not data:
69
+ return
70
+ for curve in data:
71
+ if curve not in self._data:
72
+ self._data[curve] = {}
73
+ min_y_value = np.amin(data[curve]["yvalues"])
74
+ max_y_value = np.amax(data[curve]["yvalues"])
75
+ min_x_value = np.amin(data[curve]["xvalues"])
76
+ max_x_value = np.amax(data[curve]["xvalues"])
77
+ self._data[curve]["xvalues"] = data[curve]["xvalues"].tolist()
78
+ self._data[curve]["yvalues"] = data[curve]["yvalues"].tolist()
79
+ self._min_y = min(self._min_y, min_y_value) if self._min_y else min_y_value
80
+ self._max_y = max(self._max_y, max_y_value) if self._max_y else max_y_value
81
+ self._min_x = min(self._min_x, min_x_value) if self._min_x else min_x_value
82
+ self._max_x = max(self._max_x, max_x_value) if self._max_x else max_x_value
83
+
84
+ if not self._remote_process:
85
+ if not self.fig:
86
+ self.fig = make_subplots(
87
+ rows=grid[0], cols=grid[1], subplot_titles=subplot_titles
88
+ )
89
+ for curve in self._curves:
90
+ self.fig.add_trace(
91
+ go.Scatter(
92
+ x=self._data[curve]["xvalues"],
93
+ y=self._data[curve]["yvalues"],
94
+ mode="lines",
95
+ name=curve,
96
+ ),
97
+ row=position[0] + 1,
98
+ col=position[1] + 1,
99
+ )
100
+ self.fig.update_yaxes(
101
+ title_text=self._ylabel,
102
+ type=self._yscale if self._yscale else "linear",
103
+ row=position[0] + 1,
104
+ col=position[1] + 1,
105
+ )
106
+ self.fig.update_xaxes(
107
+ title_text=self._xlabel, row=position[0] + 1, col=position[1] + 1
108
+ )
109
+
110
+ if show:
111
+ if not self._visible:
112
+ self._visible = True
113
+ self.fig.show()
114
+
115
+ def show(self):
116
+ if not self._visible:
117
+ self._visible = True
118
+ self.fig.show()
119
+
120
+ def close(self):
121
+ """Close window."""
122
+ del self.fig
123
+ self._closed = True
124
+
125
+ def is_closed(self):
126
+ """Check if window is closed."""
127
+ return self._closed
128
+
129
+ def save_graphic(self, file_name: str):
130
+ """Save graphics (static image (e.g., PNG, JPEG, PDF, SVG)).
131
+
132
+ Please note:
133
+ This requires the kaleido package.
134
+
135
+ >>> pip install kaleido
136
+
137
+ Parameters
138
+ ----------
139
+ file_name : str
140
+ File name to save graphic.
141
+ """
142
+ self.fig.write_image(file_name)
143
+
144
+ def set_properties(self, properties: dict):
145
+ """Set plot properties.
146
+
147
+ Parameters
148
+ ----------
149
+ properties : dict
150
+ Plot properties i.e. curves, title, xlabel and ylabel.
151
+ """
152
+ self._curves = properties.get("curves", self._curves)
153
+ self._title = properties.get("title", self._title)
154
+ self._xlabel = properties.get("xlabel", self._xlabel)
155
+ self._ylabel = properties.get("ylabel", self._ylabel)
156
+ self._yscale = properties.get("yscale", self._yscale)
157
+ self._data = {}
158
+ self._min_y = None
159
+ self._max_y = None
160
+ self._min_x = None
161
+ self._max_x = None
162
+ self._reset()
163
+
164
+ def __call__(self):
165
+ """Reset and show plot."""
166
+ self._reset()
167
+ self._visible = False
168
+
169
+ # private methods
170
+ def _reset(self):
171
+ for curve_name in self._curves:
172
+ self._data[curve_name] = {}
173
+ self._data[curve_name]["xvalues"] = []
174
+ self._data[curve_name]["yvalues"] = []
175
+ if not self.fig:
176
+ return
@@ -5,9 +5,10 @@ class PlotterWindow:
5
5
  def __init__(self, grid: tuple = (1, 1)):
6
6
  self._grid = grid
7
7
  self._plot_objs = []
8
+ self._subplot_titles = []
8
9
  self.window_id = None
9
10
 
10
- def add_plots(self, object, position: tuple = (0, 0)) -> None:
11
+ def add_plots(self, object, position: tuple = (0, 0), title: str = "") -> None:
11
12
  """Add data to a plot.
12
13
 
13
14
  Parameters
@@ -16,24 +17,20 @@ class PlotterWindow:
16
17
  Object to plot as a sub-plot.
17
18
  position: tuple, optional
18
19
  Position of the sub-plot.
20
+ title: str, optional
21
+ Title of the sub-plot.
19
22
  """
20
23
  self._plot_objs.append({**locals()})
21
-
22
- def _compute_position(self, position: tuple):
23
- x = position[0]
24
- y = position[1]
25
- ret = 0
26
- if x == y == 0:
27
- ret = 0
28
- elif x < y:
29
- ret = x + y
24
+ if title:
25
+ self._subplot_titles.append(title)
26
+ elif hasattr(object.obj, "monitor_set_name"):
27
+ self._subplot_titles.append(object.obj.monitor_set_name())
30
28
  else:
31
- ret = x + y + 1
32
- return ret
29
+ self._subplot_titles.append("XYPlot")
33
30
 
34
- def show(self) -> None:
31
+ def show(self, win_id=None) -> None:
35
32
  """Render the objects in window and display the same."""
36
- self.window_id = plotter_windows_manager.open_window()
33
+ self.window_id = plotter_windows_manager.open_window(window_id=win_id)
37
34
  self.plotter_window = plotter_windows_manager._post_windows.get(self.window_id)
38
35
  self.plotter = self.plotter_window.plotter
39
36
  for i in range(len(self._plot_objs)):
@@ -41,7 +38,8 @@ class PlotterWindow:
41
38
  object=self._plot_objs[i]["object"].obj,
42
39
  window_id=self.window_id,
43
40
  grid=self._grid,
44
- position=self._compute_position(self._plot_objs[i]["position"]),
41
+ position=self._plot_objs[i]["position"],
42
+ subplot_titles=self._subplot_titles,
45
43
  show=False,
46
44
  )
47
45
  plotter_windows_manager.show_plots(window_id=self.window_id)
@@ -13,13 +13,7 @@ from ansys.fluent.core.post_objects.post_object_definitions import (
13
13
  )
14
14
  from ansys.fluent.core.post_objects.singleton_meta import AbstractSingletonMeta
15
15
 
16
- from ansys.fluent.visualization import PLOTTER, get_config
17
-
18
- if PLOTTER == "matplotlib":
19
- from ansys.fluent.visualization.plotter.matplotlib.plotter_defns import Plotter
20
- else:
21
- from ansys.fluent.visualization.plotter.pyvista.plotter_defns import Plotter
22
-
16
+ from ansys.fluent.visualization import get_config
23
17
  from ansys.fluent.visualization.plotter.matplotlib.plotter_defns import ProcessPlotter
24
18
  from ansys.fluent.visualization.post_data_extractor import XYPlotDataExtractor
25
19
  from ansys.fluent.visualization.post_windows_manager import (
@@ -48,7 +42,7 @@ class _ProcessPlotterHandle:
48
42
  self.plot_process.start()
49
43
  FluentConnection._monitor_thread.cbs.append(self.close)
50
44
 
51
- def plot(self, data, grid=(1, 1), position=0, show=True):
45
+ def plot(self, data, grid=(1, 1), position=0, show=True, subplot_titles=[]):
52
46
  self.plot_pipe.send(
53
47
  {"data": data, "grid": grid, "position": position, "show": show}
54
48
  )
@@ -96,11 +90,11 @@ class PlotterWindow(PostWindow):
96
90
  """
97
91
  self.id: str = id
98
92
  self.post_object = None
99
- self.plotter: Union[_ProcessPlotterHandle, Plotter] = self._get_plotter()
93
+ self.plotter: Union[_ProcessPlotterHandle, "Plotter"] = self._get_plotter()
100
94
  self.close: bool = False
101
95
  self.refresh: bool = False
102
96
 
103
- def plot(self, grid=(1, 1), position=0, show=True):
97
+ def plot(self, grid=(1, 1), position=(0, 0), show=True, subplot_titles=[]):
104
98
  """Draw a plot."""
105
99
  if self.post_object is not None:
106
100
  plot = (
@@ -108,13 +102,23 @@ class PlotterWindow(PostWindow):
108
102
  if self.post_object.__class__.__name__ == "XYPlot"
109
103
  else _MonitorPlot(self.post_object, self.plotter)
110
104
  )
111
- plot(grid=grid, position=position, show=show)
105
+ plot(grid=grid, position=position, show=show, subplot_titles=subplot_titles)
112
106
 
113
107
  def _show_plot(self):
114
108
  self.plotter.show()
115
109
 
116
110
  # private methods
117
111
  def _get_plotter(self):
112
+ import ansys.fluent.visualization as pyviz
113
+
114
+ if pyviz.PLOTTER == "matplotlib":
115
+ from ansys.fluent.visualization.plotter.matplotlib.plotter_defns import (
116
+ Plotter,
117
+ )
118
+ elif pyviz.PLOTTER == "plotly":
119
+ from ansys.fluent.visualization.plotter.plotly.plotter_defns import Plotter
120
+ else:
121
+ from ansys.fluent.visualization.plotter.pyvista.plotter_defns import Plotter
118
122
  return (
119
123
  Plotter(self.id)
120
124
  if in_notebook() or get_config()["blocking"]
@@ -126,7 +130,7 @@ class _XYPlot:
126
130
  """Provides for drawing an XY plot."""
127
131
 
128
132
  def __init__(
129
- self, post_object: XYPlotDefn, plotter: Union[_ProcessPlotterHandle, Plotter]
133
+ self, post_object: XYPlotDefn, plotter: Union[_ProcessPlotterHandle, "Plotter"]
130
134
  ):
131
135
  """Instantiate an XY plot.
132
136
 
@@ -138,9 +142,9 @@ class _XYPlot:
138
142
  Plotter to plot the data.
139
143
  """
140
144
  self.post_object: XYPlotDefn = post_object
141
- self.plotter: Union[_ProcessPlotterHandle, Plotter] = plotter
145
+ self.plotter: Union[_ProcessPlotterHandle, "Plotter"] = plotter
142
146
 
143
- def __call__(self, grid=(1, 1), position=0, show=True):
147
+ def __call__(self, grid=(1, 1), position=0, show=True, subplot_titles=[]):
144
148
  """Draw an XY plot."""
145
149
  if not self.post_object:
146
150
  return
@@ -157,18 +161,24 @@ class _XYPlot:
157
161
  try:
158
162
  self.plotter.set_properties(properties)
159
163
  except BrokenPipeError:
160
- self.plotter: Union[_ProcessPlotterHandle, Plotter] = (
164
+ self.plotter: Union[_ProcessPlotterHandle, "Plotter"] = (
161
165
  self._get_plotter()
162
166
  )
163
167
  self.plotter.set_properties(properties)
164
- self.plotter.plot(xy_data, grid=grid, position=position, show=show)
168
+ self.plotter.plot(
169
+ xy_data,
170
+ grid=grid,
171
+ position=position,
172
+ show=show,
173
+ subplot_titles=subplot_titles,
174
+ )
165
175
 
166
176
 
167
177
  class _MonitorPlot:
168
178
  """Provides for drawing monitor plots."""
169
179
 
170
180
  def __init__(
171
- self, post_object: MonitorDefn, plotter: Union[_ProcessPlotterHandle, Plotter]
181
+ self, post_object: MonitorDefn, plotter: Union[_ProcessPlotterHandle, "Plotter"]
172
182
  ):
173
183
  """Instantiate a monitor plot.
174
184
 
@@ -180,9 +190,9 @@ class _MonitorPlot:
180
190
  Plotter to plot the data.
181
191
  """
182
192
  self.post_object: MonitorDefn = post_object
183
- self.plotter: Union[_ProcessPlotterHandle, Plotter] = plotter
193
+ self.plotter: Union[_ProcessPlotterHandle, "Plotter"] = plotter
184
194
 
185
- def __call__(self, grid=(1, 1), position=(0, 0), show=True):
195
+ def __call__(self, grid=(1, 1), position=(0, 0), show=True, subplot_titles=[]):
186
196
  """Draw a monitor plot."""
187
197
  if not self.post_object:
188
198
  return
@@ -208,12 +218,18 @@ class _MonitorPlot:
208
218
  try:
209
219
  self.plotter.set_properties(properties)
210
220
  except BrokenPipeError:
211
- self.plotter: Union[_ProcessPlotterHandle, Plotter] = (
221
+ self.plotter: Union[_ProcessPlotterHandle, "Plotter"] = (
212
222
  self._get_plotter()
213
223
  )
214
224
  self.plotter.set_properties(properties)
215
225
  if xy_data:
216
- self.plotter.plot(xy_data, grid=grid, position=position, show=show)
226
+ self.plotter.plot(
227
+ xy_data,
228
+ grid=grid,
229
+ position=position,
230
+ show=show,
231
+ subplot_titles=subplot_titles,
232
+ )
217
233
 
218
234
 
219
235
  class PlotterWindowsManager(PostWindowsManager, metaclass=AbstractSingletonMeta):
@@ -268,7 +284,8 @@ class PlotterWindowsManager(PostWindowsManager, metaclass=AbstractSingletonMeta)
268
284
  object: PlotDefn,
269
285
  window_id: Optional[str] = None,
270
286
  grid=(1, 1),
271
- position=0,
287
+ position=(0, 0),
288
+ subplot_titles=[],
272
289
  show=True,
273
290
  ) -> None:
274
291
  """Draw a plot.
@@ -292,7 +309,9 @@ class PlotterWindowsManager(PostWindowsManager, metaclass=AbstractSingletonMeta)
292
309
  window_id = self._get_unique_window_id()
293
310
  window = self._open_window(window_id)
294
311
  window.post_object = object
295
- window.plot(grid=grid, position=position, show=show)
312
+ window.plot(
313
+ grid=grid, position=position, show=show, subplot_titles=subplot_titles
314
+ )
296
315
 
297
316
  def show_plots(self, window_id: str):
298
317
  window = self._open_window(window_id)
@@ -395,14 +414,11 @@ class PlotterWindowsManager(PostWindowsManager, metaclass=AbstractSingletonMeta)
395
414
 
396
415
  # private methods
397
416
 
398
- def _open_window(self, window_id: str) -> Union[Plotter, _ProcessPlotterHandle]:
417
+ def _open_window(self, window_id: str) -> Union["Plotter", _ProcessPlotterHandle]:
399
418
  window = self._post_windows.get(window_id)
400
- if (
401
- window
402
- and not window.plotter.is_closed()
403
- and (not (in_notebook() or get_config()["blocking"]) or window.refresh)
404
- ):
405
- window.refresh = False
419
+ if window and not window.plotter.is_closed():
420
+ if not (in_notebook() or get_config()["blocking"]) or window.refresh:
421
+ window.refresh = False
406
422
  else:
407
423
  window = PlotterWindow(window_id, None)
408
424
  self._post_windows[window_id] = window