Repository: pyqtgraph/pyqtgraph

Issue:
some PlotCurveItem options not resettable by PlotDataItem
<!-- In the following, please describe your issue in detail! -->
<!-- If some of the sections do not apply, just remove them. -->

### Short description
<!-- This should summarize the issue. -->
The PlotCurveItem options ```fillLevel```, ```brush``` and ```shadowPen``` are not able to be reset to their non-active state of None from PlotDataItem keyword arguments. Some of them can only be deactivated by calling methods.

```brush``` and ```shadowPen``` could be deactivated by calling ```PlotDataItem``` methods ```setBrush(None)``` and ```setShadowPen(None)```, although this only changes their styles to ```NoBrush``` and ```NoPen```, so may not be strictly equivalent to being able to reset to ```None```.

### Code to reproduce
<!-- Please provide a minimal working example that reproduces the issue in the code block below.
     Ideally, this should be a full example someone else could run without additional setup. -->
```python
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui
import numpy as np

def print_opts(title, opts):
    print(title)
    print("fillLevel :", opts['fillLevel'])
    brush = opts['brush']
    if isinstance(brush, QtGui.QBrush):
        print("brush :", brush.style(), brush.color().name())
    else:
        print("brush :", brush)
    pen = opts['shadowPen']
    if isinstance(pen, QtGui.QPen):
        print("shadowPen :", pen.style(), pen.color().name())
    else:
        print("shadowPen :", pen)
    print()

pg.mkQApp()

if 1:
    item = pg.PlotDataItem()
    curve = item.curve
else:
    # try out using a PlotCurveItem directly
    item = pg.PlotCurveItem()
    curve = item

# setup initial values
item.setData(np.arange(10), fillLevel=0.0, brush='b', shadowPen='g')
print_opts('INITIAL', curve.opts)

# none of the 3 options can be reset via keywords
item.setData(np.arange(10), fillLevel=None, brush=None, shadowPen=None)
print_opts('MODIFY VIA KEYWORDS', curve.opts)

# fillLevel cannot be reset via method call either
item.setFillLevel(None)
item.setBrush(None)
item.setShadowPen(None)
item.setData(np.arange(10))
print_opts('MODIFY VIA METHODS', curve.opts)
```

### Expected behavior
<!-- What should happen? -->
```
INITIAL
fillLevel : 0.0

MODIFY VIA KEYWORDS
fillLevel : None

MODIFY VIA METHODS
fillLevel : None
```

### Real behavior
<!-- What happens? -->
OUTPUT:
```
INITIAL
fillLevel : 0.0
brush : BrushStyle.SolidPattern #0000ff
shadowPen : PenStyle.SolidLine #00ff00

MODIFY VIA KEYWORDS
fillLevel : 0.0
brush : BrushStyle.SolidPattern #0000ff
shadowPen : PenStyle.SolidLine #00ff00

MODIFY VIA METHODS
fillLevel : 0.0
brush : BrushStyle.NoBrush #000000
shadowPen : PenStyle.NoPen #c8c8c8
```
### Tested environment(s)

 * PyQtGraph version: <!-- output of pyqtgraph.__version__ --> 0.12.3
 * Qt Python binding: <!-- output of pyqtgraph.Qt.VERSION_INFO --> PyQt6 6.2.0
 * Python version: 3.8.10
 * NumPy version: <!-- output of numpy.__version__ --> 1.21.3
 * Operating system: Windows 10
 * Installation method: <!-- e.g. pip, conda, system packages, ... --> pip install -e .

### Additional context

```fillLevel``` can be reset to None by calling ```PlotCurveItem.setFillLevel(None)``` but _not_ by calling ```PlotDataItem.setFillLevel(None)```.


Discussion:
A more concrete example. Disabling ```fillLevel``` doesn't work in the example below. 
```python
import pyqtgraph as pg 
from pyqtgraph.Qt import QtWidgets
import numpy as np

pg.mkQApp()
pw = pg.PlotWidget()
toggle = QtWidgets.QPushButton("Fill")
toggle.setCheckable(True)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(pw)
layout.addWidget(toggle)
central = QtWidgets.QWidget()
central.setLayout(layout)
central.show()

y = np.sinc(np.linspace(-3, 3, 1001))
pdi = pw.plot(y, brush='b')

def toggle_fill(enable):
    value = 0.0 if enable else None
    pdi.setFillLevel(value)

toggle.clicked.connect(toggle_fill)
pg.exec()
```

Resolving patch:
diff --git a/pyqtgraph/graphicsItems/PlotCurveItem.py b/pyqtgraph/graphicsItems/PlotCurveItem.py
--- a/pyqtgraph/graphicsItems/PlotCurveItem.py
+++ b/pyqtgraph/graphicsItems/PlotCurveItem.py
@@ -100,8 +100,8 @@ def arrayToLineSegments(self, x, y, connect, finiteCheck):
 class PlotCurveItem(GraphicsObject):
     """
     Class representing a single plot curve. Instances of this class are created
-    automatically as part of PlotDataItem; these rarely need to be instantiated
-    directly.
+    automatically as part of :class:`PlotDataItem <pyqtgraph.PlotDataItem>`; 
+    these rarely need to be instantiated directly.
 
     Features:
 
@@ -128,8 +128,8 @@ def __init__(self, *args, **kargs):
         ==============  =======================================================
         **Arguments:**
         parent          The parent GraphicsObject (optional)
-        clickable       If True, the item will emit sigClicked when it is
-                        clicked on. Defaults to False.
+        clickable       If `True`, the item will emit ``sigClicked`` when it is
+                        clicked on. Defaults to `False`.
         ==============  =======================================================
         """
         GraphicsObject.__init__(self, kargs.get('parent', None))
@@ -150,7 +150,7 @@ def __init__(self, *args, **kargs):
             'connect': 'all',
             'mouseWidth': 8, # width of shape responding to mouse click
             'compositionMode': None,
-            'skipFiniteCheck': True
+            'skipFiniteCheck': False
         }
         if 'pen' not in kargs:
             self.opts['pen'] = fn.mkPen('w')
@@ -169,7 +169,7 @@ def name(self):
     def setClickable(self, s, width=None):
         """Sets whether the item responds to mouse clicks.
 
-        The *width* argument specifies the width in pixels orthogonal to the
+        The `width` argument specifies the width in pixels orthogonal to the
         curve that will respond to a mouse click.
         """
         self.clickable = s
@@ -370,82 +370,109 @@ def invalidateBounds(self):
 
     def setPen(self, *args, **kargs):
         """Set the pen used to draw the curve."""
-        self.opts['pen'] = fn.mkPen(*args, **kargs)
+        if args[0] is None:
+            self.opts['pen'] = None
+        else:
+            self.opts['pen'] = fn.mkPen(*args, **kargs)
         self.invalidateBounds()
         self.update()
 
     def setShadowPen(self, *args, **kargs):
-        """Set the shadow pen used to draw behind the primary pen.
+        """
+        Set the shadow pen used to draw behind the primary pen.
         This pen must have a larger width than the primary
-        pen to be visible.
+        pen to be visible. Arguments are passed to 
+        :func:`mkPen <pyqtgraph.mkPen>`
         """
-        self.opts['shadowPen'] = fn.mkPen(*args, **kargs)
+        if args[0] is None:
+            self.opts['shadowPen'] = None
+        else:
+            self.opts['shadowPen'] = fn.mkPen(*args, **kargs)
         self.invalidateBounds()
         self.update()
 
     def setBrush(self, *args, **kargs):
-        """Set the brush used when filling the area under the curve"""
-        self.opts['brush'] = fn.mkBrush(*args, **kargs)
+        """
+        Sets the brush used when filling the area under the curve. All 
+        arguments are passed to :func:`mkBrush <pyqtgraph.mkBrush>`.
+        """
+        if args[0] is None:
+            self.opts['brush'] = None
+        else:
+            self.opts['brush'] = fn.mkBrush(*args, **kargs)
         self.invalidateBounds()
         self.update()
 
     def setFillLevel(self, level):
-        """Set the level filled to when filling under the curve"""
+        """Sets the level filled to when filling under the curve"""
         self.opts['fillLevel'] = level
         self.fillPath = None
         self.invalidateBounds()
         self.update()
+        
+    def setSkipFiniteCheck(self, skipFiniteCheck):
+        """
+        When it is known that the plot data passed to ``PlotCurveItem`` contains only finite numerical values,
+        the `skipFiniteCheck` property can help speed up plotting. If this flag is set and the data contains 
+        any non-finite values (such as `NaN` or `Inf`), unpredictable behavior will occur. The data might not
+        be plotted, or there migth be significant performance impact.
+        """
+        self.opts['skipFiniteCheck']  = bool(skipFiniteCheck)
 
     def setData(self, *args, **kargs):
         """
-        =============== ========================================================
+        =============== =================================================================
         **Arguments:**
-        x, y            (numpy arrays) Data to show
+        x, y            (numpy arrays) Data to display
         pen             Pen to use when drawing. Any single argument accepted by
                         :func:`mkPen <pyqtgraph.mkPen>` is allowed.
         shadowPen       Pen for drawing behind the primary pen. Usually this
                         is used to emphasize the curve by providing a
                         high-contrast border. Any single argument accepted by
                         :func:`mkPen <pyqtgraph.mkPen>` is allowed.
-        fillLevel       (float or None) Fill the area 'under' the curve to
-                        *fillLevel*
-        fillOutline     (bool) If True, an outline surrounding the *fillLevel*
+        fillLevel       (float or None) Fill the area under the curve to
+                        the specified value.
+        fillOutline     (bool) If True, an outline surrounding the `fillLevel`
                         area is drawn.
-        brush           QBrush to use when filling. Any single argument accepted
+        brush           Brush to use when filling. Any single argument accepted
                         by :func:`mkBrush <pyqtgraph.mkBrush>` is allowed.
         antialias       (bool) Whether to use antialiasing when drawing. This
                         is disabled by default because it decreases performance.
-        stepMode        (str or None) If "center", a step is drawn using the x
-                        values as boundaries and the given y values are
+        stepMode        (str or None) If 'center', a step is drawn using the `x`
+                        values as boundaries and the given `y` values are
                         associated to the mid-points between the boundaries of
                         each step. This is commonly used when drawing
-                        histograms. Note that in this case, len(x) == len(y) + 1
-                        If "left" or "right", the step is drawn assuming that
-                        the y value is associated to the left or right boundary,
-                        respectively. In this case len(x) == len(y)
-                        If not passed or an empty string or None is passed, the
+                        histograms. Note that in this case, ``len(x) == len(y) + 1``
+                        
+                        If 'left' or 'right', the step is drawn assuming that
+                        the `y` value is associated to the left or right boundary,
+                        respectively. In this case ``len(x) == len(y)``
+                        If not passed or an empty string or `None` is passed, the
                         step mode is not enabled.
-                        Passing True is a deprecated equivalent to "center".
         connect         Argument specifying how vertexes should be connected
-                        by line segments. Default is "all", indicating full
-                        connection. "pairs" causes only even-numbered segments
-                        to be drawn. "finite" causes segments to be omitted if
-                        they are attached to nan or inf values. For any other
-                        connectivity, specify an array of boolean values.
+                        by line segments. 
+                        
+                            | 'all' (default) indicates full connection. 
+                            | 'pairs' draws one separate line segment for each two points given.
+                            | 'finite' omits segments attached to `NaN` or `Inf` values. 
+                            | For any other connectivity, specify an array of boolean values.
         compositionMode See :func:`setCompositionMode
                         <pyqtgraph.PlotCurveItem.setCompositionMode>`.
-        skipFiniteCheck Optimization parameter that can speed up plot time by
-                        telling the painter to not check and compensate for NaN
-                        values.  If set to True, and NaN values exist, the data
-                        may not be displayed or your plot will take a
-                        significant performance hit.  Defaults to False.
-        =============== ========================================================
+        skipFiniteCheck (bool, defaults to `False`) Optimization flag that can
+                        speed up plotting by not checking and compensating for
+                        `NaN` values.  If set to `True`, and `NaN` values exist, the
+                        data may not be displayed or the plot may take a
+                        significant performance hit.
+        =============== =================================================================
 
         If non-keyword arguments are used, they will be interpreted as
-        setData(y) for a single argument and setData(x, y) for two
+        ``setData(y)`` for a single argument and ``setData(x, y)`` for two
         arguments.
-
-
+        
+        **Notes on performance:**
+        
+        Line widths greater than 1 pixel affect the performance as discussed in 
+        the documentation of :class:`PlotDataItem <pyqtgraph.PlotDataItem>`.
         """
         self.updateData(*args, **kargs)
 
@@ -495,8 +522,10 @@ def updateData(self, *args, **kargs):
 
         if self.opts['stepMode'] in ("center", True):  ## check against True for backwards compatibility
             if self.opts['stepMode'] is True:
-                import warnings
-                warnings.warn('stepMode=True is deprecated, use stepMode="center" instead', DeprecationWarning, stacklevel=3)
+                warnings.warn(
+                    'stepMode=True is deprecated and will result in an error after October 2022. Use stepMode="center" instead.',
+                    DeprecationWarning, stacklevel=3
+                )
             if len(self.xData) != len(self.yData)+1:  ## allow difference of 1 for step mode plots
                 raise Exception("len(X) must be len(Y)+1 since stepMode=True (got %s and %s)" % (self.xData.shape, self.yData.shape))
         else:
@@ -514,18 +543,18 @@ def updateData(self, *args, **kargs):
             self.opts['connect'] = kargs['connect']
         if 'pen' in kargs:
             self.setPen(kargs['pen'])
-        if 'shadowPen' in kargs and kargs['shadowPen'] is not None:
+        if 'shadowPen' in kargs:
             self.setShadowPen(kargs['shadowPen'])
-        if 'fillLevel' in kargs and kargs['fillLevel'] is not None:
+        if 'fillLevel' in kargs:
             self.setFillLevel(kargs['fillLevel'])
         if 'fillOutline' in kargs:
             self.opts['fillOutline'] = kargs['fillOutline']
-        if 'brush' in kargs and kargs['brush'] is not None:
+        if 'brush' in kargs:
             self.setBrush(kargs['brush'])
         if 'antialias' in kargs:
             self.opts['antialias'] = kargs['antialias']
-
-        self.opts['skipFiniteCheck'] = kargs.get('skipFiniteCheck', False)
+        if 'skipFiniteCheck' in kargs:
+            self.opts['skipFiniteCheck'] = kargs['skipFiniteCheck']
 
         profiler('set')
         self.update()
diff --git a/pyqtgraph/graphicsItems/PlotDataItem.py b/pyqtgraph/graphicsItems/PlotDataItem.py
--- a/pyqtgraph/graphicsItems/PlotDataItem.py
+++ b/pyqtgraph/graphicsItems/PlotDataItem.py
@@ -85,7 +85,7 @@ def dataRect(self):
     def applyLogMapping(self, logMode):
         """
         Applies a logarithmic mapping transformation (base 10) if requested for the respective axis.
-        This replaces the internal data. Values of `-inf` resulting from zeros in the original dataset are
+        This replaces the internal data. Values of ``-inf`` resulting from zeros in the original dataset are
         replaced by ``np.NaN``.
         
         Parameters
@@ -177,12 +177,14 @@ def __init__(self, *args, **kargs):
         **Line style keyword arguments:**
 
             ============ ==============================================================================
-            connect      Specifies how / whether vertexes should be connected.
+            connect      Specifies how / whether vertexes should be connected. See below for details.
             pen          Pen to use for drawing the lines between points.
                          Default is solid grey, 1px width. Use None to disable line drawing.
-                         May be any single argument accepted by :func:`mkPen() <pyqtgraph.mkPen>`
+                         May be a ``QPen`` or any single argument accepted by 
+                         :func:`mkPen() <pyqtgraph.mkPen>`
             shadowPen    Pen for secondary line to draw behind the primary line. Disabled by default.
-                         May be any single argument accepted by :func:`mkPen() <pyqtgraph.mkPen>`
+                         May be a ``QPen`` or any single argument accepted by 
+                         :func:`mkPen() <pyqtgraph.mkPen>`
             fillLevel    If specified, the area between the curve and fillLevel is filled.
             fillOutline  (bool) If True, an outline surrounding the *fillLevel* area is drawn.
             fillBrush    Fill to use in the *fillLevel* area. May be any single argument accepted by 
@@ -196,7 +198,7 @@ def __init__(self, *args, **kargs):
 
             ============ ==============================================================================
         
-        `connect` supports the follwoing arguments:
+        ``connect`` supports the follwoing arguments:
         
         - 'all' connects all points.  
         - 'pairs' generates lines between every other point.
@@ -235,7 +237,7 @@ def __init__(self, *args, **kargs):
 
             ================= =======================================================================
             antialias         (bool) By default, antialiasing is disabled to improve performance.
-                              Note that in some cases (in particular, when `pxMode=True`), points
+                              Note that in some cases (in particular, when ``pxMode=True``), points
                               will be rendered antialiased even if this is set to `False`.
             downsample        (int) Reduce the number of samples displayed by the given factor.
             downsampleMethod  'subsample': Downsample by taking the first of N samples.
@@ -259,11 +261,13 @@ def __init__(self, *args, **kargs):
                               :class:`ViewBox` height.
             dynamicRangeHyst  (float) Permits changes in vertical zoom up to the given hysteresis
                               factor (the default is 3.0) before the limit calculation is repeated.
-            skipFiniteCheck   (bool) Optimization parameter that can speed up plotting by not 
-                              checking and compensating for NaN values.  
-                              If set to `True`, and NaN values exist, the data
-                              may not be displayed or plot will take a
-                              significant performance hit.  Defaults to `False`.
+            skipFiniteCheck   (bool, default `False`) Optimization flag that can speed up plotting by not 
+                              checking and compensating for NaN values.  If set to `True`, and NaN 
+                              values exist, unpredicatable behavior will occur. The data may not be
+                              displayed or the plot may take a significant performance hit.
+                              
+                              In the default 'auto' connect mode, `PlotDataItem` will apply this 
+                              setting automatically.
             ================= =======================================================================
 
         **Meta-info keyword arguments:**
@@ -271,6 +275,23 @@ def __init__(self, *args, **kargs):
             ==========   ================================================
             name         (string) Name of item for use in the plot legend
             ==========   ================================================
+
+        **Notes on performance:**
+        
+        Plotting lines with the default single-pixel width is the fastest available option. For such lines,
+        translucent colors (`alpha` < 1) do not result in a significant slowdown.
+        
+        Wider lines increase the complexity due to the overlap of individual line segments. Translucent colors
+        require merging the entire plot into a single entity before the alpha value can be applied. For plots with more
+        than a few hundred points, this can result in excessive slowdown.
+
+        Since version 0.12.4, this slowdown is automatically avoided by an algorithm that draws line segments
+        separately for fully opaque lines. Setting `alpha` < 1 reverts to the previous, slower drawing method.
+        
+        For lines with a wdith of more than 4 pixels, :func:`pyqtgraph.mkPen() <pyqtgraph.mkPen>` will automatically
+        create a ``QPen`` with `Qt.PenCapStyle.RoundCap` to ensure a smooth connection of line segments. This incurs a
+        small performance penalty.
+
         """
         GraphicsObject.__init__(self)
         self.setFlag(self.GraphicsItemFlag.ItemHasNoContents)
@@ -302,6 +323,7 @@ def __init__(self, *args, **kargs):
         #self.clear()
         self.opts = {
             'connect': 'auto', # defaults to 'all', unless overridden to 'finite' for log-scaling
+            'skipFiniteCheck': False, 
             'fftMode': False,
             'logMode': [False, False],
             'derivativeMode': False,
@@ -332,7 +354,6 @@ def __init__(self, *args, **kargs):
             'clipToView': False,
             'dynamicRangeLimit': 1e6,
             'dynamicRangeHyst': 3.0,
-            'skipFiniteCheck': False,
             'data': None,
         }
         self.setCurveClickable(kargs.get('clickable', False))
@@ -401,10 +422,10 @@ def setFftMode(self, state):
 
     def setLogMode(self, xState, yState):
         """
-        When log mode is enabled for the respective axis by setting `xState` or 
-        `yState` to `True, a mapping according to ``mapped = np.log10( value )`` 
+        When log mode is enabled for the respective axis by setting ``xState`` or 
+        ``yState`` to `True, a mapping according to ``mapped = np.log10( value )`` 
         is applied to the data. For negative or zero values, this results in a 
-        NaN value.
+        `NaN` value.
         """
         if self.opts['logMode'] == [xState, yState]:
             return
@@ -476,7 +497,10 @@ def setShadowPen(self, *args, **kargs):
         The argument can be a :class:`QtGui.QPen` or any combination of arguments accepted by 
         :func:`pyqtgraph.mkPen() <pyqtgraph.mkPen>`.
         """
-        pen = fn.mkPen(*args, **kargs)
+        if args[0] is None:
+            pen = None
+        else:
+            pen = fn.mkPen(*args, **kargs)
         self.opts['shadowPen'] = pen
         #for c in self.curves:
             #c.setPen(pen)
@@ -488,7 +512,10 @@ def setFillBrush(self, *args, **kargs):
         Sets the :class:`QtGui.QBrush` used to fill the area under the curve.
         See :func:`mkBrush() <pyqtgraph.functions.mkBrush>`) for arguments.
         """
-        brush = fn.mkBrush(*args, **kargs)
+        if args[0] is None:
+            brush = None
+        else:
+            brush = fn.mkBrush(*args, **kargs)
         if self.opts['fillBrush'] == brush:
             return
         self.opts['fillBrush'] = brush
@@ -633,6 +660,17 @@ def setDynamicRangeLimit(self, limit=1e06, hysteresis=3.):
         self._datasetDisplay = None  # invalidate display data
 
         self.updateItems(styleUpdate=False)
+        
+    def setSkipFiniteCheck(self, skipFiniteCheck):
+        """
+        When it is known that the plot data passed to ``PlotDataItem`` contains only finite numerical values,
+        the ``skipFiniteCheck`` property can help speed up plotting. If this flag is set and the data contains 
+        any non-finite values (such as `NaN` or `Inf`), unpredictable behavior will occur. The data might not
+        be plotted, or there migth be significant performance impact.
+        
+        In the default 'auto' connect mode, ``PlotDataItem`` will apply this setting automatically.
+        """
+        self.opts['skipFiniteCheck']  = bool(skipFiniteCheck)
 
     def setData(self, *args, **kargs):
         """
@@ -642,18 +680,18 @@ def setData(self, *args, **kargs):
         #self.clear()
         if kargs.get("stepMode", None) is True:
             warnings.warn(
-                'stepMode=True is deprecated, use stepMode="center" instead',
+                'stepMode=True is deprecated and will result in an error after October 2022. Use stepMode="center" instead.',
                 DeprecationWarning, stacklevel=3
             )
         if 'decimate' in kargs.keys():
             warnings.warn(
-                'decimate kwarg has been deprecated, it has no effect',
+                'The decimate keyword has been deprecated. It has no effect and may result in an error in releases after October 2022. ',
                 DeprecationWarning, stacklevel=2
             )
         
         if 'identical' in kargs.keys():
             warnings.warn(
-                'identical kwarg has been deprecated, it has no effect',
+                'The identical keyword has been deprecated. It has no effect may result in an error in releases after October 2022. ',
                 DeprecationWarning, stacklevel=2
             )
         profiler = debug.Profiler()
@@ -730,6 +768,9 @@ def setData(self, *args, **kargs):
         if 'connect' in kargs:
             self.opts['connect'] = kargs['connect']
             self.setProperty('styleWasChanged', True)
+            
+        if 'skipFiniteCheck' in kargs:
+            self.opts['skipFiniteCheck'] = kargs['skipFiniteCheck']
 
         ## if symbol pen/brush are given with no previously set symbol, then assume symbol is 'o'
         if 'symbol' not in kargs and ('symbolPen' in kargs or 'symbolBrush' in kargs or 'symbolSize' in kargs):
@@ -866,7 +907,7 @@ def updateItems(self, styleUpdate=True):
     def getDisplayDataset(self):
         """
         Returns a :class:`PlotDataset <pyqtgraph.PlotDataset>` object that contains data suitable for display 
-        (after mapping and data reduction) as `dataset.x` and `dataset.y`.
+        (after mapping and data reduction) as ``dataset.x`` and ``dataset.y``.
         Intended for internal use.
         """
         if self._dataset is None:


Test patch: