Menu

How to use the BoxPlot chart type

Gilberto
2013-08-17
2013-08-26
  • Gilberto

    Gilberto - 2013-08-17

    Hi,

    Before anything I'd like to thank you for the new release of the GWT Highcharts, it is a big and nice job.

    I'm having some trouble using the BoxPlot chart in the 1.6.0 version. The reason is there's no Point of type "StatisticalPlot": the values needed by the Point in a BoxPlot chart are min, 1st quartile, median, 3rd quartile and max. Altought is possible to use the 5-number constructor of the Point, it is not meant to be used for StatisticalPlots, since it sets the values as x, open, high, low and close, used by OHLC charts.

    If you try to use the 5-numbers contructor with the statistical data, the chart shows weird values, with no correlation with your actual data.

    I tried to create a new Point subclass, but I figured out that the lib is surprisingly hard to extend without rewriting a good part of it, due to private and package level methods.

    So, it's time to hack. This solution works even with the previous version of GWT Highcharts, given you have the version 3.0.0+ Highcharts lib.

    First of all, create the Chart, a Series, and put a "placeholder" Point in it.

    final Chart chart = new Chart();
    chart.setOption("/chart/type", "boxplot");
    
    Series series = chart.createSeries();
    series.addPoint(0); //whatever the value, it is just a placeholder
    chart.addSeries(series);
    

    After that, and after attaching and redering the chart, you have to capture the native point and directly set the statistical data to it:

    chart.addAttachHandler(new Handler() {
        @Override
        public void onAttachOrDetach(AttachEvent event) {
            if (event.isAttached()){
                if (!executeNativeUpdate()){                           
                    Scheduler.get().scheduleFixedPeriod(new RepeatingCommand() {
                        @Override
                        public boolean execute() {
                            return chart.isAttached() && !executeNativeUpdate();
                        }
                    }, 1000);
                }
            }
        }
    
        private boolean executeNativeUpdate(){
        if (chart.isRendered()){
                Point[] ps = chart.getSeries()[0].getPoints();
            JavaScriptObject nativePoint = ps[0].getNativePoint();
            if (nativePoint != null){ //can be null if the chart is persistent
                    nativeUpdate(nativePoint, min, q1, median, q3, max, true, true);
                    return true;
            }
        }
        return false;
        }
    });
    
    /* Made it private just to annoy the next developer who tries to extend my lib */
    private static native void nativeUpdate(JavaScriptObject point, double low, double q1, double median, double q3, double high, boolean redraw, boolean animation) /*-{
            point.update([low, q1, median, q3, high], redraw, animation);
    }-*/;
    

    An ugly hack, but that's the way I found to make it work. The "min, q1, median, q3, max" values must come from somewhere in your logic (from a DTO in my case).

    There's one caveat: the series.getNativePoint() method doesn't return the linked native point if your chart is set to be persistent (chart.setPersistent(true)), using the v.1.6.0 of the GWT Highcharts lib. It works as expected with the previous version.

    This code is useful to plot a single series with defined values. If you have more than one series, or if your data is dynamic, you have to improve the code to make it work for your case.

    If you have a proper way to set the data on BoxPlot charts, please let me know.

    Thank you.

     

    Last edit: Gilberto 2013-08-17
  • Cory Skowronek

    Cory Skowronek - 2013-08-19

    Greetings Gilberto,

    The method I used for setting points in a Box Plot for the new Showcase Application is

    
    chart.addSeries(chart.createSeries()
        .setName("Observations")
        .setPoints(new Number[][]{
            {760, 801, 848, 895, 965},
            {733, 853, 939, 980, 1080},
            {714, 762, 817, 870, 918},
            {724, 802, 806, 871, 950},
            {834, 836, 864, 882, 910}
        })
    )
    

    This produces the JOSN

    
    "series": [
        {
            "id": "gwt-uid-5",
            "name": "Observations",
            "data": [
                [760, 801, 848, 895, 965],
                [733, 853, 939, 980, 1080],
                [714, 762, 817, 870, 918],
                [724, 802, 806, 871, 950],
                [834, 836, 864, 882, 910]
            ]
        }
    ]
    


    I also tried using the five-parameter Point constructor, and while not semantically correct, it also produces the same JSON.

    
    chart.addSeries(chart.createSeries()
        .setName("Observations")
        .setPoints(new Point[] {
            new Point(760, 801, 848, 895, 965),
            new Point(733, 853, 939, 980, 1080),
            new Point(714, 762, 817, 870, 918),
            new Point(724, 802, 806, 871, 950),
            new Point(834, 836, 864, 882, 910)
        })
    )
    

     

    Last edit: Cory Skowronek 2013-08-21
  • Gilberto

    Gilberto - 2013-08-21

    Hi Cory, thanks for your reply.

    I just discovered that setting the chart as persistent is the real problem with BoxPlots. To reproduce the bug, run this code:

    Chart chart = new Chart();
    chart.setType(Type.BOXPLOT);
    chart.setSize("200px", "200px");
    chart.setPersistent(true); //remove this line to see the proper behavior
    
    Series series = chart.createSeries();
    series.addPoint(new Point(50, 100, 150, 200, 250));
    chart.addSeries(series);
    

    Removing the "chart.setPersistent(true);" line makes the chart work correctly.

     

    Last edit: Gilberto 2013-08-21
  • Cory Skowronek

    Cory Skowronek - 2013-08-21

    Thanks for looking more into this. Have you noticed this behavior with any other chart types?

     
    • Gilberto

      Gilberto - 2013-08-21

      I use the line, bar and pie plots, and I didn't see any strange behavior so far with persistent charts. I'll keep my eye open.

       
  • Cory Skowronek

    Cory Skowronek - 2013-08-26

    We have isolated the problem and are working on a fix. Until then, if persistent charts are absolutely necessary, you can use the setOption method to manually set the data. For example:

    
    chart.setPersistent(true)
        .addSeries(chart.createSeries()
            .setName("Observations")
            .setOption("data", new Number[][] {
                {760, 801, 848, 895, 965},
                {733, 853, 939, 980, 1080},
                {714, 762, 817, 870, 918},
                {724, 802, 806, 871, 950},
                {834, 836, 864, 882, 910}
            })
    ;
    

    For me, this produces

    
    "series": [
        {
            "id": "gwt-uid-5",
            "name": "Observations",
            "data": [
                [760, 801, 848, 895, 965],
                [733, 853, 939, 980, 1080],
                [714, 762, 817, 870, 918],
                [724, 802, 806, 871, 950],
                [834, 836, 864, 882, 910]
            ]
    
     

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.