Changeset 2055

Show
Ignore:
Timestamp:
10-10-11 18:09:59 (3 years ago)
Author:
tjeerd@…
Message:

VIS-31 and VIS-23, added some aggregation and other advanced settings. The option "no aggregation" is not present yet. There is also an error with the count-aggregation (see VIS-34)

Location:
trunk
Files:
4 modified

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/controllers/dbnp/visualization/VisualizeController.groovy

    r2054 r2055  
    405405                        // Retrieve data from GSCF itself 
    406406                        def closure = valueCallback( parsedField.type ) 
    407                          
     407 
    408408                        if( closure ) { 
    409409                                samples.each { sample -> 
     
    606606                                // The computation for mean and error will return null if no (numerical) values are found 
    607607                                // In that case, the user won't see this category 
    608                                 def dataForGroup = computeMeanAndError( values ); 
     608                def dataForGroup = null; 
     609                switch( params.get( 'aggregation') ) { 
     610                                case "average": 
     611                        dataForGroup = computeMeanAndError( values ); 
     612                        break; 
     613                    case "count": 
     614                        dataForGroup = computeCount( values ); 
     615                        break; 
     616                    case "median": 
     617                        dataForGroup = computeMedian( values ); 
     618                        break; 
     619                    case "none": 
     620                        // Currently disabled, create another function 
     621                        dataForGroup = computeMeanAndError( values ); 
     622                        break; 
     623                    case "sum": 
     624                        dataForGroup = computeSum( values ); 
     625                        break; 
     626                    default: 
     627                        // Default is "average" 
     628                        dataForGroup = computeMeanAndError( values ); 
     629                } 
     630 
    609631 
    610632                                if( showEmptyCategories || dataForGroup.value != null ) { 
     
    742764            if(it instanceof Number) { 
    743765                try{ 
    744                     tmpDateContainer << new java.util.Date( it ).toString() 
     766                    tmpDateContainer << new java.util.Date( (Long) it ).toString() 
    745767                } catch(IllegalArgumentException e){ 
    746768                    tmpDateContainer << it 
     
    878900        /** 
    879901         * Computes the mean of the given values. Values that can not be parsed to a number 
    880          * are ignored. If no values are given, the mean of 0 is returned. 
     902         * are ignored. If no values are given, null is returned. 
    881903         * @param values        List of values to compute the mean for 
    882904         * @return                      Arithmetic mean of the values 
     
    890912                                sumOfValues += num; 
    891913                                sizeOfValues++ 
    892                         }  
     914                        } 
    893915                } 
    894916 
     
    896918                        return sumOfValues / sizeOfValues; 
    897919                else 
    898                         return null;  
     920                        return null; 
    899921        } 
    900922 
     
    902924        * Computes the standard error of mean of the given values.  
    903925        * Values that can not be parsed to a number are ignored.  
    904         * If no values are given, the standard deviation of 0 is returned. 
     926        * If no values are given, null is returned. 
    905927        * @param values         List of values to compute the standard deviation for 
    906928        * @param mean           Mean of the list (if already computed). If not given, the mean  
     
    929951       } 
    930952    } 
     953 
     954    /** 
     955         * Computes the median of the given values. Values that can not be parsed to a number 
     956         * are ignored. If no values are given, null is returned. 
     957         * @param values        List of values to compute the median for 
     958         * @return                      Median of the values 
     959         */ 
     960        protected def computeMedian( List values ) { 
     961                def listOfValues = []; 
     962                values.each { value -> 
     963                        def num = getNumericValue( value ); 
     964                        if( num != null ) { 
     965                                listOfValues << num; 
     966                        } 
     967                } 
     968 
     969        listOfValues.sort(); 
     970 
     971        def listSize = listOfValues.size(); 
     972 
     973                if( listSize > 0 ) { 
     974            def listHalf = (int) Math.abs(listSize/2); 
     975            if(listSize%2==0) { 
     976                // If the list is of an even size, take the mean of the middle two value's 
     977                return ["value": (listOfValues.get(listHalf)+listOfValues.get(listHalf-1))/2]; 
     978            } else { 
     979                // If the list is of an odd size, take the middle value 
     980                return ["value": listOfValues.get(listHalf-1)]; 
     981            } 
     982        } else 
     983                        return ["value": null]; 
     984        } 
     985 
     986    /** 
     987         * Computes the count of the given values. Values that can not be parsed to a number 
     988         * are ignored. If no values are given, null is returned. 
     989         * @param values        List of values to compute the count for 
     990         * @return                      Count of the values 
     991         */ 
     992        protected def computeCount( List values ) { 
     993                def sumOfValues = 0; 
     994                def sizeOfValues = 0; 
     995                values.each { value -> 
     996                        def num = getNumericValue( value ); 
     997                        if( num != null ) { 
     998                                sumOfValues += num; 
     999                                sizeOfValues++ 
     1000                        } 
     1001                } 
     1002 
     1003                if( sizeOfValues > 0 ) 
     1004                        return ["value": sizeOfValues]; 
     1005                else 
     1006                        return ["value": null]; 
     1007        } 
     1008 
     1009    /** 
     1010         * Computes the sum of the given values. Values that can not be parsed to a number 
     1011         * are ignored. If no values are given, null is returned. 
     1012         * @param values        List of values to compute the sum for 
     1013         * @return                      Arithmetic sum of the values 
     1014         */ 
     1015        protected def computeSum( List values ) { 
     1016                def sumOfValues = 0; 
     1017                def sizeOfValues = 0; 
     1018                values.each { value -> 
     1019                        def num = getNumericValue( value ); 
     1020                        if( num != null ) { 
     1021                                sumOfValues += num; 
     1022                                sizeOfValues++ 
     1023                        } 
     1024                } 
     1025 
     1026                if( sizeOfValues > 0 ) 
     1027                        return ["value": sumOfValues]; 
     1028                else 
     1029                        return ["value": null]; 
     1030        } 
    9311031     
    9321032        /** 
  • trunk/grails-app/views/visualize/index.gsp

    r2051 r2055  
    4747 
    4848                <span class="topmenu_item" id="menu_study"> 
    49                     <span class="topmenu_item_label"><img src="${fam.icon( name: 'report' )}" style="vertical-align: text-bottom; display: inline-block;"/>&nbsp;Study<img src="${resource(dir: 'images', file: 'spinner.gif')}" class="spinner" />:</span> 
    50                     <span class="topmenu_item_info">no study selected</span> 
     49                    <div class="topmenu_item_label"><img src="${fam.icon( name: 'report' )}" style="vertical-align: text-bottom; display: inline-block;"/>&nbsp;Study<img src="${resource(dir: 'images', file: 'spinner.gif')}" class="spinner" />:</div> 
     50                    <div class="topmenu_item_info">no study selected</div> 
    5151                    <img src="${fam.icon( name: 'bullet_arrow_down' )}" style="vertical-align: text-bottom; display: inline-block;"/> 
    5252                    <div class="formulier"> 
     
    5858                </span> 
    5959 
    60                 
     60                <span class="menu_seperator">&nbsp;</span> 
     61 
     62                <span class="topmenu_item" id="menu_aggregation"> 
     63                    <span class="topmenu_item_label"><img src="${fam.icon( name: 'server_chart' )}" style="vertical-align: text-bottom; display: inline-block;"/>&nbsp;Aggregation:</span> 
     64                    <span class="topmenu_item_info">AVERAGE</span> 
     65                    <img src="${fam.icon( name: 'bullet_arrow_down' )}" style="vertical-align: text-bottom; display: inline-block;"/> 
     66                    <div class="formulier"> 
     67                        <p class="info">Select a way to aggregate the data.</p> 
     68                        <p> 
     69                            <select name="aggregation" size="5" onchange="$('#menu_aggregation').children('.topmenu_item_info').html($(this).val().toUpperCase()); changeVis();"> 
     70                                <option value="average" SELECTED>Average</option> 
     71                                <option value="count">Count</option> 
     72                                <option value="median">Median</option> 
     73                                <option value="none" disabled>No aggregation</option> 
     74                                <option value="sum">Sum</option> 
     75                            </select> 
     76                        </p> 
     77                    </div> 
     78                </span> 
    6179 
    6280                <span class="menu_seperator">&nbsp;</span> 
     
    6684                    <img src="${fam.icon( name: 'bullet_arrow_down' )}" style="vertical-align: text-bottom; display: inline-block;"/> 
    6785                    <div class="formulier"> 
    68                         <p class="info">Advanced settings.</p> 
    69                         <p> 
    70                             Visualize the data as soon as enough parameters are known. 
    71                             <input type="checkbox" name="autovis" id="autovis" CHECKED/> 
    72                         </p> 
     86                        <table> 
     87                            <tr> 
     88                                <td>Visualize the data as soon as enough parameters are known.</td> 
     89                                <td><input type="checkbox" name="autovis" id="autovis" CHECKED/></td> 
     90                            </tr> 
     91                            <tr> 
     92                                <td>Always show values in the graph.<br />(if this box is unchecked, value's are only shown when you hover over a datapoint)</td> 
     93                                <td><input type="checkbox" name="showvalues" id="showvalues" onClick="changeVis();"/></td> 
     94                            </tr> 
     95                        </table> 
    7396                    </div> 
    7497                </span> 
  • trunk/web-app/css/visualization.css

    r2051 r2055  
    113113} 
    114114 
    115 .menu_item:hover { 
    116     background-color: #EEE; 
    117 } 
    118  
    119115.menu_item_done { 
    120116    background-color: #67E667; 
     
    183179    position: relative; 
    184180    padding: 3px; 
     181    height: 14px; 
     182    vertical-align: top; 
    185183} 
    186184 
     
    191189 
    192190.topmenu_item_label { 
     191    display: inline-block; 
     192    vertical-align: text-bottom; 
    193193    color: #000033; 
    194194} 
    195195 
    196196.topmenu_item_info { 
     197    display: inline-block; 
     198    vertical-align: top; 
    197199    color: #000066; 
     200    overflow: hidden; 
     201    width:auto; 
     202    max-width: 200px; 
     203    max-height: 18px; 
    198204} 
    199205 
     
    201207    font-size: 10px; 
    202208    position: absolute; 
    203     top: 22px; 
     209    top: 21px; 
    204210    left: 0px; 
    205211    display: none; 
     
    214220    width: 100%; 
    215221    font-size: 10px; 
     222} 
     223 
     224.formulier table { 
     225    border-style: none; 
     226} 
     227 
     228.formulier table td { 
     229    font-size: 10px; 
     230    padding: 6px 2px; 
     231} 
     232 
     233#menu_advanced .formulier { 
     234    width: 300px; 
    216235} 
    217236 
  • trunk/web-app/js/visualization.js

    r2051 r2055  
    1010    $(".topmenu_item").click( 
    1111        function(event) { 
    12             if(openForm!=null && this!=openForm) { 
    13                 $(openForm).children('.formulier').hide(); 
     12            if(this!=openForm) { 
     13                toggleForm(this, "open"); 
     14            } else { 
     15                toggleForm(this, "close"); 
    1416            } 
    15             $(this).children('.formulier').toggle(); 
    16             openForm = this; 
    1717            return false; 
    1818                } 
     
    2121    $(document).keyup( 
    2222        function(event) { 
    23             if ( event.which == 27 && openForm!=null ) { 
    24                 $(openForm).children('.formulier').hide(); 
    25                 openForm = null; 
     23            if ( event.which == 27 ) { 
     24                toggleForm(openForm, "close"); 
    2625            } 
    2726        } 
     
    3029    $(document).click( 
    3130        function() { 
    32             if(openForm!=null) { 
    33                 $(openForm).children('.formulier').hide(); 
    34                 openForm = null; 
    35             } 
     31            toggleForm(openForm, "close"); 
    3632        } 
    3733    ); 
     
    4945function changeStudy() { 
    5046 
    51  
    52     $("#menu_study").children('.formulier').hide(); 
    53     openForm = null; 
    54  
    55     $( '#rows, #columns, #types' ).empty(); 
     47    toggleForm(openForm, "close"); 
     48 
     49    $( '#rows, #columns, #types, #visualization' ).empty(); 
    5650    clearStep(".menu_item"); 
    5751 
     
    6155    if($( '#study option:selected' ).length>0) { 
    6256        $( "#menu_row, #menu_column" ).find("img.spinner").show(); 
    63         $( "#menu_study" ).find("span.topmenu_item_info").html($( '#study option:selected' ).text()); 
     57        $( "#menu_study" ).find("div.topmenu_item_info").html($( '#study option:selected' ).text()); 
    6458 
    6559        executeAjaxCall( "getFields", { 
     
    8983                    $( "#rows, #columns" ).html(strOptions); 
    9084                         
    91                         $( "#menu_study" ).find("span.topmenu_item_info").html($( '#study option:selected' ).text()); 
     85                        $( "#menu_study" ).find("div.topmenu_item_info").html($( '#study option:selected' ).text()); 
    9286                    $( "#menu_row, #menu_column" ).find("img.spinner").hide(); 
    9387                        $( "#menu_row, #menu_column" ).addClass("menu_item_fill"); 
     
    10296 */ 
    10397function changeFields(divid) { 
    104  
    105     var type = "rows"; 
    106     if(divid=="menu_column") type = "columns"; 
    10798 
    10899    clearStep("#"+divid); 
     
    163154        visType = $( '#types option:selected' ).text(); 
    164155    } else { 
    165         $( "#menu_vis" ).removeClass().addClass("menu_item menu_item_fill"); 
     156        if( $( "#menu_row" ).hasClass("menu_item_done") && $( "#menu_column" ).hasClass("menu_item_done") ) { 
     157            $( "#menu_vis" ).removeClass().addClass("menu_item menu_item_fill"); 
     158        } 
    166159    } 
    167160    $( "#menu_go" ).removeClass().addClass("menu_item"); 
     
    179172function visualize() { 
    180173 
    181     if(!$( "#menu_vis" ).hasClass("menu_item_done") || 
    182         !$( "#menu_row" ).hasClass("menu_item_done") || 
    183         !$( "#menu_column" ).hasClass("menu_item_done") 
     174    if($( "#menu_vis" ).hasClass("menu_item_done") && 
     175        $( "#menu_row" ).hasClass("menu_item_done") && 
     176        $( "#menu_column" ).hasClass("menu_item_done") 
    184177       ) { 
    185         $( ".menu_item" ).not(".menu_item_done").removeClass().addClass("menu_item menu_item_warning"); 
    186     } else { 
    187  
    188178        executeAjaxCall( "getData", { 
    189179            "errorMessage": "An error occurred while retrieving data from the server. Please try again or contact a system administrator.", 
     
    229219                // chosen by the user 
    230220                var plotOptions = null; 
     221 
     222                var showDataValues = $("#showvalues").attr("checked")=="checked" ? true : false; 
    231223                 
    232224                switch( returnData.type ) { 
     
    244236                                    highlightMouseDown: true, 
    245237                                    barDirection: 'horizontal' 
    246                                 } 
     238                                }, 
     239                                pointLabels: {show: showDataValues} 
    247240                            }, 
    248241                            highlighter: { 
    249                                 show: true, 
     242                                show: !showDataValues, 
    250243                                sizeAdjust: 7.5, 
    251                                 tooltipAxes: "y" 
     244                                tooltipAxes: "x" 
    252245                            }, 
    253246                            series: series, 
    254247                            axes: { 
    255248                                xaxis: { 
    256                                     //ticks: returnData.series[ 0 ].y,          // Use the x-axis of the first serie 
    257249                                    label: ylabel, 
    258250                                    formatString:'%.2f', 
     
    261253                                yaxis: { 
    262254                                    renderer: $.jqplot.CategoryAxisRenderer, 
     255                                    ticks: returnData.series[ 0 ].x,            // Use the x-axis of the first serie 
    263256                                    label: xlabel, 
    264257                                    labelRenderer: $.jqplot.CanvasAxisLabelRenderer 
     
    276269                            stackSeries: true, 
    277270                            seriesDefaults:{ 
    278                                 renderer:$.jqplot.LineRenderer 
     271                                renderer:$.jqplot.LineRenderer, 
     272                                pointLabels: {show: showDataValues} 
    279273                            }, 
    280274                            series: series, 
    281275                            highlighter: { 
    282                                 show: true, 
     276                                show: !showDataValues, 
    283277                                sizeAdjust: 7.5, 
    284278                                tooltipAxes: "y" 
     
    302296                            stackSeries: true, 
    303297                            seriesDefaults:{ 
    304                                 renderer:$.jqplot.LineRenderer 
     298                                renderer:$.jqplot.LineRenderer, 
     299                                pointLabels: {show: showDataValues} 
    305300                            }, 
    306301                            series: series, 
    307302                            highlighter: { 
    308                                 show: true, 
     303                                show: !showDataValues, 
    309304                                sizeAdjust: 7.5, 
    310305                                tooltipAxes: "y" 
     
    337332                                    // Disables default highlighting on mouse over. 
    338333                                    highlightMouseDown: true 
    339                                 } 
     334                                }, 
     335                                pointLabels: {show: showDataValues} 
    340336                            }, 
    341337                            highlighter: { 
    342                                 show: true, 
     338                                show: !showDataValues, 
    343339                                sizeAdjust: 7.5, 
    344340                                tooltipAxes: "y" 
     
    441437        $( '#message_counter' ).children(".formulier").toggle(); 
    442438        openForm = null; 
     439    } 
     440} 
     441 
     442function toggleForm(selector, action) { 
     443    if( action=="close" || openForm !=null ) { 
     444        $(openForm).children('.formulier').hide(); 
     445        $(openForm).removeClass("topmenu_item_selected"); 
     446        openForm = null; 
     447    } 
     448    if( action=="open" ) { 
     449        $(selector).children('.formulier').show(); 
     450        $(selector).addClass("topmenu_item_selected"); 
     451        openForm = selector; 
    443452    } 
    444453}