ScottPlot/ScottPlot#1762 (comment)
ScottPlot: I want to display the value of the data point closest to the cursor from data containing gaps.
Hi, I would like to mark the highlights of the two locations indicated in the open circle.
The main code to do this is as follows:
private readonly List<ScottPlot.Plottable.SignalPlotXY> _sigsOfSeries0;
private readonly List<ScottPlot.Plottable.SignalPlotXY> _sigsOfSeries1;
private readonly ScottPlot.Plottable.MarkerPlot _highlightedPoint0;
private readonly ScottPlot.Plottable.MarkerPlot _highlightedPoint1;
private void FormsPlot1_MouseMove(object sender, MouseEventArgs e)
{
var (mousePixelX, mousePixelY) = formsPlot1.GetMousePixel();
// Search from data series 0's SignalPlotXYs.
var (x0, y0) = ChooseNearestXY(mousePixelX, mousePixelY, _sigsOfSeries0);
if (x0.HasValue && y0.HasValue)
{
_highlightedPoint0.X = x0.Value;
_highlightedPoint0.Y = y0.Value;
_highlightedPoint0.IsVisible = true;
}
// Search from data series 1's SignalPlotXYs.
var (x1, y1) = ChooseNearestXY(mousePixelX, mousePixelY, _sigsOfSeries1);
if (x1.HasValue && y1.HasValue)
{
_highlightedPoint1.X = x1.Value;
_highlightedPoint1.Y = y1.Value;
_highlightedPoint1.IsVisible = true;
}
formsPlot1.Refresh();
}
private (double? nearestXorNull, double? nearestYorNull) ChooseNearestXY(
float mousePixelX,
float mousePixelY,
IEnumerable<ScottPlot.Plottable.SignalPlotXY> sigsToSerach)
{
var mousePixelCoordinate = new ScottPlot.Coordinate(mousePixelX, mousePixelY);
double? minDistance = null;
(double? nearestX, double? nearestY) = (null, null);
foreach (var sig in sigsToSerach)
{
(var mouseUnitX, _) = formsPlot1.GetMouseCoordinates(sig.XAxisIndex, sig.YAxisIndex);
(var x, var y, _) = sig.GetPointNearestX(mouseUnitX);
(var nearestPixelX, var nearestPixelY) = formsPlot1.Plot.GetPixel(x, y, sig.XAxisIndex, sig.YAxisIndex);
var nearestPixelCoordinate = new ScottPlot.Coordinate(nearestPixelX, nearestPixelY);
var nowDistance = mousePixelCoordinate.Distance(nearestPixelCoordinate);
if (minDistance == null || minDistance > nowDistance)
{
(nearestX, nearestY) = (x, y);
minDistance = nowDistance;
}
}
return (nearestX, nearestY);
}
The sample data is generated as follows:
public DemoForm6()
{
_sigsOfSeries0 = new();
_sigsOfSeries1 = new();
InitializeComponent();
// create data for series0.
var series0_segment0 = new (double x, double y)[]
{
(1, 5), (2, 4), (3, 8),
};
var series0_segment1 = new (double x, double y)[]
{
(5, 6), (6, 9), (7, 4), (8, 7),
};
var series0_segment2 = new (double x, double y)[]
{
(10, 8), (11, 3), (12, 7),
};
// create data for series1.
var series1_segment0 = new (double x, double y)[]
{
(1, 40), (2, 30), (3, 60),
};
var series1_segment1 = new (double x, double y)[]
{
(6, 70), (7, 90), (8, 40), (9, 70),
};
// set up axises.
var plot = formsPlot1.Plot;
plot.SetAxisLimitsX(xMin: 0, xMax: 13);
var labelOfDataSeries0 = "Data Series 0";
plot.YAxis.Label(labelOfDataSeries0);
plot.YAxis.Ticks(enable: true);
plot.SetAxisLimits(yMin: 0, yMax: 10, yAxisIndex: 0);
var labelOfDataSeries1 = "Data Series 1";
plot.YAxis2.Label(labelOfDataSeries1);
plot.YAxis2.Ticks(enable: true);
plot.SetAxisLimits(yMin: 0, yMax: 100, yAxisIndex: 1);
// set up for descriptions on plot.(marker, hspan and tooltip)
SetupForDescription(plot);
// series0.
foreach (var segments in new[] { series0_segment0, series0_segment1, series0_segment2, })
{
var xs0 = segments.Select(pair => pair.x).ToArray();
var ys0 = segments.Select(pair => pair.y).ToArray();
var sig = plot.AddSignalXY(xs0, ys0, label: labelOfDataSeries0, color: ScottPlot.Palette.Category10.GetColor(0));
sig.YAxisIndex = 0;
_sigsOfSeries0.Add(sig);
labelOfDataSeries0 = null; // legend label shows only first segment.
}
// series1.
foreach (var segments in new[] { series1_segment0, series1_segment1, })
{
var xs0 = segments.Select(pair => pair.x).ToArray();
var ys0 = segments.Select(pair => pair.y).ToArray();
var sig = plot.AddSignalXY(xs0, ys0, label: labelOfDataSeries1, color: ScottPlot.Palette.Category10.GetColor(1));
sig.YAxisIndex = 1;
_sigsOfSeries1.Add(sig);
labelOfDataSeries1 = null; // legend label shows only first segment.
}
// set up for highlighted point
_highlightedPoint0 = plot.AddPoint(0, 0);
_highlightedPoint0.YAxisIndex = 0;
_highlightedPoint0.Color = ScottPlot.Palette.Category10.GetColor(0);
_highlightedPoint0.MarkerSize = 15;
_highlightedPoint0.MarkerShape = ScottPlot.MarkerShape.filledDiamond;
_highlightedPoint0.IsVisible = false;
_highlightedPoint1 = plot.AddPoint(0, 0);
_highlightedPoint1.YAxisIndex = 1;
_highlightedPoint1.Color = ScottPlot.Palette.Category10.GetColor(1);
_highlightedPoint1.MarkerSize = 15;
_highlightedPoint1.MarkerShape = ScottPlot.MarkerShape.filledDiamond;
_highlightedPoint1.IsVisible = false;
plot.Legend();
formsPlot1.Refresh();
formsPlot1.MouseMove += FormsPlot1_MouseMove;
formsPlot1.MouseLeave += FormsPlot1_MouseLeave;
}
The complete code is here.
This code is working as I expect, but
Is there a better way to do this than the way I am doing it with my ChooseNearestXY
method?
I would be grateful if you could give me some advice.
Best Regards,