Skip to content

SignalXY: improve rendering and extend customization options [and rename things]#4102

Closed
BrianAtZetica wants to merge 8 commits intoScottPlot:mainfrom
BrianAtZetica:SignalXYRefactor
Closed

SignalXY: improve rendering and extend customization options [and rename things]#4102
BrianAtZetica wants to merge 8 commits intoScottPlot:mainfrom
BrianAtZetica:SignalXYRefactor

Conversation

@BrianAtZetica
Copy link
Contributor

I was experiencing rendering artefacts with rotated SignalXY plots, but found it very difficult to debug these due to the confusing use of X and Y parameter names in the rotated graph context. This PR fully refactors SignalXY (double and generic versions) so that:

Xs (the array defining the uniform, ordered dimension of the signal) becomes "Positions"
Ys (the unordered, measured property of the signal) becomes "Amplitudes"

All method names are refactored to make their role/purpose clearer.

In the process of the refactor, I managed to:

  • resolve the rendering artefacts (illustrated below)
  • reveal and correct more serious bugs with scaled and offset SignalXY plots (illustrated below)
  • implement Position offsets (prevously listed as a ToDo in the code)
  • enable Rotated SignalXY in the generic version of the SignalXY plotable.

The main artefact was best illustrated when plotting a rotated signal on inverted axes

        var size = 500;
        var cycles = 1;
        double[] xs = Generate.Consecutive(size);
        double[] ys = Generate.Sin(count: xs.Length, oscillations: cycles);

        var sig1 = WpfPlot1.Plot.Add.SignalXY(xs, ys);
        sig1.Data.Rotated = true;
        WpfPlot1.Plot.Axes.InvertX();
        WpfPlot1.Plot.Axes.InvertY();

RotatedSignalXY_InvertedBefore

After this PR the same code produces a smooth sinusoid:
RotatedSignalXY_PositionOffsetAfter

Aretefacts with incomplete handling of offsets canbe seen with teh following code:

        var size = 500;
        var cycles = 1;
        double[] xs = Generate.Consecutive(size);
        double[] ys = Generate.Sin(count: xs.Length, oscillations: cycles);

        var sig1 = WpfPlot1.Plot.Add.SignalXY(xs, ys);
        sig1.Data.Rotated = true;
        sig1.Data.YOffset = 2;

RotatedSignalXY_YOffsetBefore

After this PR the same code (except YOffset replaced with AmplitudeOffset) produces a smooth sinusoid:
RotatedSignalXY_AmplitudeOffsetAfter

Similarly with XOffset in original code:
RotatedSignalXY_XOffsetBefore

And with PositionOffset in revised code:
RotatedSignalXY_PositionOffsetAfter

Similarly with YScale in original code:
RotatedSignalXY_YScaleBefore

And with AmplitudeScale in revised code:
RotatedSignalXY_AmplitudeScaleAfter

For completeness, the following illustrates the newly exposed PositionScale option:
RotatedSignalXY_PositionScaleAfter

Finally, I have float versions of some of the Generate functions for convenience when testing the generic version of the SignalXY (maybe the naming convention isn't right for these functions?):

        var size = 500;
        var cycles = 1;
        float[] xs = Generate.fConsecutive(size);
        float[] ys = Generate.fSin(count: xs.Length, oscillations: cycles);

        var sig1 = WpfPlot1.Plot.Add.SignalXY(xs, ys);
        sig1.Data.Rotated = true;

Note that I am using the Rotated option here with generic SignalXY class.

The main resolution to the original rendering artefacts was changing the order of the min and max values in each pixel column to prevent unecessary over-drawing of hte continuous line through the listed pixels.

…g rotated plots.

Xs becomes Positions (the uniform, ordered dimension of the signal)
Ys becomes Amplitudes (the measured property of the signal).
This commit also resolves some minor rendering glitches
Introduces rotated option for Generic SignalXY plots and
finishes introduction of an offset along the Positions domain.
@KroMignon
Copy link
Contributor

Hello @BrianAtZetica,
I think it is a good idea to replace X and Y with more explicit names, but it is also an API break, which is also pretty uncool.

I am also not very happy with the names Positions and Amplitudes, but this is just a matter of taste 😕
I would prefer Abscissas and Ordinates, but will also be an API break 😇

@BrianAtZetica
Copy link
Contributor Author

I had a long conversation with ChatGPT about what terms to use to replace X and Y 😄 at one point "Range" was in the mix for X, until I realised I would have a parameter called range range 😁

Am definitely open to the popular vote (although I'm not sure how intuitive Abscissa and Ordinate will be across the user base).

Understand the reluctance about API change. Not sure how best to approach that.

@BrianAtZetica
Copy link
Contributor Author

@KroMignon maybe I can reinstate XOffset, YOffset and YScale as obselete properties that set PositionOffset, AmplitudeOffset and AmplitudeScale respectively. That should take care of the breaking changes ?

@KroMignon
Copy link
Contributor

maybe I can reinstate XOffset, YOffset and YScale as obselete properties that set PositionOffset, AmplitudeOffset and AmplitudeScale respectively. That should take care of the breaking changes ?

This sounds good to me!

@StendProg
Copy link
Contributor

Hi @BrianAtZetica, @KroMignon

It is unlikely that someone will want to rotate SignalXY while the program is running. Most likely they will use one or the other from the beginning.

Maybe we should create two separate plottables SignalXY and SignalYX without any rotation capabilities.
To avoid duplicating common code, they can be derived from SignalXYBase which contains common parts.

The proposed renaming is confusing, the amplitude is associated with periodic signals.
I suggest using (Signal)Argument and (Signal)Value/Function. This reflects the limitations of the signal, it can only be a functional dependence y = f(x).

@BrianAtZetica
Copy link
Contributor Author

It is unlikely that someone will want to rotate SignalXY while the program is running. Most likely they will use one or the other from the beginning.

My program allows the user to do exactly this. I dont want to have to change from one plottable type to another. The rotate option is a great feature for exposing choice to the end user.

The proposed renaming is confusing, the amplitude is associated with periodic signals.

I disagree that 'amplitude' implies periodicity. Amplitude is simply the magnitude or value of a signal.

I think we will struggle to identify any two words with unanimous agreement:

  • To me, Time (or Range) and Amplitude make the most sense (I work in radar and seismic time series). But not all graphs will be time based, so I settled on Position and Amplitude
  • I understand the suggestion by @KroMignon for Abscissas and Ordinates but most definitions for these terms directly relate them back to cartesian space (i.e. X and Y). It is a little ambiguous how these terms apply to a rotated signal.
  • I also understand the suggestion by @StendProg for Argument and Value but value is used in another context throughout C# so could be confusing, and I dont think argument is very intuitive either.
  • Another option could be IndependentValue and DependentValue but these are similar terms easily mixed up.
  • Maybe IndependentValue and Magnitude is a good balance (albeit slightly wordier than Position)

So how do we choose (it doesn't matter too much to me, so long as we can avoid mixing up X and Y variables with X and Y axes)? I'll wait for @swharden to weigh in.
In the meantime, I've reinstated the XOffset, YOffset and YScale as obselete properties.

@KroMignon
Copy link
Contributor

@BrianAtZetica

  • I understand the suggestion by @KroMignon for Abscissas and Ordinates but most definitions for these terms directly relate them back to cartesian space (i.e. X and Y). It is a little ambiguous how these terms apply to a rotated signal.

This is why I suggest them as SignalXY is for me signal in Cartesian space 😄 no matter if it is rotated or inverted...
But as written before, this is just my own feeling, I am not a ScottPlot maintainer, I am using it in some of my test applications.

For me, the very important point is that there is no API break, and currently developed software still works.

@StendProg

Maybe we should create two separate plottables SignalXY and SignalYX without any rotation capabilities.

I cannot see any benefit of this suggestion? Having the capability to rotate does not imply that you have to use it... So why create a new plottable type?

… longer needed following refactor and improvements made in PR ScottPlot#4102.

This should boost performance slightly.
… longer needed following refactor and improvements made in PR ScottPlot#4102.

This should boost performance slightly (this time remembering rotated SignalXY part of code).
@swharden
Copy link
Member

Hi @BrianAtZetica and the group, this is a great PR and the discussion here is really interesting too! I plan to leave this PR open for a little longer while I close out simpler high-priority open issues, then I'll publish a new release to NuGet tomorrow, then I'll loop back here and pick this PR up again.

If this PR were limited to fixing the rendering artifacts, adding custom offset support, and improving rotation support, I'd merge it in now and publish it in the next release. However, because the PR also renames some important things, I'm inclined to put more time and research into considering the best way to proceed before merging this one.

I will offer my quick thoughts on the topic of naming, and I welcome feedback. The discussion of naming extends beyond SignalXY plots because I think it makes sense to keep names consistent with Signal and SignalConst plots too, so we're talking about potentially renaming a lot of things here. Overall I like the idea of renaming properties Xs and Ys to something more "direction agnostic". Positions seems good, but I'm not sure about Amplitudes because Signal plots can plot things that aren't signals (like the number of GitHub stars in the graph at the bottom of https://scottplot.net). I think this means there's another naming issue! I don't have an opinionated answer to this, but I'll ask the question: Should Signal plots be called something else? I'm in favor of choosing the best name possible, and if renaming properties is on the table already then maybe now's a time to consider it. It may seem like a big breaking change, but I don't think it has to be. If we make a new plot type using the new names (e.g., a Sequential plot type with Positions and Values) we can leave the existing classes how they are, but have them inherit the new thing and forward the old property names to the new ones. I assume we can figure out how to do this in a way that's non-breaking, so if we have total freedom to rename everything here I think it may be worth considering what the best possible names would be.

I'll put this down for a few days but pick it up again next week. Thanks again everyone for your input!

@swharden swharden changed the title Signal xy refactor and improvements SignalXY: improve rendering and extend customization options [and rename things] Jul 27, 2024
@BrianAtZetica
Copy link
Contributor Author

@swharden, understood. As I said, I needed to rename things to work through and understnad the code logic before I could find the small indexing and X/Y confusions that were causing some of the artefacts.

But, now that I understand it better, I've managed to achieve the same fixes to rendering starting from the current main branch. I'll make another PR, to keep the refactorign as a seperate issue.

@swharden
Copy link
Member

I've managed to achieve the same fixes to rendering starting from the current main branch. I'll make another PR, to keep the refactoring as a separate issue.

I just merged #4112 so depending on how similar the implementation there is to this branch, we could "resolve conflicts" here, then update from main, and this PR would just track the name changes. If resolving the merge conflicts gets to hard, we can open a new PR just for the renaming and pick it up from there.

Thanks again for getting this conversation going!

@swharden swharden added the WIP / DO NOT MERGE Note to Scott not to merge this until the original contributor indicates it's ready label Jul 30, 2024
@BrianAtZetica
Copy link
Contributor Author

depending on how similar the implementation there is to this branch, we could "resolve conflicts" here, then update from main, and this PR would just track the name changes.

Sorry, slow to respond to this. But just to be clear, my intention is to follow this up in a few weeks time, as work allows.

@BrianAtZetica
Copy link
Contributor Author

@swharden, this has now been merged with the main branch with all conflicts resolved. I've tested it for offsets and scales in both dimensions and all seems to be OK from my perspective.

I realise now I should have rebased instead of merged, as that would have been easier to work with.

As the discussion on this thread was unresolved, I'm not sure I can take this any further.

I think the naming I've introduced in SignalXY is easier to work with, but I realise it doesn't represent the perfect naming in every use context. It also has only addressed one plot type, and your suggestion of finding consistency across other plot types makes sense.

I'll think I'll close this PR now and leave it with you to either reopen (if you think it is an incremental improvement that can be taken forward) or put the issue on a todo list somewhere else.

Thanks

@BrianAtZetica BrianAtZetica deleted the SignalXYRefactor branch November 8, 2025 05:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

WIP / DO NOT MERGE Note to Scott not to merge this until the original contributor indicates it's ready

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants