I'm using OxyPlot to show a data chart and to allow the user to select an interval of data he wants to do calculation on.
It looks like this:
Now, I would like the user to be able to set the data interval used for calculation himself by resizing the chart. For example, if he resized the chart on this particular interval it would only take the points located between the furthest left and the furthest right on screen.
I already found the event that triggers whenever the chart is resized :
plotModel.Updated += (s, e) =>
{
//reset interval used for calculation
};
What I couldn't find in OxyPlot documentation is a way to retrieve a certain set of points currently shown. It doesn't need to be points in particular, I could also use only the x components of each extremum.
You could use Series.GetScreenRectangle().Contains() method after transforming your points using the Transform() method to detect if the point is currently in display.
For example,
model.Updated += (s,e)=>
{
if(s is PlotModel plotModel)
{
var series = plotModel.Series.OfType<OxyPlot.Series.LineSeries>().Single();
var pointCurrentlyInDisplay = new List<DataPoint>();
foreach (var point in series.ItemsSource.OfType<DataPoint>())
{
if (series.GetScreenRectangle().Contains(series.Transform(point)))
{
pointCurrentlyInDisplay.Add(point);
}
}
}
};
You are iterating over the point collection and verifying if the Transformed point (Transform method transform DataPoint to screen point) falls within the Screen Rectangle used by the series.
Update
If you have used Series.Points.AddRange()/Add() for adding points instead of Series.ItemSource, use the following for retrieving points.
foreach (var point in series.Points.OfType<DataPoint>())
{
if (series.GetScreenRectangle().Contains(series.Transform(point)))
{
pointCurrentlyInDisplay.Add(point);
}
}
Related
How do i make Live Charts graph to show the last update after changing zoom
https://i.stack.imgur.com/fECsZ.png
I face the same problem after zooming and panning. My way is to let the user reset the zoom and panning when they are done looking at the point they want. I did it in code behind when the reset button is clicked.
private void btn_Reset_Click(object sender, RoutedEventArgs e)
{
foreach (var XAxis in ConstantChangeCartesianChart.AxisX)
{
XAxis.MinValue = double.NaN;
XAxis.SetRange(double.NaN, double.NaN);
}
foreach (var YAxis in ConstantChangeCartesianChart.AxisX)
{
YAxis.MinValue = double.NaN;
YAxis.SetRange(double.NaN, double.NaN);
}
}
This will simply reset all the range and minimum value. Hope this help.
I'm writing a graphing program, and I want to be able to hover my mouse over a point on the graph to reveal details about the point. I'm aware of MouseHover(), but that only works when hovering over the form, not specific points on the form. I've written a function that works, but is incredibly resource intensive and not very reliable using MouseHover:
List<List<Point>> Points { get; set; } = new();
private async void GraphPanel_MouseHover(object sender, EventArgs e)
{
await Task.Run(() => {
do
{
foreach(var pointList in Points)
{
foreach (Point point in pointList)
{
if (Control.MousePosition == point)
{
throw new Exception();
}
}
}
}
while (true);
});
}
Is there a more practical way of doing this?
MouseHover is called a lot of times. You can:
Save mouse position into a variable in MouseHover. Save the currentTime (DateTime.UtcNow) in other variable.
Use Task.Delay to wait, for example, 100 ms. In the code executed after this delay, check if current mouse position is the same (o closest if you want work with some tolerance). Then, the mouse was 100 ms in the same position: do your work. If not, do nothing.
Avoid create a new Task if (DateTime.UtcNow-YourPreviouslySavedDate).TotalMilliSeconds is less than 100 ms
Another option is using Timer component. Set the interval and attach a method for the event (double click in the component). On the event, check mouse position and do your work.
I've started using LightningChart in my real time monitoring application. In my app there are many y axis which use segmented layout (one y axis per segment):
mainChart.ViewXY.AxisLayout.YAxesLayout = YAxesLayout.Segmented;
My goal is that when you mouse click a segment, it gets larger compared to other segments (kinda like zoom effect) and the other segments gets smaller. When you click it again it goes back to normal.
I know I can change the size of the segments with:
mainChart.ViewXY.AxisLayout.Segments[segmentNumber].Height = someValue;
That takes care of the zooming effect.
Now the problem is that how can I solve which segment was actually clicked? I figured out that you get mouse position via MouseClick -event (e.MousePos) but that seem to give only the screen coordinates so i'm not sure that it helps.
I'm using the LightningChart version 8.4.2
You are correct that getting mouse position via MouseClick event is the key here. The screen coordinates you get via e.GetPosition (not e.MousePos) can be converted to chart axis values with CoordToValue() -method. Then you just compare the y-coordinate to each y-axis minimum/maximum value to find out what segment was clicked. Here is an example:
_chart.MouseClick += _chart_MouseClick;
private void _chart_MouseClick(object sender, MouseButtonEventArgs e)
{
var mousePos = e.GetPosition(_chart).Y;
double axisPos = 0;
bool isWithinYRange = false;
foreach (AxisY ay in _chart.ViewXY.YAxes)
{
ay.CoordToValue((float)mousePos, out axisPos, true);
if (axisPos >= ay.Minimum && axisPos <= ay.Maximum)
{
// Segment clicked, get the index via ay.SegmentIndex;
isWithinYRange = true;
}
}
if (!isWithinYRange)
{
// Not in any segment
}
}
After finding out the segment index, you can modify its height as you described:
_chart.ViewXY.AxisLayout.Segments[0].Height = 1.5;
Note Height means segment height compared to other segments.
Hope this is helpful.
I am using dynamic data display library to view a dynamic integer value coming in at frequent intervals and plotting it as a linegraph ('line1') onto a chartplotter named 'plotter'. What I want is to have a way to erase all the data from the chartplotter when I uncheck the checkbox and start plotting again once i check it back. I thought I might be able to accomplish it with plotter.Children.Remove(line1), but it does not erase the old data. Instead it plots over the old data again and I have double data lines. Here is the code example (includes some pseudo codes) that I have so far.
ObservableDataSource<System.Windows.Point> source1=new ObservableDataSource<System.Windows.Point>();
LineGraph line1=new LineGraph(source1);
line1.Name = "Data1";
int i=0;
start a timer to CaptureData...
CaptureData(....,...)
{
if a CheckBox is checked...()
{
if (i == 0)
{
plotter.Children.Add(line1);
}
double graph_x = Convert.ToDouble(i);
double graph_y = Convert.ToDouble(datapoint that I have);
System.Windows.Point p1 = new System.Windows.Point(graph_x, graph_y);
source1.AppendAsync(Dispatcher, p1);
i++;
}
}
Once the checkBox is unchecked
{
if (i != 0)
{
i=0;
plotter.Children.Remove(line1);
}
}
}
This is the linegraph that I am getting now with data starting to plot again at the beginning, but the old data is still hanging in there. What I want to achieve is a clean new graph without the old line present. I don't have the minimum points to post an image. So please see the image here: https://dl.dropboxusercontent.com/u/49447650/test5.png
You have to clear the source :
source1.RemoveAll(typeof(Point));
I have added the scroll bar to the x-axis of my mschart control using this link Adding a scroll bar to MS Chart control C# and it worked as expected. But now my requirement is, I need zooming for both the axis. But since I removed Zoom reset button for x-axis, I have used the following to reset it by forcing.
private void chart1_AxisScrollBarClicked(object sender, ScrollBarEventArgs e)
{
// Handle zoom reset button
if(e.ButtonType == ScrollBarButtonType.ZoomReset)
{
// Event is handled, no more processing required
e.IsHandled = true;
// Reset zoom on X and Y axis
chart1.ChartAreas[0].AxisX.ScaleView.ZoomReset();
chart1.ChartAreas[0].AxisY.ScaleView.ZoomReset();
}
}
But it is not working properly. Please help me in fixing this in c#..
Try using ZoomReset(0).
private void zeroZoom_Click(object sender, EventArgs e)
{
chart1.ChartAreas[0].AxisX.ScaleView.ZoomReset(0);
chart1.ChartAreas[0].AxisY.ScaleView.ZoomReset(0);
}
The first thing coming in mind, is that your problem is related to multiple zooming.
As you had noticed, by default the zoom-reset button (exactly like the ZoomReset method) doesn't reset the zoom completely, but restore the previous view-status, i.e. if you have zoomed more than one time, it returns just to the previous zoomed view.
To completely reset the zoom, you can use this code:
while (chart1.ChartAreas[0].AxisX.ScaleView.IsZoomed)
chart1.ChartAreas[0].AxisX.ScaleView.ZoomReset();
while (chart1.ChartAreas[0].AxisY.ScaleView.IsZoomed)
chart1.ChartAreas[0].AxisY.ScaleView.ZoomReset();
Conversely, if you like the default zoom-reset behaviour, you should have two buttons for the two axis because it's possible to have different number of view-statex for the different axis.
Another possibility, is that you are zooming a secondary axis, like AxisX2 or AxisY2 (not sure, but I think that is depending on the chart type), so you should reset those (or, to be safe, just reset all axis...).
I tried with the below code today and it seems like working fine. Here the for loop handles the X axis with scroll and the next if block handles the ordinary X-axis. Could you please have a glance at it and let me know your views about it?
private void chart1_AxisScrollBarClicked(object sender, ScrollBarEventArgs e)
{
Boolean blnIsXaxisReset = false;
try
{
// Handle zoom reset button
if(e.ButtonType == ScrollBarButtonType.ZoomReset)
{
// Event is handled, no more processing required
e.IsHandled = true;
// Reset zoom on Y axis
while (chart1.ChartAreas[0].AxisY.ScaleView.IsZoomed)
chart1.ChartAreas[0].AxisY.ScaleView.ZoomReset();
//Handles Zoom reset on X axis with scroll bar
foreach (Series series in chart1.Series)
{
if (series.YAxisType == AxisType.Secondary)
{
chart1.ChartAreas[0].AxisX.ScaleView.Zoom(-10, 10);
blnIsXaxisReset = true;
break;
}
}
//Handles Zoom reset on ordinary X axis
if (blnIsXaxisReset == false)
{
while (chart1.ChartAreas[0].AxisX.ScaleView.IsZoomed)
chart1.ChartAreas[0].AxisX.ScaleView.ZoomReset();
}
}
}
catch (Exception ex)
{
BuildException buildException = new BuildException();
buildException.SystemException = ex;
buildException.CustomMessage = "Error in zooming the Chart";
ExceptionHandler.HandleException(buildException);
}
}
Thanks for your effort!!