Changeset 2001


Ignore:
Timestamp:
Sep 7, 2011, 5:32:34 PM (8 years ago)
Author:
taco@…
Message:

Update for the visualization controller, first support for multiple categories on the y axis

File:
1 edited

Legend:

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

    r2000 r2001  
    9393             */
    9494
     95            def moduleFields = []
    9596            study.getAssays().each { assay ->
    9697                def list = []
     
    99100                    if(list.size()!=0){
    100101                        fields += list
    101 
     102                        moduleFields += list
    102103                    }
    103104                }
    104105            }
     106
     107            // Creating the option to select composite fields (fields that all occur on one module)
     108            AssayModule.list().each { am ->
     109                def list = []
     110                moduleFields.each { mf ->
     111                    if(mf.source==am.id){
     112                        list << mf
     113                    }
     114                }
     115                if(list!=[]){
     116                    def compositeId = ""
     117                    def compositeIdId = ""
     118                    def compositeIdName = ""
     119                    def compositeIdSource = ""
     120                    def compositeIdType = ""
     121                    def source = am.id
     122                    def compositeCategory = ""
     123                    def compositeName = ""
     124
     125                    for(int i = 0; i < list.size(); i++){
     126                        def singleAssayId = list[i].id.split(',')[2]
     127                        if(i==0){
     128                            compositeIdType += list[i].category
     129                            compositeCategory += list[i].category
     130                            compositeIdSource += "compositeId"+singleAssayId
     131                            compositeIdName += list[i].name
     132                            compositeName += list[i].name
     133                        } else {
     134                            compositeIdType += "@SEP@"+list[i].category
     135                            compositeCategory += "@SEP@"+list[i].category
     136                            compositeIdSource += "@SEP@"+singleAssayId
     137                            compositeIdName += "@SEP@"+list[i].name
     138                            if(list.size()>1 && i==(list.size()-1)){
     139                                compositeName += " and "+list[i].name
     140                            } else {
     141                                compositeName += ", "+list[i].name
     142                            }
     143                        }
     144                    }
     145                    compositeId = createFieldId(id: compositeIdId, name: compositeIdName, source: compositeIdSource, type: compositeIdType)
     146                    def compositeField = ["id": compositeId, "source": source, "category": compositeCategory, "name": compositeName]
     147                    fields << compositeField
     148                    //println "compositeField: "+compositeField
     149                }
     150            }
     151
    105152
    106153            // TODO: Maybe we should add study's own fields
     
    324371
    325372                // Group data based on the y-axis if categorical axis is selected
    326                 // TODO: handle categories and continuous data
    327                 def groupedData = groupFieldData( data );
    328 
    329                 // Format data so it can be rendered as JSON
    330                 def returnData = formatData( groupedData, fields );
    331 
    332                 return sendResults(returnData)
     373
     374        // Detecting if, on the y-axis, we have categories (multiple fields on an axis)
     375        // For some reason, the class of the elements will be considered null incase of categories
     376        // I'd rather have filtered on being an instance of Collection, or something along those lines
     377        if(data['y'][0].class==null && data['y'][0]['category']!=null){
     378            // We are dealing with multiple categories
     379            def groupedData = []
     380            def returnData = []
     381
     382            data['y'].each{
     383                def tmp_GFdat = groupFieldData(['x': data['x'], 'y': it['category']['data']] );
     384                groupedData << tmp_GFdat
     385
     386                // Format data so it can be rendered as JSON
     387                def tmp_Fdat = formatData( tmp_GFdat, ['x': fields['x'], 'y': "a,"+it['category']['name']+",a,a"] );
     388                //println "\tmp_Fdat: "+tmp_Fdat
     389                returnData << tmp_Fdat
     390            }
     391
     392            // Format data so it can be rendered as JSON
     393            def returnDataWithMultipleCategories = formatCategoryData(returnData)
     394            return sendResults(returnDataWithMultipleCategories)
     395        } else {
     396            // We are dealing with a single category
     397            def groupedData = groupFieldData( data );
     398   
     399            // Format data so it can be rendered as JSON
     400            def returnData = formatData( groupedData, fields );
     401            return sendResults(returnData)
     402        }
    333403        }
    334404
     
    441511         *                                                      [ 3, 6, null, 10 ] or [ "male", "male", "female", "female" ]
    442512         */
    443         def getModuleData( study, samples, source_module, fieldName ) {
     513        def getModuleData( study, samples, assay_id, fieldName ) {
    444514                def data = []
    445                
     515                //println "assay_id: "+assay_id+", fieldName: "+fieldName
    446516                // TODO: Handle values that should be retrieved from multiple assays
    447                 def assay = Assay.get(source_module);
    448                
    449                 if( assay ) {
    450                         // Request for a particular assay and a particular feature
    451                         def urlVars = "assayToken=" + assay.assayUUID + "&measurementToken="+fieldName
    452                         urlVars += "&" + samples.collect { "sampleToken=" + it.sampleUUID }.join( "&" );
    453                        
    454                         def callUrl
    455                         try {
    456                                 callUrl = assay.module.url + "/rest/getMeasurementData"
    457                                 def json = moduleCommunicationService.callModuleMethod( assay.module.url, callUrl, urlVars, "POST" );
    458                                
    459                                 if( json ) {
    460                                         // First element contains sampletokens
    461                                         // Second element contains the featurename
    462                                         // Third element contains the measurement value
    463                                         def sampleTokens = json[ 0 ]
    464                                         def measurements = json[ 2 ]
    465                                        
    466                                         // Loop through the samples
    467                                         samples.each { sample ->
    468                                                 // Search for this sampletoken
    469                                                 def sampleToken = sample.sampleUUID;
    470                                                 def index = sampleTokens.findIndexOf { it == sampleToken }
    471                                                
    472                                                 if( index > -1 ) {
    473                                                         data << measurements[ index ];
    474                                                 } else {
    475                                                         data << null
    476                                                 }
    477                                         }
    478                                 } else {
    479                                         // TODO: handle error
    480                                         // Returns an empty list with as many elements as there are samples
    481                                         data = samples.collect { return null }
    482                                 }
    483                                
    484                         } catch(Exception e){
    485                 log.error("VisualizationController: getFields: "+e)
    486                 return returnError(404, "An error occured while trying to collect data from a module. Most likely, this module is offline.")
    487                         }
    488                 } else {
    489                         // TODO: Handle error correctly
    490                         // Returns an empty list with as many elements as there are samples
    491                         data = samples.collect { return null }
    492                 }
    493                
     517        // Check if this id starts with "compositeId", which indicates that the request concerns multiple assays from the same source module
     518        if(assay_id.toString().startsWith("compositeId")){
     519            //println "composite data request."
     520            // This assay_id is a composite, meaning that the user is requesting data from multiple assays
     521            //data = [:]
     522            def ids = assay_id.toString().substring("compositeId".length()).split("@SEP@")
     523            def names = fieldName.split("@SEP@")
     524            ids.eachWithIndex { it, i ->
     525                //println "data request decomposition:"
     526                data << ['category': ['name': names[i], 'data': getModuleData(study, samples, it, names[i])]]
     527            }
     528        } else {
     529            def assay = Assay.get(assay_id);
     530
     531            if( assay ) {
     532                // Request for a particular assay and a particular feature
     533                def urlVars = "assayToken=" + assay.assayUUID + "&measurementToken="+fieldName
     534                urlVars += "&" + samples.collect { "sampleToken=" + it.sampleUUID }.join( "&" );
     535
     536                def callUrl
     537                try {
     538                    callUrl = assay.module.url + "/rest/getMeasurementData"
     539                    def json = moduleCommunicationService.callModuleMethod( assay.module.url, callUrl, urlVars, "POST" );
     540
     541                    if( json ) {
     542                        // First element contains sampletokens
     543                        // Second element contains the featurename
     544                        // Third element contains the measurement value
     545                        def sampleTokens = json[ 0 ]
     546                        def measurements = json[ 2 ]
     547
     548                        // Loop through the samples
     549                        samples.each { sample ->
     550                            // Search for this sampletoken
     551                            def sampleToken = sample.sampleUUID;
     552                            def index = sampleTokens.findIndexOf { it == sampleToken }
     553
     554                            if( index > -1 ) {
     555                                data << measurements[ index ];
     556                            } else {
     557                                data << null
     558                            }
     559                        }
     560                    } else {
     561                        // TODO: handle error
     562                        // Returns an empty list with as many elements as there are samples
     563                        data = samples.collect { return null }
     564                    }
     565
     566                } catch(Exception e){
     567                    log.error("VisualizationController: getFields: "+e)
     568                    return returnError(404, "An error occured while trying to collect data from a module. Most likely, this module is offline.")
     569                }
     570            } else {
     571                // TODO: Handle error correctly
     572                // Returns an empty list with as many elements as there are samples
     573                data = samples.collect { return null }
     574            }
     575        }
     576
     577
     578        //println "\t data request: "+data
    494579                return data
    495 
    496580        }
    497581
     
    524608                                                .flatten()
    525609                                                .unique { it == null ? "null" : it.class.name + it.toString() }
    526                
    527610                // Make sure the null category is last
    528611                groups = groups.findAll { it != null } + groups.findAll { it == null }
    529                
    530612                // Gather names for the groups. Most of the times, the group names are just the names, only with
    531613                // a null value, the unknownName must be used
    532614                def groupNames = groups.collect { it != null ? it : unknownName }
    533                
    534615                // Generate the output object
    535616                def outputData = [:]
     
    550631                        outputData[ errorName ] << dataForGroup.error
    551632                }
    552 
    553633                return outputData
    554634        }
     
    902982        render results as JSON
    903983    }
     984
     985    /*
     986        Combine several blocks of formatted data into one
     987     */
     988    protected def formatCategoryData(inputData){
     989        def series = []
     990        inputData.eachWithIndex { it, i ->
     991            series << ['name': it['yaxis']['title'], 'y': it['series']['y'][0], 'error': it['series']['error'][0]]
     992        }
     993        def ret = [:]
     994        ret.put('type', inputData[0]['type'])
     995        ret.put('x', inputData[0]['x'])
     996        ret.put('yaxis',['title': 'title', 'unit': ''])
     997        ret.put('xaxis', inputData[0]['xaxis'])
     998        ret.put('series', series)
     999        return ret
     1000    }
    9041001}
Note: See TracChangeset for help on using the changeset viewer.