ASE Home Page Products Download Purchase Support About ASE
ChartDirector Support
Forum HomeForum Home   SearchSearch

Message ListMessage List     Post MessagePost Message

  How can I implement ROI & RANGE?
Posted by cho on May-04-2022 11:14
Attachments:
Hello Peter,

I need to collect the chamber's temperature and draw a chart, but I have to make a bit of a troublesome option.
I would like to check if the collected temperature value is in the Region of Interest (ROI) RANGE.

The way I thought is roughly like this :
The ROI RANGE is two Crosshair and specifies x1, y1, x2, y2 and confirmed as a pop-up menu to create a rectangular ROI RANGE.
Now the empty chart now has several rectangular box ROIs.
After creating the ROI, click the START button to start collecting the temperature value.
When the x-axis time reaches the ROI section, check if the y-value is in RANGE (max/min).
If the y-value is in the range, I want to mark the green mark, and if it is out, I would like to display the red X mark.
When it is not the ROI section, it does not show any signs.

I don't know which method of ChartDirector to use to implement these charts. (I use MFC.)
I know it's a big ask, but if possible, could you show me an example code for me, please?

Best Regards
Cho
Image 1.jpg

  Re: How can I implement ROI & RANGE?
Posted by Peter Kwan on May-04-2022 14:24
Hi cho,

Yes, this is possible. I can write an example for you. This should be available within a few hours.

Regards
Peter Kwan

  Re: How can I implement ROI & RANGE?
Posted by Peter Kwan on May-04-2022 16:49
Attachments:
Hi Cho,

I started with the "Multi-Symbol Line Chart" included in the ChartDirector download:

https://www.advsofteng.com/doc/cdcpp.htm#multisymbolline.htm

I modified the code so that the symbol type is computed by using the ROI rectangles. I also added code to draw the ROI rectangles on the chart. I have attached the code for your reference.

Best Regards
Peter Kwan
multisymbolchart.png
multisymbolchart.cpp
void multisymbolline(CChartViewer *viewer, int /* chartIndex */)
{
    // In this example, the data points are unevenly spaced on the x-axis
    double dataY[] = {4.7, 4.7, 6.6, 2.2, 4.7, 4.0, 4.0, 5.1, 4.5, 4.5, 6.8, 4.5, 4, 2.1, 3, 2.5,
        2.5, 3.1};
    const int dataY_size = (int)(sizeof(dataY)/sizeof(*dataY));
    double dataX[] = {Chart::chartTime(1999, 7, 1), Chart::chartTime(2000, 1, 1), Chart::chartTime(
        2000, 2, 1), Chart::chartTime(2000, 4, 1), Chart::chartTime(2000, 5, 8), Chart::chartTime(
        2000, 7, 5), Chart::chartTime(2001, 3, 5), Chart::chartTime(2001, 4, 7), Chart::chartTime(
        2001, 5, 9), Chart::chartTime(2002, 2, 4), Chart::chartTime(2002, 4, 4), Chart::chartTime(
        2002, 5, 8), Chart::chartTime(2002, 7, 7), Chart::chartTime(2002, 8, 30), Chart::chartTime(
        2003, 1, 2), Chart::chartTime(2003, 2, 16), Chart::chartTime(2003, 11, 6), Chart::chartTime(
        2004, 1, 4)};
    const int dataX_size = (int)(sizeof(dataX)/sizeof(*dataX));

    // The Rectangles
    struct ROI
    {
        double x1;
        double y1;
        double x2;
        double y2;
        ROI(double x1, double y1, double x2, double y2)
        {
            // Assume x1 <= x2, y1 < = y2
            this->x1 = x1;
            this->y1 = y1;
            this->x2 = x2;
            this->y2 = y2;
        }
    };

    std::vector<ROI> allROI;
    allROI.push_back(ROI(Chart::chartTime(1999, 10, 1), 3, Chart::chartTime(2000, 5, 1), 7));
    allROI.push_back(ROI(Chart::chartTime(2001, 3, 20), 3, Chart::chartTime(2002, 3, 20), 5));


    // Point Type:
    // 0 = No Symbol
    // 1 = In ROI
    // 2 = Outside ROI
    std::vector<double> pointType;

    for (int i = 0; i < dataX_size; ++i)
    {
        // initially NoROI
        pointType.push_back(0);

        // Check if is in ROI
        for (int j = 0; j < allROI.size(); ++j)
        {
            ROI& r = allROI[j];
            if ((dataX[i] >= r.x1) && (dataX[i] <= r.x2))
            {
                pointType.back() = ((dataY[i] >= r.y1) && (dataY[i] <= r.y2)) ? 1 : 2;
                break;
            }
        }
    }

    // Create a XYChart object of size 480 x 320 pixels. Use a vertical gradient color from pale
    // blue (e8f0f8) to sky blue (aaccff) spanning half the chart height as background. Set border
    // to blue (88aaee). Use rounded corners. Enable soft drop shadow.
    XYChart* c = new XYChart(480, 320);
    c->setBackground(c->linearGradientColor(0, 0, 0, c->getHeight() / 2, 0xe8f0f8, 0xaaccff),
        0x88aaee);
    c->setRoundedFrame();
    c->setDropShadow();

    // Add a title to the chart using 15 points Arial Italic font. Set top/bottom margins to 12
    // pixels.
    TextBox* title = c->addTitle("Multi-Symbol Line Chart Demo", "Arial Italic", 15);
    title->setMargin(0, 0, 12, 12);

    // Tentatively set the plotarea to 50 pixels from the left edge to allow for the y-axis, and to
    // just under the title. Set the width to 65 pixels less than the chart width, and the height to
    // reserve 90 pixels at the bottom for the x-axis and the legend box. Use pale blue (e8f0f8)
    // background, transparent border, and grey (888888) dotted horizontal and vertical grid lines.
    c->setPlotArea(50, title->getHeight(), c->getWidth() - 65, c->getHeight() - title->getHeight() -
        90, 0xe8f0f8, -1, Chart::Transparent, c->dashLineColor(0x888888, Chart::DotLine), -1);

    // Add a legend box where the bottom-center is anchored to the 12 pixels above the bottom-center
    // of the chart. Use horizontal layout and 8 points Arial font.
    LegendBox* legendBox = c->addLegend(c->getWidth() / 2, c->getHeight() - 12, false, "Arial Bold",
        8);
    legendBox->setAlignment(Chart::BottomCenter);

    // Set the legend box background and border to pale blue (e8f0f8) and bluish grey (445566)
    legendBox->setBackground(0xe8f0f8, 0x445566);

    // Use rounded corners of 5 pixel radius for the legend box
    legendBox->setRoundedCorners(5);

    // Set the y axis label format to display a percentage sign
    c->yAxis()->setLabelFormat("{value}%");

    // Set y-axis title to use 10 points Arial Bold Italic font
    c->yAxis()->setTitle("Axis Title Placeholder", "Arial Bold Italic", 10);

    // Set axis labels to use Arial Bold font
    c->yAxis()->setLabelStyle("Arial Bold");
    c->xAxis()->setLabelStyle("Arial Bold");

    // We add the different data symbols using scatter layers. The scatter layers are added before
    // the line layer to make sure the data symbols stay on top of the line layer.

    // Similar to above, we select the points with pointType - 1 = 0 and use green (ff00) 13 pixels
    // high six-sided polygon as symbols.
    c->addScatterLayer(DoubleArray(dataX, dataX_size), ArrayMath(DoubleArray(dataY, dataY_size)
        ).selectEQZ(ArrayMath(DoubleArray(pointType.data(), pointType.size())).sub(1), Chart::NoValue),
        "In ROI", Chart::CircleShape, 13, 0x00ff00);

    // Similar to above, we select the points with pointType - 2 = 0 and use red (ff0000) 13 pixels
    // high X shape as symbols.
    c->addScatterLayer(DoubleArray(dataX, dataX_size), ArrayMath(DoubleArray(dataY, dataY_size)
        ).selectEQZ(ArrayMath(DoubleArray(pointType.data(), pointType.size())).sub(2), Chart::NoValue),
        "Out ROI", Chart::Cross2Shape(), 13, 0xff0000);

    // Finally, add a blue (0000ff) line layer with line width of 2 pixels
    LineLayer* layer = c->addLineLayer(DoubleArray(dataY, dataY_size), 0x0000ff);
    layer->setXData(DoubleArray(dataX, dataX_size));
    layer->setLineWidth(2);

    // Adjust the plot area size, such that the bounding box (inclusive of axes) is 10 pixels from
    // the left edge, just below the title, 25 pixels from the right edge, and 8 pixels above the
    // legend box.
    c->packPlotArea(10, title->getHeight(), c->getWidth() - 25, c->layoutLegend()->getTopY() - 8);

    c->layout();

    for (int i = 0; i < allROI.size(); ++i)
    {
        ROI& r = allROI[i];
        int pixelX1 = c->getXCoor(r.x1);
        int pixelX2 = c->getXCoor(r.x2);
        int pixelY1 = c->getYCoor(r.y1);
        int pixelY2 = c->getYCoor(r.y2);

        TextBox* t = c->addText((std::min)(pixelX1, pixelX2), (std::min)(pixelY1, pixelY2), "");
        t->setSize(abs(pixelX2 - pixelX1) + 1, abs(pixelY1 - pixelY2) + 1);
        t->setBackground(Chart::Transparent, 0xcc8844, Chart::flatBorder(2));
        t->setZOrder(Chart::GridLinesZ);
    }

    // Output the chart
    viewer->setChart(c);

    //include tool tip for the chart
    viewer->setImageMap(c->getHTMLImageMap("clickable", "", "title='{x|mmm dd, yyyy}: {value}%'"));
}

  Re: How can I implement ROI & RANGE?
Posted by cho on May-06-2022 09:25
Hello Peter,

Your example is perfect!

Thank you so much.

Best Regards
Cho