Track all the series same time?
aapov wrote at 2014-01-06 20:36:
When I activate the tracker, it shows only values from one serie. Is it possible to show values of all the series which vertical tracker crosses? I could do this outside of plot control, but how do I get the X-axis value of current tracker?
objo wrote at 2014-01-07 22:14:
https://oxyplot.codeplex.com/workitem/10017
and not yet implemented
I think you can get the x-axis value from the TrackerChanged event!
aapov wrote at 2014-01-08 19:30:
Scatter series on heat map
BlindMonk wrote at 2014-01-20 17:00:
These points are dynamic so the background image remains the same, but the overlay points change.
any leads please.
thanks
objo wrote at 2014-01-27 19:21:
Performance for the heat map can be an issue if you need a high refresh rate for the dynamic points.
CSharpdevs wrote at 2014-05-15 14:13:
The code is given below:
PlotModel pm ;
pm = new PlotModel();
OxyPlot.Axes.LinearColorAxis lca = new OxyPlot.Axes.LinearColorAxis();
lca.HighColor = OxyColors.Gray;
lca.LowColor = OxyColors.Black;
lca.Position = OxyPlot.Axes.AxisPosition.Right;
pm.Axes.Add(lca);
OxyPlot.Axes.LinearAxis la = new OxyPlot.Axes.LinearAxis();
la.Position = OxyPlot.Axes.AxisPosition.Bottom;
pm.Axes.Add(la);
OxyPlot.Series.HeatMapSeries hm = new OxyPlot.Series.HeatMapSeries();
hm.Interpolate = true;
hm.X0 = 0;
hm.X1 = 8;
hm.Y0 = 0;
hm.Y1 = 8;
hm.Data = new double[9, 9];
hm.Data[3, 5] = 5;
hm.Data[4 ,5] = 5;
hm.Data[2, 4] = 5;
hm.Data[5, 4] = 5;
hm.Data[3, 3] = 5;
hm.Data[4, 3] = 5;
hm.Data[3, 7] = 15;
hm.Data[4, 7] = 15;
hm.Data[6, 6] = 15;
hm.Data[7, 4] = 15;
hm.Data[6, 2] = 15;
hm.Data[4, 1] = 15;
hm.Data[2, 2] = 15;
hm.Data[1, 4] = 15;
hm.Data[2, 6] = 15;
pm.Series.Add(hm);
OxyPlot.Series.ScatterSeries sc = new OxyPlot.Series.ScatterSeries(); sc.BinSize = 8;
sc.MarkerStrokeThickness = 3;
sc.MarkerType = MarkerType.Circle;
sc.MarkerFill = OxyColors.Black;
sc.Points.Add(new OxyPlot.Series.ScatterPoint(0, 0, 5));
sc.Points.Add(new OxyPlot.Series.ScatterPoint(3, 1, 2));
sc.Points.Add(new OxyPlot.Series.ScatterPoint(5, 5, 5));
sc.Points.Add(new OxyPlot.Series.ScatterPoint(1, 5, 7));
sc.Points.Add(new OxyPlot.Series.ScatterPoint(2, 2, 5));
sc.Points.Add(new OxyPlot.Series.ScatterPoint(8, 8, 5));
pm.Series.Add(sc);
plot1.Model = pm;nickn3710 wrote at 2014-05-27 22:23:
CSharpdevs wrote at 2014-05-30 13:54:
Best regards.
using System;
namespace MicroLibrary
{
/// <summary>
/// MicroStopwatch class
/// </summary>
public class MicroStopwatch : System.Diagnostics.Stopwatch
{
readonly double _microSecPerTick =
1000000D / System.Diagnostics.Stopwatch.Frequency;
public MicroStopwatch()
{
if (!System.Diagnostics.Stopwatch.IsHighResolution)
{
throw new Exception("On this system the high-resolution " +
"performance counter is not available");
}
}
public long ElapsedMicroseconds
{
get
{
return (long)(ElapsedTicks * _microSecPerTick);
}
}
}
/// <summary>
/// MicroTimer class
/// </summary>
public class MicroTimer
{
public delegate void MicroTimerElapsedEventHandler(
object sender,
MicroTimerEventArgs timerEventArgs);
public event MicroTimerElapsedEventHandler MicroTimerElapsed;
System.Threading.Thread _threadTimer = null;
long _ignoreEventIfLateBy = long.MaxValue;
long _timerIntervalInMicroSec = 0;
bool _stopTimer = true;
public MicroTimer()
{
}
public MicroTimer(long timerIntervalInMicroseconds)
{
Interval = timerIntervalInMicroseconds;
}
public long Interval
{
get
{
return System.Threading.Interlocked.Read(
ref _timerIntervalInMicroSec);
}
set
{
System.Threading.Interlocked.Exchange(
ref _timerIntervalInMicroSec, value);
}
}
public long IgnoreEventIfLateBy
{
get
{
return System.Threading.Interlocked.Read(
ref _ignoreEventIfLateBy);
}
set
{
System.Threading.Interlocked.Exchange(
ref _ignoreEventIfLateBy, value <= 0 ? long.MaxValue : value);
}
}
public bool Enabled
{
set
{
if (value)
{
Start();
}
else
{
Stop();
}
}
get
{
return (_threadTimer != null && _threadTimer.IsAlive);
}
}
public void Start()
{
if (Enabled || Interval <= 0)
{
return;
}
_stopTimer = false;
System.Threading.ThreadStart threadStart = delegate()
{
NotificationTimer(ref _timerIntervalInMicroSec,
ref _ignoreEventIfLateBy,
ref _stopTimer);
};
_threadTimer = new System.Threading.Thread(threadStart);
_threadTimer.Priority = System.Threading.ThreadPriority.Highest;
_threadTimer.Start();
}
public void Stop()
{
_stopTimer = true;
}
public void StopAndWait()
{
StopAndWait(System.Threading.Timeout.Infinite);
}
public bool StopAndWait(int timeoutInMilliSec)
{
_stopTimer = true;
if (!Enabled || _threadTimer.ManagedThreadId ==
System.Threading.Thread.CurrentThread.ManagedThreadId)
{
return true;
}
return _threadTimer.Join(timeoutInMilliSec);
}
public void Abort()
{
_stopTimer = true;
if (Enabled)
{
_threadTimer.Abort();
}
}
void NotificationTimer(ref long timerIntervalInMicroSec,
ref long ignoreEventIfLateBy,
ref bool stopTimer)
{
int timerCount = 0;
long nextNotification = 0;
MicroStopwatch microStopwatch = new MicroStopwatch();
microStopwatch.Start();
while (!stopTimer)
{
long callbackFunctionExecutionTime =
microStopwatch.ElapsedMicroseconds - nextNotification;
long timerIntervalInMicroSecCurrent =
System.Threading.Interlocked.Read(ref timerIntervalInMicroSec);
long ignoreEventIfLateByCurrent =
System.Threading.Interlocked.Read(ref ignoreEventIfLateBy);
nextNotification += timerIntervalInMicroSecCurrent;
timerCount++;
long elapsedMicroseconds = 0;
while ( (elapsedMicroseconds = microStopwatch.ElapsedMicroseconds)
< nextNotification)
{
System.Threading.Thread.SpinWait(10);
}
long timerLateBy = elapsedMicroseconds - nextNotification;
if (timerLateBy >= ignoreEventIfLateByCurrent)
{
continue;
}
MicroTimerEventArgs microTimerEventArgs =
new MicroTimerEventArgs(timerCount,
elapsedMicroseconds,
timerLateBy,
callbackFunctionExecutionTime);
MicroTimerElapsed(this, microTimerEventArgs);
}
microStopwatch.Stop();
}
}
/// <summary>
/// MicroTimer Event Argument class
/// </summary>
public class MicroTimerEventArgs : EventArgs
{
// Simple counter, number times timed event (callback function) executed
public int TimerCount { get; private set; }
// Time when timed event was called since timer started
public long ElapsedMicroseconds { get; private set; }
// How late the timer was compared to when it should have been called
public long TimerLateBy { get; private set; }
// Time it took to execute previous call to callback function (OnTimedEvent)
public long CallbackFunctionExecutionTime { get; private set; }
public MicroTimerEventArgs(int timerCount,
long elapsedMicroseconds,
long timerLateBy,
long callbackFunctionExecutionTime)
{
TimerCount = timerCount;
ElapsedMicroseconds = elapsedMicroseconds;
TimerLateBy = timerLateBy;
CallbackFunctionExecutionTime = callbackFunctionExecutionTime;
}
}
}Clicking on an annotation
Slxe wrote at 2014-05-01 17:46:
I've read through the code for the various mouse event examples but haven't had one that covers my issue. I'm looking to dynamically add and remove events to annotations, which means I've had to implement them as methods instead of lambdas.
The issue I'm running into now is how to actually get the annotation clicked on from what's passed to the method. I haven't found a way to access it from the PlotController or OxyMouseDownEventArgs.
Any suggestions are much appreciated! It wouldn't be the first time I'd missed something obvious hehe. Hopefully when I'm done this I'll have something interesting to add to the WinForms demos and help other people out.
Slxe wrote at 2014-05-09 17:13:
objo wrote at 2014-05-10 22:54:
UIPlotElement
should not take the sender as a parameter. Also, I see it is convenient to include the element that is hit in the HitTestResults.
I am submitting a change that should fix this. I have added two examples that should be close to what you need. Have a look at the source code!
Slxe wrote at 2014-05-12 16:07:
Yea I noticed HitTestResults only had the item and index, it didn't actually have a reference to the element clicked on, so I was hoping to find another solution. Thanks for the examples and the fix, this is exactly what I was hoping for! I'm playing around with the idea of adding a drawing toolbar to the chart display to allow the users to draw annotations onto it without having to save it and editing it in paint, with the added bonus of having things drawn be below the series I figured it'd quite helpful and faster than what they're doing now for their reports. Hopefully when I'm done I can cut it up and submit it as an example too.
Now I just have to find a nice way to sync the Axes when the user Zooms. I've got it working for just plain zooming (and panning), but I had to disable mouse wheel and +/- zooming as using ZoomAt throws it all to hell (I'm essentially transforming the actual minimum and maximum points to a screen point, then back to points on the new axes). I noticed the wdf example, but it doesn't help much when the axes have very different data on them. Would be nice if the AxisChanged event somehow had access to the pan/zoom amounts.
Thanks again for the help objo.
objo wrote at 2014-05-12 16:34:
We have a feature request for synchronization of the axes: https://oxyplot.codeplex.com/workitem/9945
I am not sure if this covers your case, I don't quite understand your usage.
It should be easy to add pan/zoom deltas in the axis changed event arguments, but I have not yet seen a need for this.
Slxe wrote at 2014-05-12 17:20:
private void axis_AxisChanged(object sender, AxisChangedEventArgs args) { if (_syncChange || ((Axis) sender).IsHorizontal()) return; _syncChange = true; switch (args.ChangeType) { case AxisChangeTypes.Zoom: case AxisChangeTypes.Pan: _pauseChartUpdate = true; foreach (Axis a in mainPlot.Model.Axes) { if (a.Key == ((Axis) sender).Key || a.IsHorizontal()) continue; double min = a.InverseTransform(((Axis) sender).Transform(((Axis) sender).ActualMinimum)); double max = a.InverseTransform(((Axis) sender).Transform(((Axis) sender).ActualMaximum)); a.Zoom(min, max); } break; case AxisChangeTypes.Reset: _pauseChartUpdate = false; break; } mainPlot.InvalidatePlot(false); _syncChange = false; }
But yea, this is basically how I'm handling syncing panning and zooming to the other axes. Probably not the best way to do it, but I'm still learning, and it works. This is why I mentioned it'd be nice for AxisChangedEventArgs to have the various zoom and pan values so if required it can transfer them to other axes (a way to tell the difference between Zoom and ZoomAt, basically points vs factor, would be nice too). Although because of how I've done this, if you use a zoom factor instead of screen points it doesn't translate properly to the other axes (the primary axes goes out of sync with the others).
guilhermecgs wrote at 2014-05-16 23:56:
Polar chart question
SamTauris wrote at 2014-06-27 12:35:
I'm struggling with following problem.
Hope you can help me out. :) !
I try to achive something similar to
On my case I need one series per line, and have the first point of every series be the center of the chart.
Is this possible?
objo wrote at 2014-06-27 13:09:
ArrowAnnotation
can be used. If you want to use one series per line, you must specify the colour of each series. Otherwise, the default colour will be different for each series.
The position of the magnitude axis labels is not yet customizable. This is covered by https://oxyplot.codeplex.com/workitem/10223
See the latest code checkin for an example that is close to your case!
SamTauris wrote at 2014-06-27 14:05:
Thanks for the FAST response ! It works!!
simple TextAnnotation
heromyth wrote at 2011-11-03 08:12:
I need some text annotations for my curves, so I implemented a simple TextAnnotation.
public partial class Form1 : Form { public Form1() { InitializeComponent(); var pm = new PlotModel("Trigonometric functions", "Example using the FunctionSeries") { PlotType = PlotType.Cartesian, Background = OxyColors.White }; pm.Series.Add(new FunctionSeries(Math.Sin, -10, 10, 0.1, "sin(x)")); pm.Series.Add(new FunctionSeries(Math.Cos, -10, 10, 0.1, "cos(x)")); pm.Series.Add(new FunctionSeries(t => 5 * Math.Cos(t), t => 5 * Math.Sin(t), 0, 2 * Math.PI, 0.1, "cos(t),sin(t)")); TextAnnotation ta = new TextAnnotation(); DataPoint dp = new DataPoint(); dp.X = 1; dp.Y = 3.5; ta.addPoint(dp); dp = new DataPoint(); dp.X = 21; dp.Y = 4.5; ta.addPoint(dp); pm.Annotations.Add(ta); plot1.Model = pm; } }public class TextAnnotation : Annotation { private IList<IDataPoint> dataPoints; public void addPoint(IDataPoint dp) { dataPoints.Add(dp); } /// <summary> /// Vertical alignment of text (above or below the line). /// </summary> public VerticalTextAlign TextVerticalAlignment { get; set; } /// <summary> /// Horizontal alignment of text. /// </summary> public HorizontalTextAlign TextHorizontalAlignment { get; set; } public override void Render(IRenderContext rc, PlotModel model) { double angle = 0; ScreenPoint position = new ScreenPoint(); foreach (IDataPoint dp in dataPoints) { if (dp.X > this.XAxis.ActualMaximum || dp.X < this.XAxis.ActualMinimum) continue; if (dp.Y > this.YAxis.ActualMaximum || dp.Y < this.YAxis.ActualMinimum) continue; position.X = this.XAxis.Transform(dp.X); position.Y = this.YAxis.Transform(dp.Y); string text = dp.Y.ToString("F1"); rc.DrawText( position, text, model.TextColor, model.ActualAnnotationFont, model.AnnotationFontSize, FontWeights.Normal, angle, this.TextHorizontalAlignment, this.TextVerticalAlignment); } } public TextAnnotation() { this.TextHorizontalAlignment = HorizontalTextAlign.Center; this.TextVerticalAlignment = VerticalTextAlign.Top; dataPoints = new List<IDataPoint>(50); } }
objo wrote at 2011-11-03 22:53:
cool, I will add a TextAnnotation class, but I think we should make it a bit more general (not only showing Y value).
I think the input properties should be a single point, horizontal/vertical alignment and a text string.
Where is YAxisKey used and how
Ambron wrote at 2014-03-06 06:12:
maddog56 wrote at 2014-03-11 01:54:
The key is used to link (or key) an axis to a series. This will insure that the series all appear in the plot area. In this example I have 3 x-axes and 1 y-axis in a single plot, with the x-axes at the bottom of the chart laid in "tiers". You can see how I used the key property.
For i = 1 To 3
Dim ax As LinearAxis
ax = New LinearAxis(AxisPosition.Bottom, 0, 50*i, "Title")
ax.Key = "key" & i.ToString
ax.PositionTier = i - 1
ax.IsZoomEnabled = False
ax.Font = "Trebuchet MS"
ax.FontSize = 12.0
ax.FontWeight = OxyPlot.FontWeights.Bold
ax.TitleFont = "Trebuchet MS"
ax.TitleFontSize = 12.0
ax.TitleFontWeight = OxyPlot.FontWeights.Bold
myModel.Axes.Add(ax)
Next For i = 1 To 3
Dim lineSeries0 As New LineSeries()
lineSeries0.Title = "Title"
lineSeries0.Color = OxyColors.Black
lineSeries0.StrokeThickness = 1.25
lineSeries0.MarkerFill = OxyColors.Red
lineSeries0.MarkerSize = 5.0
lineSeries0.MarkerStroke = OxyColors.DarkGray
lineSeries0.MarkerStrokeThickness = 1.0
lineSeries0.MarkerType = MarkerType.Circle
For j = 0 To dataseriesC.Points.Count - 1
dp = dataseriesC.Points(j)
lineSeries0.Points.Add(dp)
Next
lineSeries0.CanTrackerInterpolatePoints = False
lineSeries0.XAxisKey = "key" & i.ToString
myModel.Series.Add(lineSeries0)
NextAmbron wrote at 2014-03-11 03:55:
I probably should have added some more detail; in the .Net OxyPlot assemblies (notably OxyPlot.Wpf ) there is no XAxisKey property for a lineSeries
Hence the question, what am I missing?
Ambron wrote at 2014-03-11 04:01:
I have a ViewModel that creates an
var dateAxis = new OxyPlot.Axes.DateTimeAxis(AxisPosition.Bottom, "Time", "HH:mm")
{
MajorGridlineStyle = LineStyle.Solid,
MinorGridlineStyle = LineStyle.Dot,
IntervalLength = 80
};
var tempAxis = new OxyPlot.Axes.LinearAxis(AxisPosition.Left, "Temperature") {Key = "Temp"};
var humAxis = new OxyPlot.Axes.LinearAxis(AxisPosition.Right, "Humidity") {Key = "Hum"};
model.Axes.Add(dateAxis);
model.Axes.Add(tempAxis);
model.Axes.Add(humAxis);
Ambron wrote at 2014-03-11 04:10:
so when the data comes in I add the points with something like this, where I would want to use YAxisKey
private static void AddNamedValue(PlotModel plotModel, string name, DateTime time, decimal value)
{
var s = plotModel.Series.FirstOrDefault(ms => ms.Title == name);
if (s == null)
{
s = new OxyPlot.Series.LineSeries { Title = name };
//if (name.StartsWith("Hum"))
// s.YAxisKey = "Hum";
plotModel.Series.Add(s);
}
var ls = s as OxyPlot.Series.LineSeries;
ls.Points.Add(new DataPoint(OxyPlot.Axes.DateTimeAxis.ToDouble(time), (Double)value));
}
Tracker Position in Winforms
Tockz wrote at 2014-04-03 06:20:
Just started using oxyplot for winforms and so far so good.
The one issue I'm having is that on a column graph it seems the tracker position is not where I click. (see image below)
Image
I clicked on the middle column, and as you can see the tracker displays left and up of where I clicked
Am I doing something wrong?
Thanks
objo wrote at 2014-04-03 08:51:
Tockz wrote at 2014-04-04 00:50:
Tracker Winforms Example
On further testing, it seems to be in relation to where you place the plot control relative to other controls. If other controls are placed to the left of the plot, the tracker seems to be still working of the form borders, not where the plot is.
However if you place the plot inside a container, like a group box, it seems to work again.
Regards
Servicio de atención al cliente por UserEcho