Esempio n. 1
0
    def __init__(self,
                 analysisDef,
                 trackName1,
                 trackName2,
                 userBinSource,
                 genome=None,
                 galaxyFn=None,
                 *args,
                 **kwArgs):
        from gold.description.Analysis import Analysis

        #  to be removed later.. Just for convenience with development now..
        self._analysisDef = analysisDef
        #  self._trackName1 = trackName1
        #  self._trackName2 = trackName2

        if genome is None:
            genome = userBinSource.genome

        self._galaxyFn = galaxyFn
        self._analysis = Analysis(analysisDef, genome, trackName1, trackName2)

        track, track2 = self._analysis.getTracks()
        statistic = self._analysis.getStat()
        self._analysis.initRandomUtilAndUpdateSeedIfNeeded()

        StatJob.__init__(self, userBinSource, track, track2, statistic, *args,
                         **kwArgs)
 def getRevEngBatchLine(trackName1, trackName2, cleanedTrackName1, cleanedTrackName2, analysisDef, \
                        regSpec, binSpec, genome, manualSeed, **kwArgs):
     #analysisDef is assumed to be unquoted
     
     #if this is to work, must check explicitly against special keywords  in regSpec (or check that regSpec is a valid region that is to have region..)...
     #if not genome in regSpec:
     #    regSpec = genome+':'+regSpec
     try:
         if DebugConfig.VERBOSE:
             logMessage('getting RevEngBatchLine:')
         #analysisDef =analysisDef.replace('%20PointCountInSegsPvalStat%2C','') #REMOVE
         #print 'NOWAG: ',analysisDef
         
         analysis = Analysis(analysisDef, genome, cleanedTrackName1, cleanedTrackName2, **kwArgs)
         stat = analysis.getStat()
         if stat is None:
             return 'No corr batch line, as no valid statistic was found.. '
         #print 'CAME HERE'
         statClassName = stat.__name__
         #fixme: Add space, but this is not checked in batchrunner...
         params = ','.join(['='.join([choicePair[0], str(manualSeed)]) \
                              if (manualSeed is not None and choicePair[0] == 'randomSeed' and choicePair[1] == 'Random')
                                 else '='.join(choicePair) \
                             for choicePair in analysis.getChoices().items() \
                              if choicePair[0] not in ['H0','H1_more','H1_less','H1_different','H1_ha1','H1_ha2','H1_ha3','H1_ha4','H1_ha5'] ])
         statText = statClassName + '(' + params + ')'
         #return BATCH_COL_SEPARATOR.join([regSpec, binSpec, \
         #                 (':'.join(trackName1)).replace(' ','_'),\
         #                 (':'.join(trackName2)).replace(' ','_') if trackName2 is not None else 'None',\
         #                 statText])
         #assert unquote(regSpec) == regSpec
         assert unquote(binSpec) == binSpec #To assure that unquote can be safely applied to binSpec without any consequences (we don't want to always quote, but still want the possibility to use quoted history track names)
         batchElements = [genome, regSpec, binSpec, \
                          (':'.join([quote(x, safe='') for x in trackName1])),\
                          (':'.join([quote(x, safe='') for x in trackName2])) if trackName2 is not None else 'None',\
                          statText]
         #batchElements = [el.replace(BATCH_COL_SEPARATOR, '\\' + BATCH_COL_SEPARATOR) for el in batchElements]
         #batchElements = [quote(el, safe='') for el in batchElements]
         return BATCH_COL_SEPARATOR.join(batchElements)
         
     except Exception,e:
         #raise
         logException(e,logging.WARNING,'Could not generate corresponding batch line: ')
         #if DebugConfig.VERBOSE:
         logMessage('analysisDef, genome, trackName1, trackName2: \n' +
                    str([analysisDef, genome, trackName1, trackName2]) )
         return 'Warning: Could not generate corresponding batch line.' 
Esempio n. 3
0
    def _tryAnalysisDefForValidity(analysisDef,
                                   genome,
                                   trackName1,
                                   trackName2,
                                   tryReversed=True):
        if DebugConfig.VERBOSE:
            logMessage('Trying analysisDef: ' + str(analysisDef))
        try:
            for tnA, tnB, reversed in [
                (trackName1, trackName2, False)
            ] + ([(trackName2, trackName1, True)] if tryReversed else []):
                #print "TEMP1: ", (analysisDef, genome, tnA, tnB)
                analysis = Analysis(analysisDef, genome, tnA, tnB, reversed)

                #analysis.setTracks(trackName1, trackName2)
                #analysis.setConverters(formatConverter1, formatConverter2)
                if analysis.isValid():
                    return analysis, reversed
        except Exception, e:
            if DebugConfig.VERBOSE:
                logException(e)
            if DebugConfig.PASS_ON_VALIDSTAT_EXCEPTIONS:
                raise
Esempio n. 4
0
 def __init__(self, analysisDef, trackName1, trackName2, userBinSource, genome=None, *args, **kwArgs):        
     from gold.description.Analysis import Analysis
 
     #to be removed later.. Just for convenience with development now.. 
     self._analysisDef = analysisDef
     #self._trackName1 = trackName1
     #self._trackName2 = trackName2
     
     if genome is None:
         genome = userBinSource.genome
         
     self._analysis = Analysis(analysisDef, genome, trackName1, trackName2)
     self._setRandomSeedIfNeeded()
         
     track, track2 = self._analysis.getTracks()
     StatJob.__init__(self, userBinSource, track, track2, self._analysis.getStat(), *args, **kwArgs)
Esempio n. 5
0
 def _tryAnalysisForValidity(cls,
                             analysis,
                             genome,
                             trackName1,
                             trackName2,
                             tryReversed=True):
     if DebugConfig.VERBOSE:
         logMessage('Trying analysisDef: ' + str(analysis.getDef()))
     try:
         if cls._trackFormatsAreEqual(genome, trackName1, trackName2):
             tryReversed = False
         for tnA, tnB, reversed in [(trackName1, trackName2, False)] + \
                                   ([(trackName2, trackName1, True)] if tryReversed and trackName2 not in [None, []] else
                                   []):
             analysis = Analysis.createFromParsedAnalysis(
                 analysis, genome, tnA, tnB, reversed)
             if analysis.isValidForListing():
                 return analysis, reversed
     except Exception, e:
         if DebugConfig.VERBOSE:
             logException(e)
         if DebugConfig.PASS_ON_VALIDSTAT_EXCEPTIONS:
             raise
Esempio n. 6
0
    def getRunDescription(genome, trackNames, analysisDef, ubSource,
                          revEngBatchLine, urlForTrackAutoSelection, **kwArgs):
        # genome = ubSource.genome
        assert len(trackNames) == 3
        core = HtmlCore()

        analysis = Analysis(analysisDef, genome, trackNames[0], trackNames[1],
                            **kwArgs)

        core.header('GENOME')
        core.append(GenomeInfo(genome).mainInfo(printEmpty=False))
        core.divider()

        formatChoices = analysis.getFormatConverterChoicesAsText().items()
        tr1FormatChoice, tr2FormatChoice = formatChoices if len(
            formatChoices) == 2 else (None, None)

        first = True
        for tn,label,formatChoice in zip(trackNames, \
                                         ['TRACK 1', 'TRACK 2', 'INTENSITY TRACK'], \
                                         [tr1FormatChoice, tr2FormatChoice, None]):
            if tn in [None, []]:
                continue

            if not first:
                core.divider()

            core.header(label)
            trackInfo = TrackInfo(genome, tn)
            trackText = ''
            if ExternalTrackManager.isHistoryTrack(tn):
                assert len(
                    tn) >= 4, 'Length of external track name < 4: %s' % str(tn)
                core.descriptionLine(
                    'Name',
                    ExternalTrackManager.extractNameFromHistoryTN(tn) +
                    ' (from history)' + os.linesep)
            else:
                core.descriptionLine('Name', ':'.join(tn) + os.linesep)
            core.append(trackInfo.mainInfo(printEmpty=False))

            if formatChoice is not None:
                core.descriptionLine('Treated as', formatChoice[1])

            first = False

        core.divider()
        core.header('ANALYSIS')
        core.paragraph(''.join(str(analysis).split(':')[1:]))

        first = True
        for label, choice in analysis.getInterfaceChoicesAsText().items():
            if first:
                core.divider()
                core.header('OPTIONS')

            core.descriptionLine(label, choice)
            first = False

        h0 = analysis.getH0()
        if h0 is not None:
            core.divider()
            core.header('NULL HYPOTHESIS')
            core.paragraph(h0)

        h1 = analysis.getH1()
        if h1 is not None:
            core.divider()
            core.header('ALTERNATIVE HYPOTHESIS')
            core.paragraph(h1)

        core.divider()
        core.header('ANALYSIS REGIONS')
        if hasattr(ubSource, 'description'):
            core.paragraph(ubSource.description)

        core.divider()
        core.header('SOLUTION')

        statClass = analysis.getStat()
        #One alternative is to put getDescription in MagicStatFactory-hierarchy as class-method, and get real class behind partial-object.
        #if isinstance(statClass, functools.partial):
        #statClass = statClass.func
        #core.paragraph( statClass.getDescription() )

        #Chosen alternative is to Instantiate an object, which will automatically give object of real class..
        #and then use the following two lines, which will get class in Statistic-hierarchy instead of MagicStatFactory-hierarchy ..
        try:
            reg = ubSource.__iter__().next()
        except:
            core.paragraph(
                'Solution not relevant, as there are no specified analysis regions..'
            )
        else:
            track1, track2 = analysis.getTracks()
            if statClass is None:
                core.paragraph(
                    'Solution not available, due to currently invalid analysis'
                )
                logMessage('Solution not available, with params: ' +
                           str([trackNames[0], trackNames[1], analysisDef]),
                           level=logging.WARN)
            else:
                statObj = statClass(reg, track1, track2)
                statDescr = statObj.getDescription()
                replPat = '<a href=' + os.sep.join(
                    [STATIC_REL_PATH, 'notes', 'stats', '']) + r'\1>note</a>'
                statDescr = re.sub('<note>(.*)</note>', replPat, statDescr)

                core.paragraph(statDescr)

        core.divider()
        core.header('TIME OF ANALYSIS')
        core.paragraph('Analysis initiated at time: ' +
                       str(datetime.datetime.now()))

        if urlForTrackAutoSelection not in [None, '']:
            core.divider()
            core.header('URL FOR TRACK AUTOSELECTION')
            #urlOptions = '&'.join(['track1=' + quote(':'.join(trackName1)), 'track2=' + quote(':'.join(trackName2))])
            #core.paragraph(URL_PREFIX + '/hyper?' + urlOptions)
            core.styleInfoBegin(styleClass='break-word')
            core.paragraph(urlForTrackAutoSelection)
            core.styleInfoEnd()

        if revEngBatchLine not in [None, '']:
            core.divider()
            core.header('CORRESPONDING BATCH COMMAND LINE')
            #if any(ExternalTrackManager.isRedirectOrExternalTrack(tn) for tn in [trackName1, trackName2]):
            #core.paragraph('Batch-run line not available with tracks from history')
            #else:
            core.styleInfoBegin(styleClass='break-word')
            core.paragraph(revEngBatchLine)
            core.styleInfoEnd()

        core.divider()
        core.header('REFERENCES')
        core.paragraph(
            'The HyperBrowser system is described in:<br>"Sandve et al., <a href="http://genomebiology.com/2010/11/12/R121/">The Genomic HyperBrowser: inferential genomics at the sequence level</a>, Genome Biol. 2010;11(12):R121'
        )
        from gold.statistic.RandomizationManagerStat import RandomizationManagerStat
        if statClass is not None and RandomizationManagerStat.getMcSamplingScheme(
                statClass.keywords) == 'MCFDR':
            core.paragraph('The p-values of this analysis were computed using the MCFDR scheme for Monte Carlo based p-value computation'+\
                           ', described in:<br>Sandve et al., <a href="http://bioinformatics.oxfordjournals.org/content/early/2011/10/13/bioinformatics.btr568.long">Sequential Monte Carlo multiple testing</a>, Bioinformatics 2011')

#        description = \
#'''
#Run descriptions will be introduced in the next version of HB. <br>
#Below is an example run description, which is a static text unconnected to your choices. The purpose is to get feedback from you on what this should look like:<br>
#Track1 (refseg:genes): Unmarked points (converted from unmarked segments, taking midpoints)<br>
#Track2 (DNA melting:meltmap): Function<br>
#Bins: Chr1, divided into bins of 10 megabases<br>
#Question: Are track1-points occurring with different frequency inside track2-segment than outside?<br>
#Analysis:<br>
#The main result is a p-value resulting from a statistical test connected to the question.<br>
#The null-hypothesis assumes that the track1-points are randomly distributed according to a poisson-distribution, with the same number of points as in the original data. Track2-segment are assumed fixed as they are in the original data. This can be answered by a binomial test. The alternative hypothesis is then that the count of points inside segments has resulted from a different distribution of points, where the points are then either distributed more or less inside segments versus outside. See the note on this question in the user guide for further info.<br>
#'''
        return str(core)
Esempio n. 7
0
    def getRevEngBatchLine(analysisDef, trackNames, cleanedTrackNames, regSpec,
                           binSpec, genome, **kwArgs):
        #analysisDef is assumed to be unquoted

        #if this is to work, must check explicitly against special keywords  in regSpec (or check that regSpec is a valid region that is to have region..)...
        #if not genome in regSpec:
        #    regSpec = genome+':'+regSpec
        try:
            if DebugConfig.VERBOSE:
                logMessage('getting RevEngBatchLine:')
            #analysisDef =analysisDef.replace('%20PointCountInSegsPvalStat%2C','') #REMOVE
            #print 'NOWAG: ',analysisDef

            analysis = Analysis(analysisDef, genome, cleanedTrackNames[0],
                                cleanedTrackNames[1], **kwArgs)

            #assert unquote(regSpec) == regSpec
            assert unquote(
                binSpec
            ) == binSpec  #To assure that unquote can be safely applied to binSpec without any consequences (we don't want to always quote, but still want the possibility to use quoted history track names)
            quotedTrackName1 = (':'.join(
                [quote(x, safe='') for x in trackNames[0]]))
            quotedTrackName2 = (':'.join([
                quote(x, safe='') for x in trackNames[1]
            ])) if trackNames[1] is not None else 'None'
            intensityChoice = analysis.getChoice('trackNameIntensity')
            if intensityChoice:
                quotedIntensityTrackName = quote(intensityChoice, safe='^|')
                analysis.changeChoices('trackNameIntensity',
                                       [(quotedIntensityTrackName, ) * 2])

            stat = analysis.getStat()
            if stat is None:
                return 'No corr batch line, as no valid statistic was found.. '
            #print 'CAME HERE'
            statClassName = stat.__name__
            #fixme: Add space, but this is not checked in batchrunner...
            params = ','.join(['='.join(choicePair) for choicePair in analysis.getAllChoices(filterByActivation=True).items() \
                                 if choicePair[0] not in ['H0','H1_more','H1_less','H1_different','H1_ha1','H1_ha2','H1_ha3','H1_ha4','H1_ha5'] ])
            statText = statClassName + '(' + params + ')'

            batchElements = [
                genome, regSpec, binSpec, quotedTrackName1, quotedTrackName2,
                statText
            ]
            #batchElements = [el.replace(BATCH_COL_SEPARATOR, '\\' + BATCH_COL_SEPARATOR) for el in batchElements]
            #batchElements = [quote(el, safe='') for el in batchElements]
            oneLineBatch = BATCH_COL_SEPARATOR.join(batchElements)

            #return oneLineBatch
            #Under construction...:
            from collections import OrderedDict
            #batchVariables = OrderedDict([('@GENOME',genome), ('@REGION',regSpec), ('@BINNING',binSpec), ('@TN1',tn1), ('@TN2',tn2), ('@ANALYSIS',statText)])
            batchVariables = OrderedDict([('@REGION', regSpec),
                                          ('@BINNING', binSpec),
                                          ('@TN1', quotedTrackName1),
                                          ('@TN2', quotedTrackName2),
                                          ('@ANALYSIS', statText)])
            batchComposition = BATCH_COL_SEPARATOR.join([genome] +
                                                        batchVariables.keys())
            fullBatchList = [
                '='.join(assignment) for assignment in batchVariables.items()
            ] + [batchComposition]
            fullBatch = '<br>'.join(fullBatchList)

            batchLinkDef = '<a href="%s/hyper?mako=generictool&tool_id=hb_batch_run_tool&command=%s&dbkey=%s">%s</a>'
            oneLineBatchLink = batchLinkDef % (URL_PREFIX, quote(oneLineBatch),
                                               genome, 'single line version')
            fullBatchLink = batchLinkDef % (URL_PREFIX,
                                            quote('\n'.join(fullBatchList)),
                                            genome, 'variable based version')

            #return oneLineBatch + '<br><br>or corresponding spec using variable assignment:<br><br>' + fullBatch + '<br><br>Execute batchline in ' \
            #+ oneLineBatchLink + ' / ' + fullBatchLink
            return oneLineBatch + '<br><br>Execute batchline in ' + oneLineBatchLink + ' / ' + fullBatchLink

        except Exception, e:
            #raise
            logException(e, logging.WARNING,
                         'Could not generate corresponding batch line: ')
            #if DebugConfig.VERBOSE:
            logMessage('analysis, genome, trackName1, trackName2: \n' +
                       str([analysis, genome, trackNames[0], trackNames[1]]))
            return 'Warning: Could not generate corresponding batch line.'
Esempio n. 8
0
class AnalysisDefJob(StatJob):
    '''
    @takes(AnalysisDefJob, str, list, list, UserBinSource)
    @returns Results
    '''
    def __init__(self, analysisDef, trackName1, trackName2, userBinSource,
                 genome=None, galaxyFn=None, *args, **kwArgs):
        from gold.description.Analysis import Analysis

        #  to be removed later.. Just for convenience with development now..
        self._analysisDef = analysisDef
        #  self._trackName1 = trackName1
        #  self._trackName2 = trackName2
        
        if genome is None:
            genome = userBinSource.genome
            
        self._galaxyFn = galaxyFn
            
        self._analysis = Analysis(analysisDef, genome, trackName1, trackName2)
        self._setRandomSeedIfNeeded()
            
        track, track2 = self._analysis.getTracks()
        StatJob.__init__(self, userBinSource, track, track2,
                         self._analysis.getStat(), *args, **kwArgs)

    def _setRandomSeedIfNeeded(self):
        from gold.util.RandomUtil import getRandomSeed
        randSeedChoice = self._analysis.getChoice('randomSeed')
        if randSeedChoice == 'Random':
            self._analysis.changeChoices('randomSeed', [(str(getRandomSeed()),)*2])
    
    def run(self, printProgress=PRINT_PROGRESS):
        '''
        Runs the statistic specified in self._analysis (from analysisDef) and returns an object of class Result
        
        '''
        #Should be there for batch runs.. Should never happen from GUI..
        if self._statClass == None:
            self._handleMissingStat()
            return None

        if DebugConfig.USE_PROFILING:
            from gold.util.Profiler import Profiler
            profiler = Profiler()
            resDict = {}
            profiler.run('resDict[0] = StatJob.run(self, printProgress=printProgress)', globals(), locals())
            res = resDict[0]
        else:
            res = StatJob.run(self, printProgress=printProgress)
        
        res.setAnalysis(self._analysis)
        res.setAnalysisText(str(self._analysis))
        
        ResultsMemoizer.flushStoredResults()
        
        if DebugConfig.USE_PROFILING:
            profiler.printStats()
            if DebugConfig.USE_CALLGRAPH and self._galaxyFn:
                profiler.printLinkToCallGraph(['profile_AnalysisDefJob'], self._galaxyFn)
        
        return res

    def _handleMissingStat(self):
        from gold.application.LogSetup import logMessage, logging
        from gold.description.RunDescription import RunDescription
        import gold.description.Analysis as AnalysisModule
        #AnalysisModule.VERBOSE = True
        msg = 'Started run with invalid statistic... Please run with debug mode set to "Debug by raising hidden ' \
              'exceptions" to see underlying problem. ' \
              'Def: ' + self._analysisDef
                    #+ ', Run description: ' + \
                    #RunDescription.getRevEngBatchLine( self._trackName1, self._trackName2, self._analysisDef, \
                                                      #'Not Available', 'Not Available', self._userBinSource.genome)
        logMessage(msg, level=logging.ERROR)
        raise Exception(msg)
Esempio n. 9
0
class AnalysisDefJob(StatJob):
    #@takes(AnalysisDefJob, str, list, list, UserBinSource)
    #@returns Results
    def __init__(self, analysisDef, trackName1, trackName2, userBinSource, genome=None, *args, **kwArgs):        
        from gold.description.Analysis import Analysis
    
        #to be removed later.. Just for convenience with development now.. 
        self._analysisDef = analysisDef
        #self._trackName1 = trackName1
        #self._trackName2 = trackName2
        
        if genome is None:
            genome = userBinSource.genome
            
        self._analysis = Analysis(analysisDef, genome, trackName1, trackName2)
        self._setRandomSeedIfNeeded()
            
        track, track2 = self._analysis.getTracks()
        StatJob.__init__(self, userBinSource, track, track2, self._analysis.getStat(), *args, **kwArgs)
    
    def _setRandomSeedIfNeeded(self):
        from gold.util.RandomUtil import getRandomSeed
        randSeedChoice = self._analysis.getChoice('randomSeed')
        if randSeedChoice == 'Random':
            self._analysis.changeChoices('randomSeed', [(str(getRandomSeed()),)*2])
    
    def run(self, printProgress=PRINT_PROGRESS):
        '''
        Runs the statistic specified in self._analysis (from analysisDef) and returns an object of class Result
        
        '''
        #Should be there for batch runs.. Should never happen from GUI..
        if self._statClass == None:
            self._handleMissingStat()
            return None

        if USE_PROFILING:
            profiler = Profiler()
            resDict = {}
            profiler.run('resDict[0] = StatJob.run(self, printProgress=printProgress)', globals(), locals())
            res = resDict[0]
        else:
            res = StatJob.run(self, printProgress=printProgress)
        res.setAnalysis(self._analysis)
        res.setAnalysisText(str(self._analysis))
        
        ResultsMemoizer.flushStoredResults()
        if USE_PROFILING:
            profiler.printStats()
        
        return res

    def _handleMissingStat(self):
        from gold.application.LogSetup import logMessage, logging
        from gold.description.RunDescription import RunDescription
        import gold.description.Analysis as AnalysisModule
        #AnalysisModule.VERBOSE = True
        msg = 'Started run with invalid statistic... Def: ' + self._analysisDef
                    #+ ', Run description: ' + \
                    #RunDescription.getRevEngBatchLine( self._trackName1, self._trackName2, self._analysisDef, \
                                                      #'Not Available', 'Not Available', self._userBinSource.genome)
        logMessage(msg, level=logging.ERROR)
        raise Exception(msg)
Esempio n. 10
0
    def getRunDescription(trackName1, trackName2, trackNameIntensity, analysisDef, ubSource, revEngBatchLine, \
                          urlForTrackAutoSelection, manualSeed, **kwArgs):
        genome = ubSource.genome
        core = HtmlCore()

        analysis = Analysis(analysisDef, genome, trackName1, trackName2, **kwArgs)
        
        core.header('GENOME')
        core.append(GenomeInfo(genome).mainInfo(printEmpty=False))
        core.divider()
                
        formatChoices = analysis.getFormatConverterChoicesAsText().items()
        tr1FormatChoice, tr2FormatChoice = formatChoices if len(formatChoices) == 2 else (None, None) 
        
        first = True
        for tn,label,formatChoice in zip([trackName1,trackName2,trackNameIntensity], \
                                         ['TRACK 1','TRACK 2','INTENSITY TRACK'], \
                                         [tr1FormatChoice,tr2FormatChoice,None]):
            if tn in [None, []]:
                continue
            
            if not first:
                core.divider()

            core.header(label)
            trackInfo = TrackInfo(genome, tn)
            trackText = ''
            if ExternalTrackManager.isHistoryTrack(tn):
                assert len(tn)>=4, 'Length of external track name < 4: %s' % str(tn)
                core.descriptionLine('Name', ExternalTrackManager.extractNameFromHistoryTN(tn) + ' (from history)' + os.linesep)
            else:
                core.descriptionLine('Name', ':'.join(tn) + os.linesep)
            core.append(trackInfo.mainInfo(printEmpty=False))

            if formatChoice is not None:
                core.descriptionLine('Treated as', formatChoice[1])
            
            first = False
        
        core.divider()
        core.header('ANALYSIS')
        core.paragraph( ''.join(str(analysis).split(':')[1:]) )

        first = True
        for label,choice in analysis.getInterfaceChoicesAsText().items():
            if first:
                core.divider()
                core.header('OPTIONS')
            
            if manualSeed is not None and label == 'Random seed' and choice == 'Random':
                choice = str(manualSeed)
                
            core.descriptionLine(label, choice)
            first = False
            
        h0 = analysis.getH0()
        if h0 is not None:
            core.divider()
            core.header('NULL HYPOTHESIS')
            core.paragraph(h0)
            
        h1 = analysis.getH1()
        if h1 is not None:
            core.divider()
            core.header('ALTERNATIVE HYPOTHESIS')
            core.paragraph(h1)
            
        core.divider()
        core.header('ANALYSIS REGIONS')
        if hasattr(ubSource, 'description'):
            core.paragraph(ubSource.description)
            
        core.divider()
        core.header('SOLUTION')

        statClass = analysis.getStat()
        #One alternative is to put getDescription in MagicStatFactory-hierarchy as class-method, and get real class behind partial-object.
        #if isinstance(statClass, functools.partial):
            #statClass = statClass.func
        #core.paragraph( statClass.getDescription() )

        #Chosen alternative is to Instantiate an object, which will automatically give object of real class..
        #and then use the following two lines, which will get class in Statistic-hierarchy instead of MagicStatFactory-hierarchy ..
        try:
            reg = ubSource.__iter__().next()
        except:
            core.paragraph('Solution not relevant, as there are no specified analysis regions..')
        else:
            track1, track2 = analysis.getTracks()
            if statClass is None:
                core.paragraph('Solution not available, due to currently invalid analysis')
                logMessage('Solution not available, with params: ' + str([trackName1, trackName2, analysisDef]), level=logging.WARN )
            else:
                statObj = statClass(reg,track1, track2)
                statDescr = statObj.getDescription()
                replPat = '<a href=' + os.sep.join([STATIC_REL_PATH,'notes','stats','']) + r'\1>note</a>'
                statDescr = re.sub('<note>(.*)</note>', replPat, statDescr)
        
                core.paragraph( statDescr )

        core.divider()
        core.header('TIME OF ANALYSIS')
        core.paragraph('Analysis initiated at time: ' + str( datetime.datetime.now() ) )
        
        if urlForTrackAutoSelection not in [None, '']:
            core.divider()
            core.header('URL FOR TRACK AUTOSELECTION')
            #urlOptions = '&'.join(['track1=' + quote(':'.join(trackName1)), 'track2=' + quote(':'.join(trackName2))])
            #core.paragraph(URL_PREFIX + '/hyper?' + urlOptions)
            core.styleInfoBegin(styleClass='break-word')
            core.paragraph(urlForTrackAutoSelection)
            core.styleInfoEnd()
            
        if revEngBatchLine not in [None, '']:
            core.divider()
            core.header('CORRESPONDING BATCH-RUN LINE')
            #if any(ExternalTrackManager.isRedirectOrExternalTrack(tn) for tn in [trackName1, trackName2]):
                #core.paragraph('Batch-run line not available with tracks from history')
            #else:
            core.styleInfoBegin(styleClass='break-word')
            core.paragraph(revEngBatchLine)
            core.styleInfoEnd()

        core.divider()
        core.header('REFERENCES')
        core.paragraph('The HyperBrowser system is described in:<br>"Sandve et al., <a href="http://genomebiology.com/2010/11/12/R121/">The Genomic HyperBrowser: inferential genomics at the sequence level</a>, Genome Biol. 2010;11(12):R121')
        from gold.statistic.RandomizationManagerStat import RandomizationManagerStat
        if statClass is not None and RandomizationManagerStat.getMcSamplingScheme(statClass.keywords) == 'MCFDR':
            core.paragraph('The p-values of this analysis were computed using the MCFDR scheme for Monte Carlo based p-value computation'+\
                           ', described in:<br>Sandve et al., <a href="http://bioinformatics.oxfordjournals.org/content/early/2011/10/13/bioinformatics.btr568.long">Sequential Monte Carlo multiple testing</a>, Bioinformatics 2011')
        
#        description = \
#'''
#Run descriptions will be introduced in the next version of HB. <br>
#Below is an example run description, which is a static text unconnected to your choices. The purpose is to get feedback from you on what this should look like:<br>
#Track1 (refseg:genes): Unmarked points (converted from unmarked segments, taking midpoints)<br>
#Track2 (DNA melting:meltmap): Function<br>
#Bins: Chr1, divided into bins of 10 megabases<br>
#Question: Are track1-points occurring with different frequency inside track2-segment than outside?<br>
#Analysis:<br>
#The main result is a p-value resulting from a statistical test connected to the question.<br>
#The null-hypothesis assumes that the track1-points are randomly distributed according to a poisson-distribution, with the same number of points as in the original data. Track2-segment are assumed fixed as they are in the original data. This can be answered by a binomial test. The alternative hypothesis is then that the count of points inside segments has resulted from a different distribution of points, where the points are then either distributed more or less inside segments versus outside. See the note on this question in the user guide for further info.<br>
#'''
        return str(core)