Scatter series on heat map

Jan 20, 2014 at 5:00 PM
Is it possible to display points on a bitmap/polarheatmap/bitmap series?
These points are dynamic so the background image remains the same, but the overlay points change.

any leads please.

thanks
Coordinator
Jan 27, 2014 at 7:21 PM
Yes, you can add both a HeatMapSeries and a ScatterSeries (based on different data) to the same plot model.
Performance for the heat map can be an issue if you need a high refresh rate for the dynamic points.
May 15, 2014 at 1:13 PM
I added both heat map series and scatter series to the same plot model. but only heat map is shown on the plot model. What is reason of the problem?
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;
May 27, 2014 at 9:23 PM
Hi, I am working on a similar project where the HeatMapSeries changes vary rarely, but a FunctionSeries on the same plot will be changing rapidly (ideally 5-10 times/second). I am currently using WinForms. To test the update rates, I'm using a simple timer that cycles through different FunctionSeries that get overlaid on top of the HeatMapSeries. As I understand it, when I call "plotView1.InvalidatePlot(true)" it will re-draw both the HeatMapSeries and the FunctionSeries. Is there any way to get it to only redraw/render only the FunctionSeries? Would this be significantly faster if I were using WPF?
May 30, 2014 at 12:54 PM
Edited May 30, 2014 at 12:55 PM
I dont think that the WPF works faster than Windows form application. Not too long a time interval of 100 ms. The standart timer control is used to the process. But a sample rate with more precise time is required, (For example 1-2 milisecond), I recommend that you can use the milisecond class library that is a class written by C# language. the sample rate of standart timer control is not stable under the 10 ms. I have been using the class in windows form application to obtain a sample rate of 2 ms. Additionaly, If you want to give priority to the work of some functions,you should use multi-threading programming. The microlibrary class is below;

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;
    }
}
}