Skip to content

Add asymmetric error bars to scatter plots#316

Merged
swharden merged 40 commits intoScottPlot:masterfrom
zrolfs:master
Mar 22, 2020
Merged

Add asymmetric error bars to scatter plots#316
swharden merged 40 commits intoScottPlot:masterfrom
zrolfs:master

Conversation

@zrolfs
Copy link
Contributor

@zrolfs zrolfs commented Mar 20, 2020

Hi Scott!
I wanted to use asymmetric error bars, so I added in some functionality to allow users to do that. To clarify, this pull request should allow users to:
-create asymmetric error bars
-create only a single (positive or negative) error bar

I used the overloading mechanism so that the methods "PlotScatter" and "PlottableScatter" should still be compatible with previous calls.

Thanks for your consideration with this pull request! I'm happy to answer any questions or make changes if you disagree with something.
Zach

@StendProg
Copy link
Contributor

StendProg commented Mar 20, 2020

Hi @zrolfs
I think you need to add overloads for PlotPoint and PlotStep too.

Using overload works, but quickly inflates code.
It might be better to think through an API to avoid this.
I see some possible solutions:

  1. Add optional errorXarrayNegative and errorYarrayNegative params with default null value.
    If they not null, then you interpret existing errorX and errorY as errorXarrayPositive and errorYarrayPositive.
  2. Add optional errorXarrayDelta and errorXarrayDelta params with default null value.
    errorXarrayNegative = errorX + errorXarrayDelta....
  3. To use assymmetric error bars user must provide double sized arrays to errorX and errorY.
    There first half contain positive error values, second half contain negative error values.

Do not rush to realize this, I think Scott will choose 4 option even better.

@zrolfs
Copy link
Contributor Author

zrolfs commented Mar 20, 2020

Hi @StendProg
Thanks for your feedback! I agree the overload is not an ideal solution. I appreciate your proposed solutions, but I'm not sure how intuitive those are for the users.
My preferred solution would be to simply change the original constructors of PlotScatter and PlottableScatter so that they accept the positive/negative arrays (which is what I did with PlotPoint; PlotStep doesn't use error bars). I wrote in the overrides in case we wanted to prevent build errors when users update their versions. I'd be happy to remove them if we don't think that's going to be a big deal.

@StendProg
Copy link
Contributor

I looked more closely at the PR, and didn’t cling to anything, each line expands the functionality and is necessary.
I can offer only one improvement, although it does not related to this PR.
You can simplify min/max search in Scatter GetLimits() with linq:

limits[1] = xs.Zip(errorXPositive, (x, e) => x + e).Max();
...

Not sure if this is easier to read for everyone, but shorter.

Additionaly you can add Demo for this new error bar mode. It's simple task with new demo engine.

@swharden
Copy link
Member

@swharden swharden changed the title Add additional functionality for error bars Add asymmetric error bars to scatter plots Mar 20, 2020
@zrolfs
Copy link
Contributor Author

zrolfs commented Mar 20, 2020

Sounds good! I'm busy right now, but I should have time this evening.

@swharden
Copy link
Member

I think there's some type of rendering error based on the demo...

image

but before going much farther far down this path, I'm wondering if PlottableErrorbars should be its own type of Plottable, not included inside PlottableScatter? If it is separate from Scatter, it can be added/removed/styled independently, and even used with other plot types (such as bar plots). Also the code would be in its own file, not require modification of any existing plottables, and probably be easier to write and maintain 🤔

@zrolfs what do you think?

@zrolfs
Copy link
Contributor Author

zrolfs commented Mar 21, 2020

Oops! I'll take another look.
I like that idea! I'll need to think of a clean way to ensure the color of the error bars matches the color of the plotted series. Would you like me to remove the original symmetric error bar code that is in PlottableScatter and the bar plots?

@swharden
Copy link
Member

I like that idea! I'll need to think of a clean way to ensure the color of the error bars matches the color of the plotted series.

Good point... I'm not really sure of a way to do that automatically other than to define the color of the plotted series when you make it, and also define the color of the errorbars when you make that too. An easy way to get those colors is to use this function which returns a pre-defined series of nice-looking colors based on an integer value:

var thisColor = new ScottPlot.Config.Colors().GetColor(indexValue);

Would you like me to remove the original symmetric error bar code that is in PlottableScatter and the bar plots?

I think that would be easiest because the "files changed" by this PR as it it is right now is a bit intimidating to review 😅 It would be a lot easier if most of the changes were compartmentalized in a new file.

https://github.com/swharden/ScottPlot/pull/316/files

@swharden
Copy link
Member

Thanks for woking on this @zrolfs! Let me know when you think it's ready to merge and I'll take a closer look 👍

@zrolfs
Copy link
Contributor Author

zrolfs commented Mar 22, 2020

Hi Scott! I think it's ready.
I hit a snag for a while on the error bar offset, but I figured it out. I think this solution is a lot cleaner that the first draft (but there might be even more line differences now)! However, one thing that's kinda hacky is the implementation of the default error bar color. These are lines 63-65 in Settings.cs. The idea is to have the user make their scatter/bar plot and then their error bar plot. We can also scrap this and just make the default error bar color black. Users can just figure out the color of the previous serious by saving the prior plot as a local variable. I don't have strong opinions either way, but I wanted to draw your attention to it. Let me know which solution you prefer.

@swharden
Copy link
Member

Hi Scott! I think it's ready .... Let me know which solution you prefer.

Thanks @zrolfs I'll take a look! It might take me a day or so, but I'll take it from here and add some modifications/commits to this branch as I go.

I'll post an update here when things are looking good to merge!

@swharden
Copy link
Member

swharden commented Mar 22, 2020

This is not @zrolfs's fault but there is a GDI rendering glitch where diagonal lines get drawn inappropriately. I ran into this before but I forgot how I solved it...

err

image

@swharden
Copy link
Member

I hit a snag for a while on the error bar offset, but I figured it out

No kidding - I'm hitting the same snag! This horizontal offset stuff is super confusing. I'm refactoring the bar plots as part of #315 and they'll be a little smarter about error bars... so I'll try removing the xOffset code from PlottableErrorBars and see if it makes it easier to work with.

I understand it may break errorbars some of the multi-bar-plot demos, but those are about to be replaced anyway due to #315 so I'm okay with that.

make names more consistent with other plottables, favor functions which return values rather than mutate arguments, favor fewer nested statements, remove xOffset
trying to prevent breaking peoples code who might rely on old methods
@zrolfs
Copy link
Contributor Author

zrolfs commented Mar 22, 2020

This is not @zrolfs's fault but there is a GDI rendering glitch where diagonal lines get drawn inappropriately. I ran into this before but I forgot how I solved it...

Yeah! I saw that too! It strangely went away if I didn't touch it for a while...

this.yNegativeError = yNegativeError;
this.capLength = (float)capLength;
this.xOffSet = xOffSet;
this.xPositiveError = SanitizeErrors(xPositiveError, xs.Length);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good change!


// customize the plot to make it look nicer
plt.Axis(-10, 110, 0, 110);
plt.Axis(null, null, 0, null);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I changed these to help me debug. For WPF, the null defaults made the plots super zoomed in on the first bar. I thought I had screwed up the code until I zoomed out. Just a heads up.

Copy link
Member

Choose a reason for hiding this comment

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

This might be a bug that just got introduced by #313... I'll take a closer look! Other cookbook have messed up auto-axis suddenly

@swharden
Copy link
Member

@zrolfs this is looking great! Sorry if I was ambiguous earlier when I suggested having a plottable errorbar would be cool for things like scatter plots and bar plots - my thinking wasn't to remove that functionality from scatters and bars, but rather to provide a secondary (more customizable) way to add scatter plots. A lot of my recent comments were undoing changes to those modules which makes sure this merge won't break anybody's code out there who relies on the existing functionality (and it also makes the PR/merge easier to review because it's fewer files!)

I going to keep working on this a bit more, but thought I'd give you an update

@zrolfs
Copy link
Contributor Author

zrolfs commented Mar 22, 2020

Thanks for keeping me posted! I've really appreciated your support and communication. The code base was pretty intuitive and fun to work on, too! If this doesn't get merged by Monday, I'll probably just make a local nuget release for my project, so no rush.

Probably doesn't have to be fancy. I suspect people will plot errors without plotting things like scatter plots at all. Just errors are useful sometimes, and getting too fancy with the color determination could make that more complex than it needs to be.
so it shows in legend
@swharden
Copy link
Member

swharden commented Mar 22, 2020

Thanks for keeping me posted! I've really appreciated your support and communication. The code base was pretty intuitive and fun to work on, too!

That's great to hear! It's a lot of work to keep this library minimal and light, but it's worth it because it's so much nicer of a library to work in!

If this doesn't get merged by Monday, I'll probably just make a local nuget release for my project, so no rush.

Whatever you're comfortable with. I suspect this will be done by then, but the auto-axis bug that just got introduced in #313 might wind up in there too so you might do well to wait for the "official" one which will be right on its heels.

Regarding this PR, we're getting there! Still want to make a few tweaks, but I think this plottable stands nicely on its own

image

EDIT: after fixing GetLimits():

image

@swharden
Copy link
Member

swharden commented Mar 22, 2020

there is a GDI rendering glitch where diagonal lines get drawn inappropriately. I ran into this before but I forgot how I solved it...

image

HOW TO FIX THE GDI RENDERING GLITCH / NOTE TO FUTURE SCOTT: This GDI rendering glitch only affects small, perfectly level lines drawn with anti-aliasing mode disabled. I fixed this glitch by applying a slight offset to one of the points of the line so it's not perfectly flat. The tilt is invisible to humans, but it fixes the glitch

@swharden
Copy link
Member

@zrolfs this looks great! I'm gong to merge and close this PR now. I'll release a new NuGet package later today. Thanks for all your hard work!

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.

3 participants