A 2D Lite Graph Control with Multiple Plot Support


Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame

This is a simple, lightweight 2D graph control that supports multiple plots as well as printing. Why make another graph control? This one gives the user basic functionality which would make a great oscilloscope without a lot of extra features getting in the way. Because it is so small, it's also a great base from which to develop a more fully featured specialized graph–the very essence of OOP!

Note: It makes use of the MemDC class written by Keith Rule, and downloaded from Codeguru.com.


Once the control has been created and displayed, the user may run the mouse over it, and the current position and value at that position will be displayed in the upper left-hand corner. The values that are displayed are for the currently selected plot.

In the example above, the selected plot is the "Green Data" plot, which is a sine wave. To select another plot, click its key value on the left-hand side of the graph. This will change the statistics, position, and value accordingly.

The statistics are reported for all the data in the currently selected plot, and will not change unless the underlying data changes.

To "zoom in" on a piece of the plot, draw a rectangle with the mouse by starting in the upper left-hand corner of the desired area, holding down the left mouse button, and moving it to the lower-left hand corner of the area and letting go.

Once the rectangle has been drawn, the axes' min and max limits will be recalculated and the graph will be redrawn such that the selected area fills the entire graph area.

The user can zoom as many levels down as is realistic for the particular graph in question. The graph stores an "undo" list of zooms, so by drawing a rectangle in reverse (start at bottom right, move to top left), the most recent previous zoom will be restored.

The graph also supports the "locking" of the axes. This is useful if the user would like to update the data, but keep the limits the same as a frame of reference. This also can be used to limit the zoom in one axis only. For example, locking the y axis would effectively zoom in on a narrower and narrower section of the graph. Locking both x and y would disable the zooming feature altogether. To lock an axis, click one of the two icons in the lower left-hand corner. In this example, both are unlocked.

The user also can zoom by manually changing the limits. Clicking on the min or max (in this example, min x = -5.0, max x = 100.0, min y = -10.0, max y = 10.0) will allow the user to type in a number and update the graph.

What else is there? At this point, the plots support two different styles: "line" and "bar." Above, the "blue data" is of the "bar" style, and the "red data" and "green data" are of the "line" style.

Most parameters are configurable. Take a look at the example below to see.


There are two classes that make up this control: CPlotData and CLinePlot. CLinePlot is the main class of the control; it contains a vector of the CPlotData class. You never need to actually manipulate the CPlotData class directly, so you will focus on the CLinePlot class.

BOOL Create(const RECT& rect, UINT uiFlags, CWnd *pwndParent,
            UINT uiID);

This is pretty much the standard constructor for a CWnd derived class.

int Add(CString szName, COLORREF crColor, enumPlotStyle nStyle,
        FLOATPOINT *pptData, UINT uiPointCount);

This adds a new plot to the control. Note the FLOATPOINT structure; it is basically the same as a POINT structure, except x and y are both floats. It returns the index of the added plot.

int Add(CString szName, COLORREF crColor, enumPlotStyle nStyle,
        std::vector<FLOATPOINT> *pvecData);

Same as above, only the data is in a vector instead of an array. It returns the index of the added plot.

void Clear();

Remove all the plots.

int Count();

Returns the number of plots in the graph.

void Print();

Sends a WYSIWYG rendering of the graph to the printer.

bool Remove(int nIndex);

Removes a plot at a specific index. Returns whether or not the operation succeeded.

void Refresh();

Forces the control to be repainted.

int Selected();

Returns the index of the selected plot.

CPlotData &operator[](UINTunIndex);

Gets a reference to the plot at a specific index. This can be used to modify a plot directly.


In the "OnCreate" or "OnInitDialog":

m_LinePlot.Create(CRect(0, 0, rcBounds.Width(), rcBounds.Height()),
                  CHILD | WS_VISIBLE, this, ID_CTRL_LINE_PLOT);

Add a plot to the control:

FLOATPOINT pData3[400];
for (ii=0; ii<400; ii++)
   pData3[ii].x = (float)(ii);
   pData3[ii].y = (float)(cos((float)(ii)/4.0f)*8);
COLORREF crColor3 = RGB ( 0, 128, 0);
m_LinePlot.Add("Green Data", crColor3, CLinePlot::LpLine, pData3,

See the included example for more details.

About the Author

Paul Grenz

Paul Grenz is a software engineer with the University of Arizona, located in beautiful, sunny Tucson. His primary focus is writing software to run the LBTO (Large Binocular Telescope Observatory). When he is not writing hardware control/image processing software, he can be found writing about himself in the third person or playing with his wonderful daughter Elizabeth.



  • Command line errors on compile with VS2015

    Posted by Bob Gibson on 01/06/2017 04:17pm

    Awesome graph! When I compile with VS2015, I get error D8016.... '/ZI' and '/Gy-' command line options are incompatible. I can't seem to resolve this issue. Any help would be very welcome. Thanks again. Bob

  • Compile/Build Error

    Posted by Alan on 06/04/2015 03:05am

    Hi, Sir: I download source code to build by using VS2013 But it shows error error LNK2005: "public: virtual __thiscall CMemDC::~CMemDC(void)" (??1CMemDC@@UAE@XZ) at LinePlot.obj is already defined D:\Src\Reference\LiteGraphPlot\LinePlotTest\nafxcwd.lib(afxglobals.obj) LinePlotTest How to fix this issue? By the way, do I use this class to plot realtime data? Thanks for your help BR, Alan

    • Compile/Build Error fix

      Posted by Giorgio Mugnaini on 03/17/2016 09:46am

      Using VS2010, I obtained the same error. I solved this moving CMemDc in memdc.h to a suitable namespace in order to fix the collision with MFC CMemDc.

  • Good job

    Posted by SChepurin on 05/28/2011 04:14pm

    Very good job indeed. Thank you. S.Chepurin

  • little question

    Posted by uni_apollo on 07/17/2006 11:15am

    fist,that's a good job.my question is if i want flag some point on current ploted line with different clore or signo

  • Blank graphic

    Posted by jongarcia on 02/23/2006 03:53pm

    First of all... Great work!!! Besides that, I had a little problem with the example. I'm running W98 1024x768 ant 32bits (true color). If I move move the mouse over it for a while, the graph goes blank (no axes, no grid, no plot; just a blank area). I tried other PCs (both with XP and W98) and it always works fine. But when I use my PC the graph goes blank. I'm trying to find the problem but I've got no clue. Any idea? Thanks in advance, Jon.

    • Blank graphic

      Posted by MycroftH on 02/24/2006 12:01am

      Hi Jon: Thanks for the kind words. I wrote and tested the graph control on windows 2000 running on a pentium 3 (if I remember correctly), but I tried to keep the drawing calls as standard as I could, and they should work the same on all versions of windows from 95 on up. It almost sounds like you are overwhelming the "onpaint" function with calls due to the high update rate. Try commenting out the refresh code which is called as you pass the mouse over the control and see if the same thing happens. If it stops, you may just need to set some kind of mutex when you are in the "onpaint" function to limit the rate at which "onpaint" is called. I'd be willing to bet that the computer you are experiencing this problem on is older (slower) than the ones which do not experience the problem. That's just my first thought on the subject. I'll mull over it some more, and if I think of something else I'll let you know.

  • Graph does not show?

    Posted by myhanguk on 01/11/2006 11:16am

    Hi Paul,
    First of all, thanks for providing us with this nice tool of yours! I tried to include it in a litte SDI program I'm trying to write (I'm just a novice in Visual C++), and didn't quite get it to work.
    Basically, I did the following:
    In the InitInstance() of my application's cpp file, I commented out all the SDI template stuff, and inserted:
    CPlotDlg dlg;
    m_pMainWnd = &dlg
    int nResponse = dlg.DoModal();
    if (nResponse == IDOK){}
    CPlotDlg is just a simple Dialog box in which I want to display your graphs, without using your the CLinePlotTestDlg class.
    Then, in the OnInitDialog() part of the CPlotDlg dlg object, I put:
    BOOL CPlotDlg::OnInitDialog() 
       // TODO: Add extra initialization here
      CRect rcClient;
      rcClient.bottom = rcClient.top + 300;
      rcClient.right = rcClient.left + 900;
      CLinePlot m_LinePlot;
      m_LinePlot.Create(CRect(0, 0, 1, 1), WS_CHILD WS_VISIBLE, this, ID_CTRL_LINE_PLOT);
      m_LinePlot.MoveWindow(200, 0, rcClient.Width(), rcClient.Height());
    return TRUE;
    The white background of the graph area does not appear on after create and resizing, as in the test program you provided. What am I doing wrong?
    Thanks for you feedback,

    • Graph does not show?

      Posted by MycroftH on 02/24/2006 12:14am

      You may want to check the coordinates that "GetWindowRect" is returning. I may be mistaken, but I think you need a call to "ScreenToClient" to translate the coordinates into the dialog's coordinate system.
      Also, you are declaring "m_LinePlot" as a local variable within the "OnInitDialog" function. If you do it this way, it goes away after the function ends! To use it in a dialog like this, declare it as a module level variable in the dialog's header file.
      Ensure that "ID_CTRL_LINE_PLOT" is defined in your resource file as well.
      Try this:
      BOOL CPlotDlg::OnInitDialog() 
         // TODO: Add extra initialization here
        CRect rcClient;
        GetWindowRect( &rcClient );
        ScreenToClient( &rcClient );
        m_LinePlot.Create( rcClient, WS_CHILD WS_VISIBLE, this, ID_CTRL_LINE_PLOT);
      return TRUE;
      Good Luck!

  • CPen causes exception in DrawFrameWork

    Posted by ahoodin on 02/11/2005 09:17pm

    In DrawFramework, the CPens will eventually cause a recurring exception. I fixed them in my own implementation.One fix is moving them out of DrawFramWork and making them members of lineplot to be initialized in the constructor.

    • Restoring pens and fonts properly avoids memory leak

      Posted by Ernst Lustig on 06/15/2009 05:42pm


    • CPen causes exception in DrawFrameWork

      Posted by MycroftH on 02/24/2006 12:15am

      Sounds good to me, as long as you destroy them in the class desructor. This is probably a better way to do it than I have implemented, since it will speed up the drawing process.

  • Great Graph Screen

    Posted by ahoodin on 01/19/2005 09:41pm

    I really like this control. How would one reroute messages to the lineplot control when it is on a child dialog?

    • thank you

      Posted by crycrane on 12/28/2007 05:56am

      your help is very useful

    • working well now

      Posted by ahoodin on 02/11/2005 09:14pm

      thanks, the messages are coming through well now. There was a transparent CWnd obstructing the graph and blocking the messages.

    • Handling messages

      Posted by MycroftH on 01/20/2005 09:24am

      I believe if you want to respond to windows messages, you just need to add a handler. Edit the source code for the graph, right click and select "Class Wizard" from the context menu that appears, and choose the message you wish to handle. You can see an example of a message handler like this if you look at the "OnMouseMove" function in the LinePlot class.

  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date