Infinite loop/crash in WCartesianChart

Added by Ulf Johnsson 5 months ago

Hi!
It seems like putting a NaN at the begining or at the end of a dataseries causes an infinite loop.
See example below to recreate.
BR, Ulf.

class Application : public Wt::WApplication
{
public:
    Application (const Wt::WEnvironment &enviorment) : Wt::WApplication(enviorment) {}

    class GraphModel : public Wt::Chart::WAbstractChartModel
    {
    public:
        GraphModel(Wt::WObject *parent = 0)
        {
            m_data[0].v1 = std::numeric_limits<double>::quiet_NaN(); m_data[0].v2 = 1.0;
            m_data[1].v1 = 1.0; m_data[1].v2 = 1.0;
            m_data[2].v1 = 2.0; m_data[2].v2 = 2;
            m_data[3].v1 = 3.0; m_data[3].v2 = 1.0;
            m_data[4].v1 = 4.0; m_data[4].v2 = 1.0; // if m_data[4].v1 = NaN the same thing occurs!
        }

        int columnCount() const override { return 2; }
        int rowCount() const override { return sizeof(m_data)/sizeof(m_data[0]); }

        double data(int row, int column) const override
        {
            if(rowCount() == 0)
                return 0.0;

            if(row < 0 || row >= rowCount())
                return 0.0;

            if(column == 0)
                return m_data[row].v1;

            return m_data[row].v2;
        }

    private:
        struct
        {
            double v1, v2;
        } m_data[5];
    };

    /***************************************************************/
    void initialize()
    {
        WApplication::initialize();

        Wt::Chart::WCartesianChart *chart = new Wt::Chart::WCartesianChart(root());
        chart->setType(Wt::Chart::ScatterPlot);
        chart->resize(500, 500);
        chart->setOnDemandLoadingEnabled(true);
        chart->setAutoLayoutEnabled(true);
        chart->setPanEnabled(true);
        chart->setZoomEnabled(true);
        chart->axis(Wt::Chart::XAxis).setRange(0, 4);
        chart->axis(Wt::Chart::XAxis).setLabelInterval(1);
        chart->axis(Wt::Chart::Y1Axis).setRange(0, 20);
        chart->axis(Wt::Chart::Y1Axis).setMaxZoom(1.0);
        chart->setXSeriesColumn(0);
        chart->show();

        Wt::Chart::WAxis *yA = new Wt::Chart::WAxis;
        chart->addYAxis(yA);
        yA->setVisible(true);
        yA->setRange(0, 4);

        Wt::Chart::WDataSeries *dataSeries = new Wt::Chart::WDataSeries(1, Wt::Chart::LineSeries, yA->yAxisId());
        GraphModel *gm = new GraphModel(chart);
        dataSeries->setModel(gm);
        chart->addSeries(dataSeries);
    }
};

Replies (6)

RE: Infinite loop/crash in WCartesianChart - Added by Roel Standaert 5 months ago

Ah yes, that violates the constraint of on demand loading that the X series data should be sorted in ascending order, since you can't actually sort NaN values, comparing with NaN always yields false.

RE: Infinite loop/crash in WCartesianChart - Added by Ulf Johnsson 5 months ago

Yeah thats what I suspected.
I resolved it by checking the first and last point in the series, and if they were NaN I simply assigned them to 0, since that series will never be valid.
But is it possible to protect against this without manualy checking the series every time it changes?
In my project the dataseries is generated by the end user from script, so the series might very well contain invalid data suck as NaN.

BR, Ulf.

RE: Infinite loop/crash in WCartesianChart - Added by Roel Standaert 5 months ago

I suppose binarySearchRow could bail with an exception when it encounters NaN, but I don't know if there's an actually good way of dealing with it. Your case is quite simple: the first and last items are NaN, but it would be very specific just to check for that.

RE: Infinite loop/crash in WCartesianChart - Added by Ulf Johnsson 5 months ago

Roel Standaert wrote:

I suppose binarySearchRow could bail with an exception when it encounters NaN, but I don't know if there's an actually good way of dealing with it. Your case is quite simple: the first and last items are NaN, but it would be very specific just to check for that.

No, I dont image that would be a good thing to include in the Wt-trunk.
But do you think it is enough of a check for an end user? Or do you reckon I have to check all values for Nan, and if I encounter any just set an empty array as data?

BR, Ulf.

RE: Infinite loop/crash in WCartesianChart - Added by Roel Standaert 5 months ago

I don't know where you're getting those NaN values from, but I imagine a binary search algorithm is not going to be happy with any NaN values, since they are neither greater than nor smaller than nor equal to any other value.

So, as it is currently implemented you have to make sure that none of the X values are NaN. Are they becoming NaN as the result of some calculation, or...?

RE: Infinite loop/crash in WCartesianChart - Added by Ulf Johnsson 5 months ago

That sounds like what I expeced, then it seems I'll have to check all values to be safe.

We develop an application where the user can configure all aspects of the project that will be running. We also use a stand alone script engine to run server side, to interpret user input, and since everything is configurable by the creator of the project, there is no garantee that the data provided is correct.
Therefor I have to check the provided values so that the dataseries does not get stuck.

(1-6/6)