Heatmap with x/y/temperature
michaeldjackson wrote at 2013-07-22 19:17:
mdj
michaeldjackson wrote at 2013-07-25 15:49:
I have a set of vertexes (elements) as such: example: first row is a triangle, so I have to connect from point 1 to point 2, to point 29, by looking up the X/Y in the points points table below this one.
1 2 29 29
2 3 30 30
2 30 29 29
3 4 30 30
4 5 31 31
4 31 30 30
5 6 32 32
5 32 31 31
6 7 33 33
6 33 32 32
7 8 33 33
8 9 34 34
8 34 33 33
9 10 53 53
9 53 34 34
etc...
and a related set of points, x/y/temperature values as such: col 1 = X, col 2 = Y, col 3 = temperature value
0.00000 10104.30469 85.42578
23.81701 10099.78027 85.39697
52.66248 10100.03027 85.21484
91.39400 10100.03027 84.43164
138.70711 10100.03027 82.15918
176.91968 10100.03027 79.03809
220.44461 10100.03027 74.18945
267.32025 10099.66699 69.26123
314.75699 10087.49316 65.67090
373.00156 10064.55566 62.69043
420.31058 10042.03711 60.59082
481.73688 10006.85254 203.34668
477.66980 9935.93457 202.28516
413.56137 9882.99414 95.26904
354.52710 9845.10938 101.92480
289.58786 9833.21191 -63.29688
223.60796 9822.66699 -60.64404
157.68076 9815.36816 -59.27246
96.99345 9811.48535 -58.68701
46.78601 9809.75977 -58.65527
0.00000 9808.47070 -60.16504
0.00000 9841.34082 115.28174
0.00000 9874.21191 112.79932
0.00000 9907.08203 225.96680
0.00000 9939.95215 227.61377
0.00000 9972.82324 230.82422
0.00000 10005.69336 233.89453
0.00000 10038.56348 85.20508
0.00000 10071.43457 84.78027
58.55649 10055.58594 84.53174
110.75381 10060.53125 83.12988
159.16745 10048.73047 80.73828
220.05704 10048.87402 76.52832
282.87769 10028.51855 221.96436
In my app, I draw a mesh by iterating through the elements, and for each I find the associated line in the points table. Example. 1, 2, 29, 29 in the elements table means to get the X/Y coordinates from line 1, line 2, line 29. I'm supplyng these points to the OxyPlot series.
I've done the meshing successfully, but now I need to create a heatmap of the temperatrues at the given points. As mentioned above, I don't know what to supply the the "data" for the HeatMapSeries.
Can anyone help?
Note: the tables above are a very small subset of the full table.
Thanks
Oxyplot XamarinAndroid "Zoom"-Question
Death69 wrote at 2014-07-15 08:29:
I wanted to know if it is possible to make a "Center-Button" for a PlotView with your library. I created an plotview in my application that is zoomable with touch gesture. And I need a method to reset the Zoom. But I couldn't find a property or method for this. Is this implemented or do i need to figure out a way to do is?
Btw: Thanks for this great library :D
Greetings
(If anything is unclear, just ask.)
Slxe wrote at 2014-07-15 15:31:
Death69 wrote at 2014-07-16 08:07:
centerButton.Click += (object sender, EventArgs e) =>
{
centerButton_Click(sender, e, view, plotView);
};
and handle it with this:private void centerButton_Click(object sender, EventArgs e, View view, PlotView plotView)
{
plotView.Model.ResetAllAxes();
plotView.Model.InvalidatePlot(true);
}
then nothing happens. Is that what you suggested?Slxe wrote at 2014-07-16 16:57:
centerButton.Click += (s, args) =>
{
plotView.Model.ResetAllAxes();
plotView.InvalidatePlot(false);
}
Other than that I'm not really sure. I haven't had a chance to play with Xamarin or Mono at all (and the only android dev I've done was in Java), so not sure if it might be an issue with that =. I'm sure Objo will be around at some point and will have some better input on it.
Death69 wrote at 2014-07-16 17:02:
plotView.Model.InvalidatePlot(true);
Thank you for your help.Monodroid and MouseEvents
Tamlocar wrote at 2013-01-01 12:45:
Hi,
if I see it right, there is no Support for MouseEvents right now. Is it planned to get them implemented?
How would you suggest to get s Zoom/Pan working right now?
objo wrote at 2013-01-12 18:30:
I am currently thinking about how to solve http://oxyplot.codeplex.com/workitem/9625, and I would like to use some cross-platform code to solve this..
I think it should be possible to implement the mouse events on Mono for Android in the same way as for the other platforms, have a look at the code for the WPF control! (Source\OxyPlot.Wpf\Plot.cs)
codenutter wrote at 2013-01-13 05:16:
In my Monodroid project, I made a custom PlotView implements IPlotControl, and use ScaleGestureDetector for zoom gesture, GestureDector for pan gesture.
A cross platform solution would be great. Emulate mouse events might be better than reply on platform specific code eg. GestureDector of android api.
Btw, just found out Oxyplot recently, it's such a great plot solution, thanks objo! (and other contributors)
objo wrote at 2013-01-15 07:26:
codenutter: it would be interesting to see your implementation of ScaleGestureDetector, can you create a fork or post the code here?
I am new to the touch events, and need to find an abstraction that can be implemented on both the Windows (Winforms, WPF, SL), iOS and Android platforms.
Tamlocar wrote at 2013-01-15 07:58:
I Implemented it in the AndroidView class. The only issue is the scaling according to the real size of the axis (in Screen space) Also I did not implement the Translation in x- and y- direction with this code...
I have no knowledge about how the scaling and Transformation issues are woring inside the lib but maybe you could start with my code here :)
Some snippets from my implementation:
private void Initialize() { mScaleDetector = new ScaleGestureDetector(Context, this); } private readonly object renderingLock = new object(); private readonly object modelLock = new object(); private ScaleGestureDetector mScaleDetector; public override bool OnTouchEvent(MotionEvent e) { return mScaleDetector.OnTouchEvent(e); return base.OnTouchEvent(e); }
public bool OnScale(ScaleGestureDetector detector) { Debug.WriteLine("Scale" + (1-detector.ScaleFactor)); var y=Model.Axes[1]; y.Minimum -= (1-detector.ScaleFactor)*20; y.Maximum += (1-detector.ScaleFactor)*20; Model.Update(true); Invalidate(); return true; } public bool OnScaleBegin(ScaleGestureDetector detector) { return true; } public void OnScaleEnd(ScaleGestureDetector detector) { }
objo wrote at 2013-01-22 09:35:
Thank you! I will look at this soon. I also noticed there were some build errors with the latest Mono for Android version.
I am also trying to get a Mono for Android build running on the build machine.
codenutter wrote at 2013-01-23 12:51:
Hi objo,
Here're the TouchablePlotView for supporting scale and pan gesture. actually it's much simpler than I thought thanks to the IPlotControl.
I'm quite new to Andorid (only starting weeks ago), so I just use the built-in ScaleGestureDetector and GestureDetector. It might be better to implement my own gesture support by using OnTouchEvent. But for my current project, built-in gesture class seems sufficient.
public class TouchablePlotView : View , IPlotControl, ScaleGestureDetector.IOnScaleGestureListener, GestureDetector.IOnGestureListener { private ScaleGestureDetector _scaleDetector; private GestureDetector _gestureDetector; public override bool OnTouchEvent(MotionEvent e) { bool isConsumed = _gestureDetector.OnTouchEvent(e); if (!isConsumed) isConsumed = _scaleDetector.OnTouchEvent(e); return isConsumed; } private PlotModel model; public PlotModel Model { get { return this.model; } set { if (this.model == value) { return; } this.model = value; this.OnModelChanged(); } } private void OnModelChanged() { this.InvalidatePlot(true); } private readonly object invalidateLock = new object(); private bool isModelInvalidated; private bool updateDataFlag = true; protected override void OnAttachedToWindow() { base.OnAttachedToWindow(); _scaleDetector = new ScaleGestureDetector(this.Context, this); _gestureDetector = new GestureDetector(this.Context, this); } public PlotModel ActualModel { get { return Model; } } public void GetAxesFromPoint(ScreenPoint pt, out Axis xaxis, out Axis yaxis) { if (this.ActualModel != null) { this.ActualModel.GetAxesFromPoint(pt, out xaxis, out yaxis); } else { xaxis = null; yaxis = null; } } public Series GetSeriesFromPoint(ScreenPoint pt, double limit = 100) { return this.ActualModel != null ? this.ActualModel.GetSeriesFromPoint(pt, limit) : null; } public void HideTracker() { // } public void HideZoomRectangle() { // } public void InvalidatePlot(bool updateData) { lock (this.invalidateLock) { this.isModelInvalidated = true; this.updateDataFlag = this.updateDataFlag || updateData; } this.Invalidate(); } public void Pan(Axis axis, ScreenPoint ppt, ScreenPoint cpt) { axis.Pan(ppt, cpt); this.InvalidatePlot(false); } public void RefreshPlot(bool updateData = true) { UpdateModelAndVisuals(updateData); } public void Reset(Axis axis) { axis.Reset(); } public void SetCursorType(CursorType cursorType) { /* switch (cursorType) { case CursorType.Pan: this.Cursor = this.PanCursor; break; case CursorType.ZoomRectangle: this.Cursor = this.ZoomRectangleCursor; break; case CursorType.ZoomHorizontal: this.Cursor = this.ZoomHorizontalCursor; break; case CursorType.ZoomVertical: this.Cursor = this.ZoomVerticalCursor; break; default: this.Cursor = Cursors.Arrow; break; } */ } public void ShowTracker(TrackerHitResult trackerHitResult) { //throw new System.NotImplementedException(); } public void ShowZoomRectangle(OxyRect r) { //throw new System.NotImplementedException(); } public void Zoom(Axis axis, double p1, double p2) { axis.Zoom(p1, p2); this.RefreshPlot(false); } public void ZoomAt(Axis axis, double factor, double x) { if (double.IsNaN(x)) { double sx = (axis.Transform(axis.ActualMaximum) + axis.Transform(axis.ActualMinimum)) * 0.5; x = axis.InverseTransform(sx); } axis.ZoomAt(factor, x); } private void UpdateModelAndVisuals(bool updateData = true) { this.UpdateModel(updateData); this.UpdateVisuals(); } private void UpdateModel(bool updateData) { this.ActualModel.Update(updateData); } private void UpdateVisuals() { this.Invalidate(); } public TouchablePlotView(Context context, IAttributeSet attrs) : base(context, attrs) { Initialize(); } public TouchablePlotView(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle) { Initialize(); } private void Initialize() { } private readonly object renderingLock = new object(); private readonly object modelLock = new object(); protected override void OnDraw(Canvas canvas) { base.OnDraw(canvas); canvas.DrawColor(Color.White); lock (this.invalidateLock) { if (this.isModelInvalidated) { if (this.model != null) { this.model.Update(this.updateDataFlag); this.updateDataFlag = false; } this.isModelInvalidated = false; } } lock (this.renderingLock) { if (this.model != null) { var rc = new CanvasRenderContext(canvas); this.model.Render(rc); } } /* canvas.DrawColor(Color.White); using (var paint = new Paint()) { paint.AntiAlias = true; paint.Color = new Color(0, 0, 0, 220); paint.StrokeWidth = 2; canvas.DrawLine(10f, 10f, canvas.Width - 10, h - 10, paint); canvas.DrawLine(canvas.Width - 10, 10f, 10, h - 10, paint); paint.TextSize = 24; paint.TextAlign = Paint.Align.Left; var textbounds = new Rect(); paint.GetTextBounds("ABC", 0, 1, textbounds); var tw = paint.MeasureText("ABC"); // canvas.DrawText(this.Text, 40, 200, paint); canvas.Translate(40, 40); canvas.DrawText("ABC=" + tw + "/" + textbounds, 0, 0, paint); canvas.Rotate(20); canvas.DrawText("ABC=" + tw, 0, 0, paint); }*/ } #region Implementation of IOnScaleGestureListener public bool OnScale(ScaleGestureDetector detector) { float scale = detector.ScaleFactor; if (OnPlotZoomed != null) OnPlotZoomed(this, new PlotScaleEventArgs(scale)); return false; } public class PlotScaleEventArgs : System.EventArgs { public float Scale { get; set; } public PlotScaleEventArgs(float scale) { Scale = scale; } } public event EventHandler<PlotScaleEventArgs> OnPlotZoomed; public bool OnScaleBegin(ScaleGestureDetector detector) { return true; } public void OnScaleEnd(ScaleGestureDetector detector) {} #endregion #region Implementation of IOnGestureListener public bool OnDown(MotionEvent e) { return false; } public bool OnFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return false; } public void OnLongPress(MotionEvent e) { //return false; } public class PlotScrollEventArgs : EventArgs { public float DistanceX { get; set; } public float DistanceY { get; set; } public PlotScrollEventArgs(float distanceX, float distanceY) { DistanceX = distanceX; DistanceY = distanceY; } } public event EventHandler<PlotScrollEventArgs> OnPlotScroll; public bool OnScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { if (OnPlotScroll!=null) OnPlotScroll(this, new PlotScrollEventArgs(distanceX, distanceY)); return false; } public void OnShowPress(MotionEvent e) { // } public bool OnSingleTapUp(MotionEvent e) { return false; } #endregion }
Tamlocar wrote at 2013-01-24 09:21:
That Looks damn good.
But how do I use that?
How can I enable the paning and Zooming? I see that the corresponding OnScale etc. are correctly called but they just Forward it to an Event handler which I now have to implement right?
codenutter wrote at 2013-01-24 11:49:
HI Tamlocar,
For Zooming, you add event handler for TouchablePlotView.OnPlotZoomed; For Panning, you add event handler for TouchablePlotView.OnPlotScroll
eg, for panning:
protected override void OnCreate(Bundle bundle) { _plotView = FindViewById(Resource.Id.plotview); _plotView.OnPlotScroll += (sender, args) => { var deltaX = -1*args.DistanceX; PanPlot(deltaX); }; } private void PanPlot(float deltaX) { var axe = _plotView.Model.Axes[0]; axe.Pan(deltaX); _plotView.Model.RefreshPlot(false); }
Tamlocar wrote at 2013-01-24 12:12:
Yep, thx. I got the panning working.
But sooming is not working as expected. If I release the pinc-to-zoom gesture and zoom again the scale will be reset every time. Somehow the zoom function does not Keep the latest value.
private void ZoomPlot(float delta) { var axeX = plotView.Model.Axes[0]; axeX.Zoom(delta); var axeY = plotView.Model.Axes[1]; axeY.Zoom(delta); //plotView.Model.PlotControl = plotView; plotView.RefreshPlot(false); }
codenutter wrote at 2013-01-24 12:20:
Sorry, missed something in my last code snippet when formatting. It should be
protected override void OnCreate(Bundle bundle) { _plotView = FindViewById<TouchablePlotView>(Resource.Id.plotview); _plotView.Model = ... // Setup your model here _plotView.Model.AttachPlotControl(_plotView); _plotView.OnPlotScroll += (sender, args) => { var deltaX = -1*args.DistanceX; PanPlot(deltaX); }; }
Tamlocar wrote at 2013-01-24 12:49:
Yes, otherwiese it is crashing. I just called the RefreshPlot function directly on the view instead of the model.
Still could not get the zooming stuff to work. Adding or multiplying with the Axis.Scale does not work as it seems.
codenutter wrote at 2013-01-24 14:17:
I only use DateTimeAxis, and the zooming works for me. But I suppose the LinearAxis should works too.
May I suggest you try Zoom(double x0, double x1) instead of Zoom(double newScale). My guess is there're some problem with Zoom(double newScale) method, but have not look deep inside.
Tamlocar wrote at 2013-01-25 11:38:
Hm, that does not seem to work eighter. As I have only the scaling factor available. If I put that one in into x0 and x1 it is acting very strange :)
codenutter wrote at 2013-01-29 02:17:
On vacation, dont have the code around. As I can recall, for using the Zoom(double x0, double x1), you should fetch the actualMinimum and actualMaximum from existing axis first, then use the zoom factor to calculate out your new minimum and maximum, then you use Zoom(newMimum, newMaxium) to get your desiring zooming. ( And you might want to clamp the zoom factor to prevent out of scale error )
Tamlocar wrote at 2013-02-24 07:29:
FrankiAA wrote at 2013-04-10 13:15:
Have your a solution for that?
Thanks.
WPF series visibility updates
GeertvanHorrik wrote at 2014-03-26 16:18:
I am trying to manipulate the PlotModel via MVVM. I have created a list of SeriesVisibility models that represent a Series (model, not WPF) with a Color and IsVisible properties. As soon as the property has changed, I pass on the property to the series model:
private void OnIsVisibleChanged()
{
Series.IsVisible = IsVisible;
}
This does not update because the models do not implement INotifyPropertyChanged. I wanted to work around this problem with this method in a service:public void UpdateSeriesVisibility()
{
var plotModel = PlotModel;
if (plotModel == null)
{
return;
}
var plotControl = plotModel.PlotControl as Plot;
if (plotControl != null)
{
foreach (var viewSeries in plotControl.Series)
{
viewSeries.Visibility = viewSeries.InternalSeries.IsVisible ? Visibility.Visible : Visibility.Hidden;
}
}
}
Unfortunately the plotControl.Series is empty while PlotModel.Series
and plotControl.ActualModel.Series are not empty. Next thing I was trying is to UpdateData or InvalidatePlot, but this does not cause a re-render of the plot:
- UpdateData(false and true)
- InvalidatePlot(false and true)
- InvalidArrange
Can you give some hints on how I can re-render the plot?
GeertvanHorrik wrote at 2014-03-26 16:34:
public void RenderPlot()
{
var plotModel = PlotModel;
if (plotModel == null)
{
return;
}
var plotControl = plotModel.PlotControl as Plot;
if (plotControl != null)
{
plotControl.Dispatcher.BeginInvoke(() =>
{
plotControl.InvalidateFlag++;
});
}
}
I think there should be an easier way though.tibel wrote at 2014-03-26 19:24:
GeertvanHorrik wrote at 2014-03-26 19:43:
objo wrote at 2014-03-26 20:52:
It should not be necessary to call
Plot.UpdateModel
(private!) and
PlotModel.Update
(I think the last one should also be protected in some way).GeertvanHorrik wrote at 2014-03-26 20:53:
objo wrote at 2014-03-26 21:17:
GeertvanHorrik wrote at 2014-03-26 21:18:
Remember that I found a workaround so you don't need to feel rushed in any way.
Rendered smooth line is different with tracker data
ryoujr wrote at 2013-06-10 20:44:
I tried to draw some smooth line (with log scale axies) in the example code as below, and found that the actual rendered line is slightly different from the tracker data line. so, if I tried to add hit test on the line and add a point on the clicked point, it is not possible to add on the actual line but only on the tracker line. I would really appreciate it if someone can explain the reason for this difference and could share any idea to make this perfectly aligned.
[Example("LineSeries and PlotModel MouseDown event")]
public static PlotModel MouseDownEvent()
{
var model = new PlotModel("MouseDown", "Left click to edit or add points.") { LegendSymbolLength = 40 };
var logarithmicAxis1 = new LogarithmicAxis();
logarithmicAxis1.Title = "X";
logarithmicAxis1.Position = AxisPosition.Bottom;
model.Axes.Add(logarithmicAxis1);
// Add a line series
var s1 = new LineSeries("LineSeries1")
{
Color = OxyColors.SkyBlue,
MarkerType = MarkerType.Circle,
MarkerSize = 6,
MarkerStroke = OxyColors.White,
MarkerFill = OxyColors.SkyBlue,
MarkerStrokeThickness = 1.5,
Smooth = true
};
s1.Points.Add(new DataPoint(100, 100));
s1.Points.Add(new DataPoint(400, 200));
s1.Points.Add(new DataPoint(600, -300));
s1.Points.Add(new DataPoint(1000, 400));
s1.Points.Add(new DataPoint(1500, 500));
s1.Points.Add(new DataPoint(2500, 600));
s1.Points.Add(new DataPoint(3000, 700));
model.Series.Add(s1);
//model.RefreshPlot(false);
model.Update(true);
int indexOfPointToMove = -1;
int indexOfPointToInsert = -1;
ryoujr wrote at 2013-06-10 22:31:
objo wrote at 2013-06-12 13:46:
Tracker that scrolls the X-Axis
OxyPlot - awesome tool by the way.
Legend options
bball0246 wrote at 2013-04-04 23:30:
I want the legend to be outside the plot area. I've seen the following in some example code but it doesn't seem to do anything.
LegendPlacement="Outside" LegendPosition="RightTop" LegendOrientation="Vertical"
VS2013 Designer will not load with OxyPlot control
"Could Not Find Windows Runtime type "Windows.UI.Xaml.Control.RelativeSource".
See Below
Customer support service by UserEcho