|
Proper/Best way for XYChart with Multiple lines, each with own X values (non-date/time) |
Posted by Brad Kimble on Feb-01-2025 09:39 |
|
1. This is Windows MFC C++ VS2022.
2. I will refer to each of our displayed Charts as a Graph so I can separate my class names from ChartDirector's.
3. Detailed description of what I need and am trying to do with each graph:
I have several real time graphs that have multiple lines, all based on the same X type of values (non-date/time though). However, each line can have different X values and different number of points. I am attaching a screenshot of one graph with 4 channels of data each with a possible 2 versions of each individual data point, total max 8 lines (plus 2 vertical lines for a defined range, but I think they are irrelevant to this question).
Since this data could be coming in for many hours we have set a limit of how many values to keep for each line. The number of points displayed will remain fixed when not zoomed, but to support scrolling and zooming all lines will have arrays larger that the max displayed number of points. I am currently creating 2 arrays, X & Y (may change to vectors, but again, I don't think this matters) for each line. Data comes in (displayed) from right to left. I initialize each value in these arrays (lines) with Chart::NoValue for each X/Y. As each new point comes in for a given line, I put it at the end of the array, moving all current values to the left by 1.
As you can see in the attached .png I can display the original data. Each of my graphs contains a ChartDirector XYChart and a CChartViewer.
When I assign the X values to the viewer I use the ones from the line with the most values.
I am wondering if this is the best way. I was thinking of changing it so all lines in my graph share an X array, but for each point that comes in, if it does not apply to a specific line, put a NoValue in that slot.
I have also not gotten scrolling to work properly on these charts.
Sometimes it will scroll the first time, but display the data scrunched up, then after the first scroll, it never scrolls back. The mouse event comes in, but the values coming back from getViewPortLeft() and getViewPortWith() never change. Also after the first move, my
index values from calling
DoubleArray XAxisValues(pFirstLine->m_pXValues, pFirstLine->GetMaxNumValues());
int startIndex = (int)floor(Chart::bSearch(XAxisValues, viewPortLeftValue));
int endIndex = (int)ceil(Chart::bSearch(XAxisValues, viewPortRightValue));
are almost always 0.
I feel like I'm doing something pretty basic wrong.
Brad
|
Re: Proper/Best way for XYChart with Multiple lines, each with own X values (non-date/time) |
Posted by Peter Kwan on Feb-01-2025 22:56 |
|
Hi Brad,
For your case, it is OK to use multiple x data series and multiple y data series. It is also OK to use one x data series shared by all lines, and multiple y data series with unused y data points filled with Chart::NoValue.
For the code:
DoubleArray XAxisValues(pFirstLine->m_pXValues, pFirstLine->GetMaxNumValues());
I assume xAxisValues is the entire array, including the Chart::NoValue elements. Unluckily, the binary search (Chart::bSearch) does not support Chart::NoValue. You would need to use only the portion of the array that contains valid values.
Instead, I suggest to fill the array from the left instead of from the right.
In our sample code, we keep track of the current index which starts at 0. When a new value comes in, we put it at the current index, and increment the current index by 1. If we reach the end of the array, we shifted the array to the left by 5% and update the current index accordingly. The XAxisValues is then:
DoubleArray XAxisValues(pFirstLine->m_pXValues, pFirstLine->currentIndex).
There is no need to initialize the arrays with Chart::NoValue or any other value, as XAxisValues will only contain valid values and Chart::bSearch can be used.
The code to do the above is in the OnDataRateTimer method in the "Real Time Chart with Zooming and Scrolling sample code".
https://www.advsofteng.com/doc/cdcpp.htm#realtimezoomscroll.htm
To get started, you can begin with the sample code with 1 line only. When it works, you can add more lines.
For testing, I have also modified the sample code to use a single non-date-time x data series with y-series fill with Chart::NoValue randomly (to emulate y-series that may have Chart::NoValue in some x positions). I choose this method because it is easy to modify from the sample code. To try it, you can use the attached RealTimeZoomScrollDlg.cpp to replace the existing file in the mfcdemo sample code.
Best Regards
Peter Kwan
|
|