
Panning and Zooming
JuergenD wrote at 2012-11-07 15:51:
Hi, thanks for this great Plot-Library!
I have a question about panning and zooming charts. I have a time series with data for every day for about ten years. I created a simple line chart with this data and everything looks nice. But I have a problem with the zoom/pan feature.
Using the Mousewheel or the +/- Key zooms the chart in both directions (x and y axis). But I need the zoom only on the x-axis and the y-axis should scale itself automatically by the new min/max values inside the chart window.
Also panning the chart left/right with the cursor keys should rescale the y-axis.
Is this possible?
Best Regards
Juergen
objo wrote at 2012-11-07 16:15:
Sorry, this is not supported 'out of the box'.
You could subscribe to the x-axis change event, then find the minimum and maximum y-values for the visible part of the curve (you have to write this yourself).
Then update the minimum and maximum properties of the y-axis and refresh the plot.
This should work for both mouse and keyboard events.
JuergenD wrote at 2012-11-08 09:31:
Oh wow, that was quick :-) Thanks for your fast response.
I will try to add your suggestions to my code. Thanks for your help.
JuergenD wrote at 2012-11-08 13:22:
Ok, I was playing around with the code but without success. How can I update the min/max Values of the y-axis?
I can access the min/max DateTime Values from the visible range inside the change event like so
void xAxisDateTime_AxisChanged(object sender, AxisChangedEventArgs e) { DateTimeAxis axis = sender as DateTimeAxis; DateTime dtMax = DateTime.FromOADate(axis.ActualMaximum); DateTime dtMin = DateTime.FromOADate(axis.ActualMinimum);
But when I try to update the min/max values of the y-axis with new values I already retrieved from my data:
myYAxis.Minimum = GetMin(dtMin, dtMax); myYAxis.Maximum = GetMax(dtMin, dtMax); myPlot.RefreshPlot(true);
nothing happens. How can I refresh the chart?
By the way, I am using class variables (myPlot, myYAxis) to access the plot components. Is it possible to get access to the components via the "sender" object? I am in the X-Axis event handler. How can I access the Y-Axis or the series of my plotmodel without
using class variables?
Best Regards
Juergen
JohnnyPP wrote at 2012-11-13 21:15:
Hello,
what is the status of this thread? I am also very interested in the feature that zooms only the x-axis and the y-axis scales itself automatically by the new min/max values inside the chart window.
Kind regards,
Johnny
JuergenD wrote at 2012-11-14 09:48:
@JohnnyPP
The status is unchanged. Unfortunately I got no response from the author anymore.
The current implemented zoom/pan feature feels more like a zoom/pan inside a drawing software like Photoshop. In my opinion it makes no sense to zoom/pan a chart this way. It is pretty useless to see areas of my chart without the function graph or data series. Therefore I would prefer an option to force the chart to show always a piece of my function and disable the possibility to pan or zoom to an area where the function or the dataseries does not exist.
I would need an example or information about how I can change the min/max values for the y-axis and then force a redraw of the chart. It does not work with the method I already tested (see my prev. message).
Another problem is to get access to the y-axis and the series from inside x-axis event handler. I can use "global" class variables, but this is a bit clumsy...
Please let me know when you get any further information.
Best Regards,
Juergen
objo wrote at 2012-11-14 18:36:
The Minimum and Maximum properties are overridden by the ViewMaximum and ViewMinimum properties (which are set when you pan/zoom your axes). You can
a) call Reset() then set Minimum and Maximum on the y-axis
or
b) call Zoom(newMinimum,newMaximum) on the y-axis
Then call RefreshPlot as you do in your code.
JuergenD wrote at 2012-11-15 09:57:
@objo
No need to be sorry, the software is free and I am very grateful for your work :-)
Your last hint was the missing puzzle-piece for my code. I am using variant b and now I can pan the chart on the x-axis and the y-axis and the function plot redraws perfectly. I have to fine tune the performance of my seek min/max method for really large data series, but that should be easy...
Many Thanks for your help
and best regards
Juergen
JohnnyPP wrote at 2012-11-15 20:20:
Hello Juergen,
would it be possible for you to post your solution to the forum? It would help me a lot.
Thanks in advance!
Johnny
JuergenD wrote at 2012-11-16 10:00:
@Johnny
My program is rather to big to publish it here. But I wrote a small example, with my "solution". It is not perfect, but it works for me.
Create a new Windows Form Solution named SimpleChart, add an OxyPlot.WindowsForms.Plot control on your form, change the Layout.Doc property from None to Fill and use my code inside form1.cs.
using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; using OxyPlot; namespace SimpleChart { public partial class Form1 : Form { //I am using a small helper class for my date/value pairs //providing an IComparable Interface for using BinarySearch //in the x-axis change event class MyValue : IComparable { public DateTime Date { get; set; } public double Value { get; set; } public MyValue(DateTime d) { Date = new DateTime(d.Year, d.Month, d.Day); } public MyValue(DateTime d, double v) { Date = new DateTime(d.Year, d.Month, d.Day); Value = v; } int IComparable.CompareTo(object to) { return Date.CompareTo(((MyValue)to).Date); } } DateTimeAxis xAxisDateTime; LinearAxis yAxisValues; List<MyValue> myValues; PlotModel plotModel; LineSeries lineSeries; public Form1() { InitializeComponent(); myValues = new List<MyValue>(); DateTime startDate = new DateTime(2000, 1, 1); double startValue = 100; Random r = new Random(); for (int i = 0; i < 1000; i++, startDate = startDate.AddDays(1), startValue += (r.NextDouble() - 0.5)) { myValues.Add(new MyValue(startDate, startValue)); } plotModel = new PlotModel("Chart"); xAxisDateTime = new DateTimeAxis() { IntervalType = DateTimeIntervalType.Auto, MinorIntervalType = DateTimeIntervalType.Days, MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Dot, CalendarWeekRule = System.Globalization.CalendarWeekRule.FirstFourDayWeek, FirstDayOfWeek = DayOfWeek.Monday, Position = AxisPosition.Bottom }; //Set the min/max values of the x-axis to my min/max date to prevent zoom/pan beyond data series xAxisDateTime.AbsoluteMinimum = myValues[0].Date.ToOADate(); xAxisDateTime.AbsoluteMaximum = myValues[myValues.Count - 1].Date.ToOADate(); //calling user defined event on change xAxisDateTime.AxisChanged += xAxisDateTime_AxisChanged; yAxisValues = new LinearAxis() { MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Dot }; plotModel.Axes.Add(xAxisDateTime); plotModel.Axes.Add(yAxisValues); lineSeries = new LineSeries { Title = "Values", Color = OxyColor.FromArgb(255, 78, 154, 6), MarkerType = MarkerType.None, StrokeThickness = 1, DataFieldX = "Date", DataFieldY = "Value", ItemsSource = myValues }; plotModel.Series.Add(lineSeries); plot1.Model = plotModel; } void xAxisDateTime_AxisChanged(object sender, AxisChangedEventArgs e) { DateTimeAxis axis = sender as DateTimeAxis; //save the current min/max date values DateTime dtMax = DateTime.FromOADate(axis.ActualMaximum); DateTime dtMin = DateTime.FromOADate(axis.ActualMinimum); double minValue = double.MaxValue; double maxValue = double.MinValue; //BinarySearch, because the xAxisDateTime is sorted int idxMin = myValues.BinarySearch(new MyValue(dtMin)); int idxMax = myValues.BinarySearch(new MyValue(dtMax)); //if we can not find an exact location (result is negativ) we can use the complement //see BinarySearch help for further explanation if (idxMin < 0) idxMin = ~idxMin; if (idxMax < 0) idxMax = ~idxMax; //find the corresponding min/max values in the selected intervall for (int i = idxMin; i < idxMax; i++) { minValue = Math.Min(minValue, myValues[i].Value); maxValue = Math.Max(maxValue, myValues[i].Value); } //set y-axis min/max and redraw the chart yAxisValues.Zoom(minValue, maxValue); plotModel.RefreshPlot(true); } } }
When running the program, you have first to zoom (mouse wheel or ctrl-right mouse button) inside the chart to use the x-axis pan feature (drag with right mouse button or use cursor keys), because if it is "unzoomed" you already see the whole chart and cannot pan beyond valid x/y pairs. Ctrl-Double-Click with Right mouse button brings back the whole chart.
Hope that helps
bet regards
Juergen
endorphing wrote at 2013-10-08 17:18:
Gubo wrote at 2014-03-19 10:34:
jackRose wrote at 2014-05-06 13:18:
@objo
In any case thank you for great job!
Customer support service by UserEcho