Repository: pyvista/pyvista

Issue:
add SetEdgeOpacity
### Describe the feature you would like to be added.

Is it possible to add `SetEdgeOpacity` ?

### Links to VTK Documentation, Examples, or Class Definitions.

https://vtk.org/doc/nightly/html/classvtkProperty.html#abe49ba1d9dfb86de9201fe6d5b16f4be



Discussion:
tkoyama010: pre-commit.ci autofix
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/pyvista/pyvista/pull/5192?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pyvista) Report
> Merging [#5192](https://app.codecov.io/gh/pyvista/pyvista/pull/5192?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pyvista) (2dcd941) into [main](https://app.codecov.io/gh/pyvista/pyvista/commit/5a8ace755fced445d54fbf06c1a9016563a44090?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pyvista) (5a8ace7) will **decrease** coverage by `7.11%`.
> The diff coverage is `86.66%`.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #5192      +/-   ##
==========================================
- Coverage   96.06%   88.95%   -7.11%     
==========================================
  Files         131      131              
  Lines       21872    21887      +15     
==========================================
- Hits        21011    19470    -1541     
- Misses        861     2417    +1556     
```

</details>
github-actions[bot]: <!-- NETLIFY DEPLOY COMMENT GENERATED BY ACTIONS_NETLIFY - APP ID SHA256: fa806a2cf6952a12e6174f41068bd77e8b2eec522017ddd7190a1bd99a7881db -->
🚀 Deployed on https://6552e74681c71c05489819be--tubular-marzipan-5e01ed.netlify.app
eskandarih: I was wondering if the new edge opacity is similar to the former opacity in `Plotter.add_mesh` method?
https://docs.pyvista.org/version/stable/api/plotting/_autosummary/pyvista.Plotter.add_mesh.html
in `Plotter.add_mesh` method, the opacity takes `array_like` value too.
Can we pass `array_like` list to set the edge opacaity corresponding to each cell too?
banesullivan: +1 for adding `edge_opacity` as a keyword argument to `add_mesh()`
user27182: Referencing #5029 as it updates the `Property` class, some of the discussion here may be relevant
tkoyama010: pre-commit.ci autofix
tkoyama010: pre-commit.ci autofix
tkoyama010: > I was wondering if the new edge opacity is similar to the former opacity in `Plotter.add_mesh` method? https://docs.pyvista.org/version/stable/api/plotting/_autosummary/pyvista.Plotter.add_mesh.html in `Plotter.add_mesh` method, the opacity takes `array_like` value too. Can we pass `array_like` list to set the edge opacaity corresponding to each cell too?

@eskandarih I added `edge_opacity` as a keyword arg to `add_mesh` but only float. In order to realize the array argument of your request, we need to investigate how to realize it in VTK. If you have any information you know about it, I would be happy to share the information.
tkoyama010: pre-commit.ci autofix
tkoyama010: precommit.ci autofix

Patch:
diff --git a/pyvista/plotting/_property.py b/pyvista/plotting/_property.py
index 36c7af1b..17a5ae55 100644
--- a/pyvista/plotting/_property.py
+++ b/pyvista/plotting/_property.py
@@ -2,6 +2,7 @@
 from typing import Union
 
 import pyvista
+from pyvista import vtk_version_info
 from pyvista.core.utilities.misc import _check_range, no_new_attr
 
 from . import _vtk
@@ -107,6 +108,16 @@ class Property(_vtk.vtkProperty):
         * ``"front"`` - Enable frontface culling
         * ``'none'`` - Disable both backface and frontface culling
 
+    edge_opacity : float, default: :attr:`pyvista.plotting.themes.Theme.edge_opacity`
+        Edge opacity of the mesh. A single float value that will be applied globally
+        edge opacity of the mesh and uniformly applied everywhere - should be
+        between 0 and 1.
+
+        .. note::
+            `edge_opacity` uses ``SetEdgeOpacity`` as the underlying method which
+            requires VTK version 9.3 or higher. If ``SetEdgeOpacity`` is not
+            available, `edge_opacity` is set to 1.
+
     Examples
     --------
     Create a :class:`pyvista.Actor` and assign properties to it.
@@ -166,6 +177,7 @@ class Property(_vtk.vtkProperty):
         lighting=None,
         line_width=None,
         culling=None,
+        edge_opacity=None,
     ):
         """Initialize this property."""
         self._theme = pyvista.themes.Theme()
@@ -230,6 +242,16 @@ class Property(_vtk.vtkProperty):
         self.line_width = line_width
         if culling is not None:
             self.culling = culling
+        if vtk_version_info < (9, 3) and edge_opacity is not None:  # pragma: no cover
+            import warnings
+
+            warnings.warn(
+                '`edge_opacity` cannot be used under VTK v9.3.0. Try installing VTK v9.3.0 or newer.',
+                UserWarning,
+            )
+        if edge_opacity is None:
+            edge_opacity = self._theme.edge_opacity
+        self.edge_opacity = edge_opacity
 
     @property
     def style(self) -> str:  # numpydoc ignore=RT01
@@ -398,6 +420,51 @@ class Property(_vtk.vtkProperty):
         _check_range(value, (0, 1), 'opacity')
         self.SetOpacity(value)
 
+    @property
+    def edge_opacity(self) -> float:  # numpydoc ignore=RT01
+        """Return or set the edge opacity of this property.
+
+        Edge opacity of the mesh. A single float value that will be applied globally
+        edge opacity of the mesh and uniformly applied everywhere. Between 0 and 1.
+
+        .. note::
+            `edge_opacity` uses ``SetEdgeOpacity`` as the underlying method which
+            requires VTK version 9.3 or higher. If ``SetEdgeOpacity`` is not
+            available, `edge_opacity` is set to 1.
+
+        Examples
+        --------
+        Set edge opacity to ``0.5``.
+
+        >>> import pyvista as pv
+        >>> prop = pv.Property()
+        >>> prop.show_edges = True
+        >>> prop.edge_opacity = 0.5
+        >>> prop.edge_opacity
+        0.5
+
+        Visualize default edge opacity of ``1.0``.
+
+        >>> prop.edge_opacity = 1.0
+        >>> prop.plot()
+
+        Visualize edge opacity of ``0.1``.
+
+        >>> prop.edge_opacity = 0.1
+        >>> prop.plot()
+
+        """
+        if vtk_version_info < (9, 3):
+            return 1.0
+        else:
+            return self.GetEdgeOpacity()
+
+    @edge_opacity.setter
+    def edge_opacity(self, value: float):  # numpydoc ignore=GL08
+        _check_range(value, (0, 1), 'edge_opacity')
+        if vtk_version_info >= (9, 3):
+            self.SetEdgeOpacity(value)
+
     @property
     def show_edges(self) -> bool:  # numpydoc ignore=RT01
         """Return or set the visibility of edges.
diff --git a/pyvista/plotting/plotter.py b/pyvista/plotting/plotter.py
index b9c13003..99c1adf0 100644
--- a/pyvista/plotting/plotter.py
+++ b/pyvista/plotting/plotter.py
@@ -2323,6 +2323,7 @@ class BasePlotter(PickingHelper, WidgetHelper):
         color_missing_with_nan=False,
         copy_mesh=False,
         show_vertices=None,
+        edge_opacity=None,
         **kwargs,
     ):
         """Add a composite dataset to the plotter.
@@ -2587,6 +2588,16 @@ class BasePlotter(PickingHelper, WidgetHelper):
             * ``vertex_style`` - Change style to ``'points_gaussian'``
             * ``vertex_opacity`` - Control the opacity of the vertices
 
+        edge_opacity : float, optional
+            Edge opacity of the mesh. A single float value that will be applied globally
+            edge opacity of the mesh and uniformly applied everywhere - should be
+            between 0 and 1.
+
+            .. note::
+                `edge_opacity` uses ``SetEdgeOpacity`` as the underlying method which
+                requires VTK version 9.3 or higher. If ``SetEdgeOpacity`` is not
+                available, `edge_opacity` is set to 1.
+
         **kwargs : dict, optional
             Optional keyword arguments.
 
@@ -2710,6 +2721,7 @@ class BasePlotter(PickingHelper, WidgetHelper):
             line_width=line_width,
             opacity=opacity,
             culling=culling,
+            edge_opacity=edge_opacity,
         )
         actor.SetProperty(prop)
 
@@ -2847,6 +2859,7 @@ class BasePlotter(PickingHelper, WidgetHelper):
         copy_mesh=False,
         backface_params=None,
         show_vertices=None,
+        edge_opacity=None,
         **kwargs,
     ):
         """Add any PyVista/VTK mesh or dataset that PyVista can wrap to the scene.
@@ -3180,6 +3193,16 @@ class BasePlotter(PickingHelper, WidgetHelper):
             * ``vertex_style`` - Change style to ``'points_gaussian'``
             * ``vertex_opacity`` - Control the opacity of the vertices
 
+        edge_opacity : float, optional
+            Edge opacity of the mesh. A single float value that will be applied globally
+            edge opacity of the mesh and uniformly applied everywhere - should be
+            between 0 and 1.
+
+            .. note::
+                `edge_opacity` uses ``SetEdgeOpacity`` as the underlying method which
+                requires VTK version 9.3 or higher. If ``SetEdgeOpacity`` is not
+                available, `edge_opacity` is set to 1.
+
         **kwargs : dict, optional
             Optional keyword arguments.
 
diff --git a/pyvista/plotting/themes.py b/pyvista/plotting/themes.py
index f724028f..a71ea8f6 100644
--- a/pyvista/plotting/themes.py
+++ b/pyvista/plotting/themes.py
@@ -1567,6 +1567,7 @@ class Theme(_ThemeConfig):
         '_opacity',
         '_before_close_callback',
         '_logo_file',
+        '_edge_opacity',
     ]
 
     def __init__(self):
@@ -1650,6 +1651,7 @@ class Theme(_ThemeConfig):
         self._lighting_params = _LightingConfig()
         self._interpolate_before_map = True
         self._opacity = 1.0
+        self._edge_opacity = 1.0
 
         self._logo_file = None
 
@@ -1755,6 +1757,28 @@ class Theme(_ThemeConfig):
         _check_range(opacity, (0, 1), 'opacity')
         self._opacity = float(opacity)
 
+    @property
+    def edge_opacity(self) -> float:  # numpydoc ignore=RT01
+        """Return or set the edges opacity.
+
+        .. note::
+            `edge_opacity` uses ``SetEdgeOpacity`` as the underlying method which
+            requires VTK version 9.3 or higher. If ``SetEdgeOpacity`` is not
+            available, `edge_opacity` is set to 1.
+
+        Examples
+        --------
+        >>> import pyvista as pv
+        >>> pv.global_theme.edge_opacity = 0.5
+
+        """
+        return self._edge_opacity
+
+    @edge_opacity.setter
+    def edge_opacity(self, edge_opacity: float):  # numpydoc ignore=GL08
+        _check_range(edge_opacity, (0, 1), 'edge_opacity')
+        self._edge_opacity = float(edge_opacity)
+
     @property
     def above_range_color(self) -> Color:  # numpydoc ignore=RT01
         """Return or set the default above range color.


Test patch:
diff --git a/tests/plotting/test_property.py b/tests/plotting/test_property.py
index 3662cc09..072ef304 100644
--- a/tests/plotting/test_property.py
+++ b/tests/plotting/test_property.py
@@ -44,6 +44,15 @@ def test_property_opacity(prop):
         prop.opacity = 2
 
 
+@pytest.mark.skipif(pv.vtk_version_info < (9, 3), reason="Functions not implemented before 9.3.X")
+def test_property_edge_opacity(prop):
+    edge_opacity = 0.5
+    prop.edge_opacity = edge_opacity
+    assert prop.edge_opacity == edge_opacity
+    with pytest.raises(ValueError):
+        prop.edge_opacity = 2
+
+
 def test_property_show_edges(prop):
     value = False
     prop.show_edges = value