Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "left" and "right" step Modes #1360

Merged
merged 11 commits into from
Oct 13, 2020
Merged

Add "left" and "right" step Modes #1360

merged 11 commits into from
Oct 13, 2020

Conversation

cpascual
Copy link
Contributor

@cpascual cpascual commented Sep 8, 2020

stepMode is currently either True or False. If it is True,
it requires the user to make len(x) = len(y)+1. This is
inconvenient because it makes it difficult to change the
stepMode on a given curve (just as one would change, e.g.,
its color).

This commit extends the current situation by introducing
two more step modes: "lstep" and "rstep", which do not require
passing an extra x value. In turn, this modes associate each
y value to either the left or the right boundary of the step.

For example, the "rstep" mode is handy when plotting "live"
digital signals in which x,y data pairs are appended as they
are read.

This commit does not modify the behavior in case of stepMode=True

stepMode is currently either True or False. If it is True,
it requires the user to make len(x) = len(y)+1. This is
inconvenient because it makes it difficult to change the
stepMode on a given curve (just as one would change, e.g.,
its color).

This commit extends the current situation by introducing
two more step modes: "lstep" and "rstep", which do not require
passing an extra x value. In turn, this modes associate each
y value to either the left or the right boundary of the step.

For example, the "rstep" mode is handy when plotting "life"
digital signals in which x,y data pairs are appended as they
are read.

This commit does not modify the behaviour in case of stepMode=True
@cpascual
Copy link
Contributor Author

cpascual commented Sep 8, 2020

Here an example:

import pyqtgraph as pg
from pyqtgraph.Qt import QtGui
import numpy as np

app = QtGui.QApplication([])
p = pg.PlotWidget()
p.addLegend()
x = y = np.arange(5)

p.plot(x=x, y=y, symbol="t", stepMode=False, name="False", pen="r")
p.plot(x=x, y=2+y[:-1], symbol="t", stepMode=True, name="True", pen="g")
p.plot(x=x, y=4+y, symbol="t", stepMode="rstep", name="rstep", pen="c")
p.plot(x=x, y=6+y, symbol="t", stepMode="lstep", name="lstep", pen="m")

p.show()
app.exec_()

... and its result:

image

@cpascual
Copy link
Contributor Author

Hi, sorry for this shameless "bumping", but... can someone (@campagnola ?) comment on whether this contribution may be considered for inclusion or if there is something I should do to improve it?

(I just want to know because if it is going to be rejected I should find another way to implement this in my own project)

Copy link
Member

@ixjlyons ixjlyons left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a nice feature to me, and the API seems good in particular keeping backward compatibility. I'm inclined to accept but thoughts from others would be great.

A couple notes:

Using "step" in the possible values seems redundant. Maybe stepMode="left" and stepMode="right"? Just a thought, I don't feel strongly about it.

I would actually emphasize documentation of stepMode in the PlotDataItem class, and you could either copy the text to PlotCurveItem or refer to stepMode in PlotDataItem. The reason is the scatter plot item may be impacted by the step mode as well as the curve item. Also, people are likely (I think) to land on the PlotDataItem reference page from plot -> PlotItem.plot -> PlotDataItem.__init__ in the docs.

When stepMode == True, it's the x value that's taken as the midpoint between provided x values, not y (y values are used as given).

And a last nitpick, I think it'd be prudent to add a comment above the line in PlotCurveItem.updateData where it says if self.opts['stepMode'] is True. Someone in the future might be inclined to remove is True, but that's actually a useful distinction now that stepMode can be a string where that condition doesn't apply

Carlos Pascual added 4 commits September 22, 2020 08:21
Reword docstring and add it to PlotDataItem class too
TODO: confirm the exact version number to use here
Some conditional statements in the code regarding stepMode are
done with "is True". This is actually required since other
possible values such as "left" also evaluate as true but should
not be caught.
@cpascual
Copy link
Contributor Author

Thanks a lot @ixjlyons for the review. I just pushed 4 commits which, I think, address all your comments.

Please note that I included a "added in version 0.12.0" for the left and right step modes in the PlotDataItem docs, but of course I am not sure if the specific version number is right. I did it in a separate commit so that it can easily be reverted.

@cpascual cpascual changed the title Add "lstep" and "rstep" step Modes Add "left" and "right" step Modes Sep 22, 2020
stepMode If True, two orthogonal lines are drawn for each sample
as steps. This is commonly used when drawing histograms.
Note that in this case, len(x) == len(y) + 1
stepMode If True, a step is drawn using the x values as
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this start with (bool or str or None) ?

@j9ac9k
Copy link
Member

j9ac9k commented Sep 23, 2020

I don't have anything to add other than a thank you for submitting this feature @cpascual, I appreciate you ensuring the addition to this feature does not impact the current implementation. I must admit the API feels a bit weird that it is an Optional[Union[bool, str]] but I'm not sure of a better way of doing it (unless we introduced a stepType (or something analogous) kwarg, that defaults to standard which the existing behavior, and has lstep and rstep as potential options.

I'm just throwing this idea out there to see what folks think, I'm not requesting any changes be made.

@ixjlyons
Copy link
Member

Regarding the weird mix of types accepted (particularly evident with is True being meaningful in the code), I was thinking there could be a "mid" option so True could be more of a legacy option (with the possibility of being deprecated and removed over time).

@cpascual
Copy link
Contributor Author

I can do the "mid" option implementation.
I didn't do it originally because I was after the minimum possible changes in order to be super-safe in respecting backwards-compat. But I think it is quite safe to do that.

Introduce stepMode="mid" as a replacement of stepMode=True,
but keeping full backwards compatibility with the old API.
Adapt docs, examples and tests accordingly.
@cpascual
Copy link
Contributor Author

d8b71e5 adds the "mid" option and marks usage of booleans as a legacy API

@cpascual
Copy link
Contributor Author

cpascual commented Sep 23, 2020

I also added 3997532 to prevent that any other string (e.g. a misspell like "letf") ends up treated the same as "mid" or True.

@dgoeries
Copy link
Contributor

I very much like this feature. I only have a nitpick and would call it center instead of mid.

@cpascual
Copy link
Contributor Author

@dgoeries :

would call it center instead of mid.

17cab0f does it.

I originally called it "mid" as per @ixjlyons suggestion. Since it is a matter of taste, I leave it up to the integrator to revert this last commit if he/she prefers "mid" over "center".

@dgoeries
Copy link
Contributor

dgoeries commented Oct 3, 2020

thanks for the updates!

(added in version 0.9.9)
(str modes added in version 0.12.0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would go ahead and remove the modes added in version 0.12.0; we'll likely have this in 0.11.1....

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

73542aa does it

@@ -379,7 +387,7 @@ def updateData(self, *args, **kargs):
if 'stepMode' in kargs:
self.opts['stepMode'] = kargs['stepMode']

if self.opts['stepMode'] is True:
if self.opts['stepMode'] in ("center", True): ## check against True for backwards compatibility
if len(self.xData) != len(self.yData)+1: ## allow difference of 1 for step mode plots
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also consider adding a DeprecationWarning if stepMode is True

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2335e29 does it.

Note 1: I did the check on the PlotDataItem.setData() and PlotCurveItem.updateData() instead of the constructors, to cover the possibility of those being called directly. If stepMode is used in the constructors, these methods end up being called anyway.

Note 2: since the warnings module is not otherwise used in these modules, I chose to import it locally so that the whole deprecation check can be cleanly removed once it is no longer needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing this out; this looks good to me.

@j9ac9k
Copy link
Member

j9ac9k commented Oct 10, 2020

hey @cpascual thanks for the updates, sorry it's taking me a while to follow up (I'm still unpacking from my move). The changes you made look great; I'm going to toy with it a bit more later, but I do think a deprecation warning should be emitted if stepMode=True is passed into the __init__ methods.

Carlos Pascual added 3 commits October 13, 2020 16:22
Issue a DeprecationWarning if stepMode=True is being passed to the
constructor or setData() of PlotDataItem or PlotCurveItem.

Note: warnings module is imported locally so that it is esier to
remove once this check is no longer needed.
Fix usage of "default" kwarg in dict.get()
@j9ac9k
Copy link
Member

j9ac9k commented Oct 13, 2020

This looks good to me, thanks for the PR @cpascual I'll merge.

@j9ac9k j9ac9k merged commit 23a46b5 into pyqtgraph:master Oct 13, 2020
@cpascual cpascual deleted the master branch October 14, 2020 10:15
cpascual pushed a commit to cpascual/taurus_pyqtgraph that referenced this pull request Oct 16, 2020
Support step modes in curveproperties.  Requires:
pyqtgraph/pyqtgraph#1360
cpascual pushed a commit to cpascual/taurus_pyqtgraph that referenced this pull request Oct 16, 2020
If pyqtgraph <=0.11.0, left/right step modes are
not supported. Disable the combo box of the
curveproperties dialog in that case.

pyqtgraph/pyqtgraph#1360
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants