Skip to content

Incorrect IHasPoints.GetPointNearestX results using SignalPlotXY  #809

@at2software

Description

@at2software

ScottPlot version v4.1.8-beta

Note: this might be related to #548 and maybe this function is just not yet supported for SignalPlotXY (then this is not a bug of course, but probably this function should then not be available to SignalPlotXY instead of returning false values).

There seems to be an issue with the results returned by IHasPoints.GetPointNearestX with a SignalPlotXY when the x values aren't consecutive integers starting at zero.
Here is an example to highlight the nearest point of a ScatterPlot (adapted from here)

public partial class MainWindow : Window
{
	private readonly IHasPoints plottable;
	private readonly ScatterPlot HighlightedPoint;
	private int LastHighlightedIndex = -1;

	public MainWindow()
	{
		InitializeComponent();

		int sampleCount = 50;
		double[] xs = new double[sampleCount];
		double[] ys = new double[sampleCount];

		Random rand = new Random(0);
		for (int i = 0; i < 50; i++)
		{
			xs[i] = DateTime.Now.ToOADate() + i*10;
			ys[i] = i > 0 ? ys[i - 1] + rand.NextDouble() - .5 : 0;
		}

		//plottable = plot.Plot.AddScatterPoints(xs, ys);    // <-- this works as expected
		plottable = plot.Plot.AddSignalXY(xs, ys);
			
		HighlightedPoint = plot.Plot.AddPoint(0, 0);
		HighlightedPoint.Color = System.Drawing.Color.Red;
		HighlightedPoint.MarkerSize = 10;
		HighlightedPoint.MarkerShape = MarkerShape.openCircle;
		HighlightedPoint.IsVisible = false;

		plot.Plot.XAxis.DateTimeFormat(true);
	}

	private void plot_MouseMove(object sender, MouseEventArgs e)
	{
		(double mouseCoordX, double mouseCoordY) = plot.GetMouseCoordinates();

		// these results are incorrect when plottable is SignalPlotXY:
		(double pointCoordX, double pointCoordY, int pointIndex) = plottable.GetPointNearestX(mouseCoordX);

		// highlight the point of interest
		HighlightedPoint.Xs[0] = pointCoordX;
		HighlightedPoint.Ys[0] = pointCoordY;
		HighlightedPoint.IsVisible = true;

		tbPointCoord.Text = $"{pointCoordX:N1}, {pointCoordY:N1}";
		tbIndex.Text = pointIndex.ToString();

		if (LastHighlightedIndex != pointIndex)
		{
			LastHighlightedIndex = pointIndex;
			plot.Render();
		}
	}
}

With the ScatterPlot this works as expected. Changing the IHasPoints plottable to SignalPlotXY, GetPointNearestX now gives wrong results, the index always relates to x=0. This is especially striking when using DateTimeFormat(true) as here we provide DateTime.ToOADate() values as xs values, which e.g. are in the range of 44000 and above. So here, the determined index by GetPointNearestX is always the max index of the array (49 in the example case).

I guess this is because here

int index = (int)((x - OffsetX) / SamplePeriod);
it is assumed that the x parameter is directly correlated to the index, which is true for SignalPlot but not for SignalPlotXY. Probably GetPointNearestX should be made virtual in SignalPlotBase and SignalPlotXY would need to override it with an implementation to determine the index based on the parameter value similar to here
public (double x, double y, int index) GetPointNearestX(double x)
{
int from = MinRenderIndex ?? 0;
int to = MaxRenderIndex ?? (Xs.Length - 1);
double minDistance = Math.Abs(Xs[from] - x);
int minIndex = 0;
for (int i = from; i <= to; i++)
{
double currDistance = Math.Abs(Xs[i] - x);
if (currDistance < minDistance)
{
minIndex = i;
minDistance = currDistance;
}
}
return (Xs[minIndex], Ys[minIndex], minIndex);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    BUGunexpected behavior

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions