Exemple #1
0
    def __init__(self, filename, semester = None):
        super(SemesterSummary, self).__init__(filename)

        # save off original table style
        self.tableStyleNoSpan = self.tableStyle

        # redefine the table sytle to include a span
        self.tableStyle = TableStyle([
            ('SPAN', (0, 0), (-1,0)),
            ('TOPPADDING', (0, 0), (-1, -1), 0),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 0),
            ('LINEABOVE', (0, 1), (-1, 1), 1, colors.black),
            ('BOX', (0, 0), (-1, -1), 1, colors.black),
        ])
        
        self.semester = semester

        # In order to calculate the pressures for the right semester
        # we need to tell this class that we are a few days before
        # this semester starts:
        s = DSSSemester.objects.get(semester = semester)
        today = (s.start() - timedelta(days = 10))
        self.lst = LstPressures(today = today)

        self.title = 'Semester Summary'
Exemple #2
0
    def __init__(self, filename):
        super(LstPressureReport, self).__init__(filename, orientation="landscape", topMargin=50)

        # make first style sheet font a little smaller
        self.styleSheet.fontSize = 6

        # a second style sheet for headers
        self.styleSheet2 = getSampleStyleSheet()["Normal"]
        self.styleSheet2.fontSize = 8

        # redefine table style to include an inner grid
        self.tableStyle = TableStyle(
            [
                ("TOPPADDING", (0, 0), (-1, -1), 0),
                ("BOTTOMPADDING", (0, 0), (-1, -1), 0),
                ("LINEABOVE", (0, 1), (-1, 1), 1, colors.black),
                ("INNERGRID", (0, 0), (-1, -1), 1, colors.black),
                ("BOX", (0, 0), (-1, -1), 1, colors.black),
            ]
        )

        self.lst = LstPressures()

        self.title = "LST Pressures"
        self.titleOffset = 0

        self.fltFrmt = "%5.2f"
Exemple #3
0
def lst_pressure(request, *args, **kws):

    # Are we calculating pressures for all sessions, or just
    # specific ones?
    filters = request.GET.get('filter', None)

    # TBF: even though it's possible to have the two project/session 
    # filters at once we will just use one of them
    ss = None
    carryOverUseNextSemester = True
    adjustWeatherBins = True
    showSponsors = False
    if filters is not None:
        filters = filters.replace('true', 'True')
        filters = filters.replace('false', 'False')
        filters = eval(filters)
        for filter in filters:
            prop = filter.get('property')
            value = filter.get('value')
            if prop == 'pcode':
                ss = Session.objects.filter(proposal__pcode = value)
            elif prop == 'session':
                ss = Session.objects.filter(id = value)
            elif prop == 'carryover':
                carryOverUseNextSemester = value == 'Next Semester Time'
            elif prop == 'adjust':
                adjustWeatherBins = value 
            elif prop == 'sponsor':
                showSponsors = value 
    #else:
    #    ss = None
        
    # calcualte the LST pressures    
    lst = LstPressures(carryOverUseNextSemester = carryOverUseNextSemester
                     , adjustWeatherBins = adjustWeatherBins
                     , hideSponsors = not showSponsors)
    pressure = lst.getPressures(sessions = ss)
    return HttpResponse(json.dumps({"success" : "ok"
                                  , "lst_pressure" : pressure
                                   })
                      , content_type = 'application/json')
Exemple #4
0
    def __init__(self):


        self.grades = ['A', 'B', 'C']

        # colors for grades A, B, C ...
        # TBF: these should match what the Ext JS 4 client is using
        self.reds   = ('#FF0000', '#FF8080', '#FFCCCC')
        self.blues  = ('#0000FF', '#8080FF', '#CCCCFF')
        self.greens = ('#00FF00', '#99FF99', '#e5FFe5')

        self.colors = {'excellent' : self.blues
                     , 'good' : self.greens
                     , 'poor' : self.reds
                      }

        self.lst = LstPressures()

        self.initPlots()
Exemple #5
0
class PlotLstPressures(object):

    def __init__(self):


        self.grades = ['A', 'B', 'C']

        # colors for grades A, B, C ...
        # TBF: these should match what the Ext JS 4 client is using
        self.reds   = ('#FF0000', '#FF8080', '#FFCCCC')
        self.blues  = ('#0000FF', '#8080FF', '#CCCCFF')
        self.greens = ('#00FF00', '#99FF99', '#e5FFe5')

        self.colors = {'excellent' : self.blues
                     , 'good' : self.greens
                     , 'poor' : self.reds
                      }

        self.lst = LstPressures()

        self.initPlots()

    def initPlots(self):

        self.figure = Figure(figsize=(10,6))
        self.axes = self.figure.add_axes([0.1, 0.1, 0.6, 0.8])
        self.canvas = None

    def plot(self
           , type
           , carryOverUseNextSemester = True
           , adjustWeatherBins = True
            ):

        # calculate stuff
        self.lst.carryOverUseNextSemester = carryOverUseNextSemester
        self.lst.adjustWeatherBins = adjustWeatherBins
        self.lst.getPressures()

        # what type of plot?
        if type == 'total':
            self.plotTotals()
        elif type == 'poor':    
            self.plotPoor()
        elif type == 'good':    
            self.plotGood()
        elif type == 'excellent':    
            self.plotExcellent()
        else:
            raise "unknown plot type", type

    def plotTotals(self):
    
        stacks = [
            {'data': self.lst.carryoverTotalPs
           , 'color': 'orange'
           , 'label': 'Carryover'}
           # grade A
          , {'data': self.lst.gradePs['A'].excellent
           , 'color': self.getColor('A', 'excellent')
           , 'label': 'Excellent A'}
          , {'data': self.lst.gradePs['A'].good
           , 'color': self.getColor('A', 'good')
           , 'label': 'Good A'}
          , {'data': self.lst.gradePs['A'].poor
           , 'color': self.getColor('A', 'poor')
           , 'label': 'Poor A'}
           # grade B
          , {'data': self.lst.gradePs['B'].excellent
           , 'color': self.getColor('B', 'excellent')
           , 'label': 'Excellent B'}
          , {'data': self.lst.gradePs['B'].good
           , 'color': self.getColor('B', 'good')
           , 'label': 'Good B'}
          , {'data': self.lst.gradePs['B'].poor
           , 'color': self.getColor('B', 'poor')
           , 'label': 'Poor B'}
           # grade C
          , {'data': self.lst.gradePs['C'].excellent
           , 'color': self.getColor('C', 'excellent')
           , 'label': 'Excellent C'}
          , {'data': self.lst.gradePs['C'].good
           , 'color': self.getColor('C', 'good')
           , 'label': 'Good C'}
          , {'data': self.lst.gradePs['C'].poor
           , 'color': self.getColor('C', 'poor')
           , 'label': 'Poor C'}
          , {'data': self.lst.requestedTotalPs
           , 'color': 'yellow'
           , 'label': 'Requested'}
                ]
       
        self.plotPressureData(stacks, "Total", "Total Pressure")
    
    def plotPoor(self):

        # TBF: There's a patter here we could use to shrink this
        stacks = [
            {'data': self.lst.carryoverPs.poor
           , 'color': 'orange'
           , 'label': 'Carryover Poor'}
          , {'data': self.lst.gradePs['A'].poor
           , 'color': self.getColor('A', 'poor')
           , 'label': 'Poor A'}
          , {'data': self.lst.gradePs['B'].poor
           , 'color': self.getColor('B', 'poor')
           , 'label': 'Poor B'}
          , {'data': self.lst.gradePs['C'].poor
           , 'color': self.getColor('C', 'poor')
           , 'label': 'Poor C'}
          , {'data': self.lst.requestedPs.poor
           , 'color': 'yellow'
           , 'label': 'Requested Poor'}
                ]
       
        self.plotPressureData(stacks, "Poor", "Poor")

    def plotGood(self):

        stacks = [
            {'data': self.lst.carryoverPs.good
           , 'color': 'orange'
           , 'label': 'Carryover Good'}
          , {'data': self.lst.gradePs['A'].good
           , 'color': self.getColor('A', 'good')
           , 'label': 'Good A'}
          , {'data': self.lst.gradePs['B'].good
           , 'color': self.getColor('B', 'good')
           , 'label': 'Good B'}
          , {'data': self.lst.gradePs['C'].good
           , 'color': self.getColor('C', 'good')
           , 'label': 'Good C'}
          , {'data': self.lst.requestedPs.good
           , 'color': 'yellow'
           , 'label': 'Requested Good'}
                ]
       
        self.plotPressureData(stacks, "Good", "Good")

    def plotExcellent(self):

        stacks = [
            {'data': self.lst.carryoverPs.excellent
           , 'color': 'orange'
           , 'label': 'Carryover Excellent'}
          , {'data': self.lst.gradePs['A'].excellent
           , 'color': self.getColor('A', 'excellent')
           , 'label': 'Excellent A'}
          , {'data': self.lst.gradePs['B'].excellent
           , 'color': self.getColor('B', 'excellent')
           , 'label': 'Excellent B'}
          , {'data': self.lst.gradePs['C'].excellent
           , 'color': self.getColor('C', 'excellent')
           , 'label': 'Excellent C'}
          , {'data': self.lst.requestedPs.excellent
           , 'color': 'yellow'
           , 'label': 'Requested Excellent'}
                ]
       
        self.plotPressureData(stacks, 'Excellent', "Excellent")

    def plotPressureData(self, stacks, availableType, title):

        # stack the pressures one on top of eachother
        ind = numpy.arange(self.lst.hrs)
        total = numpy.zeros(self.lst.hrs)
        for stack in stacks:
            data = stack['data']
            self.axes.bar(ind, data, color=stack['color'], label=stack['label'], bottom=total)
            total += data

        lgd = self.axes.legend(loc=(1.05, 0.4))

        # put the availablitly line across it all
        if availableType == 'Total':
            data = self.lst.weather.availabilityTotal
        else:    
            data = self.lst.weather.availability.getType(availableType)
        self.axes.plot(ind, data, color='black')

        # TBF: failed attempt at adding a table of the data
        #self.axes.add_table(self.createTable(ind, stacks))          

        self.axes.set_xlabel('LST')
        self.axes.set_ylabel('Pressure (Hrs)')
        self.figure.suptitle(title, fontsize=14)
        self.canvas = FigureCanvasAgg(self.figure)

    def createTable(self, ind, stacks):
        "Failed attempt at adding a table of the data"
        cells = []
        for stack in stacks:
            cells.append(["%5.2f" % d for d in stack['data']])
        colLabels = ["%d" % i for i in ind]

        return table(cellText=cells
                  , colLabels = colLabels
                  #, rowLabels=rowLabels
                  , cellLoc='center'
                  , loc='lower left')
            

    def getColor(self, grade, weatherType):
        return self.colors[weatherType][self.grades.index(grade)]

    def printPlot(self, filename):
        self.canvas.print_png(filename)
Exemple #6
0
class SemesterSummary(Report):

    """
    This class is responsible for producing a report on the overall
    summary of a given semester.
    """

    def __init__(self, filename, semester = None):
        super(SemesterSummary, self).__init__(filename)

        # save off original table style
        self.tableStyleNoSpan = self.tableStyle

        # redefine the table sytle to include a span
        self.tableStyle = TableStyle([
            ('SPAN', (0, 0), (-1,0)),
            ('TOPPADDING', (0, 0), (-1, -1), 0),
            ('BOTTOMPADDING', (0, 0), (-1, -1), 0),
            ('LINEABOVE', (0, 1), (-1, 1), 1, colors.black),
            ('BOX', (0, 0), (-1, -1), 1, colors.black),
        ])
        
        self.semester = semester

        # In order to calculate the pressures for the right semester
        # we need to tell this class that we are a few days before
        # this semester starts:
        s = DSSSemester.objects.get(semester = semester)
        today = (s.start() - timedelta(days = 10))
        self.lst = LstPressures(today = today)

        self.title = 'Semester Summary'

    def report(self, semester = None):

        if semester is not None:
            self.semester = semester

        # crunch the numbers we need for this report
        self.lst.getPressures()
        self.lst.getOriginalRequestedPressures()
        
        self.title = self.title if self.semester is None else \
                     self.title + " for Semester %s" % self.semester


        t0 = self.getIntroTable()
        t1 = self.getStartingHoursTable()
        t2 = self.getAvailableAllAstronomyTable()
        t3 = self.getAvailableNewAstronomyTableGradeA()
        t4 = self.getAvailableNewAstronomyTable()
        t5 = self.getTotalRequestedTable()

        b = self.getBreak()

        tables = [t0, b, t1, b, t2, b]
        for g in self.lst.grades: 
            tables.append(self.getBacklogTableForGrade(g))
            tables.append(b)

        tables.extend([t3, b, t4, b, t5])    

        # write the document to disk (or something)
        self.doc.build(tables
                    , onFirstPage = self.makeHeaderFooter
                    , onLaterPages = self.makeHeaderFooter)

    def getIntroTable(self):

        data = [[self.pg('Time Analysis for Semester %s' % self.semester, bold = True)
                ]
              , [self.pg('%s - %s' % (self.lst.timeRange))]
              , [self.pg('As of %s' % self.lst.published)]
               ]

        t = Table(data, colWidths = [300])

        t.setStyle(self.tableStyle)
        
        return t

    def getStartingHoursTable(self):

        hrsInSemester = (self.lst.weather.availability.total()
                       , self.lst.weather.availability.total(gc = True))
        hrsMaint      = (self.lst.maintenancePs.total()
                       , self.lst.maintenancePs.total(gc = True))
        hrsShutdown   = (self.lst.shutdownPs.total()
                       , self.lst.shutdownPs.total(gc = True))
        hrsTests      = (self.lst.testingPs.total()
                       , self.lst.testingPs.total(gc = True))

        data = [self.hrsPg('Hours in Semester', hrsInSemester, bold = True)
              , self.hrsPg('Maintenance Hours', hrsMaint)
              , self.hrsPg('Test, Comm, Calib Hours', hrsTests)
              , self.hrsPg('Shutdown Hours', hrsShutdown)
                ]

        t = Table(data, colWidths = [100, 100, 100])
        t.setStyle(self.tableStyleNoSpan)
        return t

    def getAvailableAllAstronomyTable(self):
        txt = 'Available for ALL Astronomy during %s' % self.semester
        return self.getAvailableTable(txt
                                    #, self.ta.astronomyAvailableHrs)
                                    , self.lst.postMaintAvailabilityPs)

    def getBacklogTableForGrade(self, grade):

        g = grade
        t = True
        hrsFixed = (self.lst.carryoverGradePs['fixed'][g].total()
                  , self.lst.carryoverGradePs['fixed'][g].total(gc = t))
        hrsTotal = (self.lst.carryoverGradePs['total'][g].total()
                  , self.lst.carryoverGradePs['total'][g].total(gc = t))

        data = [[self.pg('Group %s time' % grade, bold = True)]
               , self.hrsPg('Hours Total', hrsTotal)  
               , self.hrsPg('Fixed Hours', hrsFixed)
               ]

        r = 'rest'
        for w in self.lst.weatherTypes:
            w = w.lower()
            hrs = (self.lst.carryoverGradePs[r][g].total(type = w)
                 , self.lst.carryoverGradePs[r][g].total(type = w
                                                       , gc = t))
            label = 'Hours for %s' % self.lst.weatherMap[w]        
            data.append(self.hrsPg(label, hrs))

        t = Table(data, colWidths = [100, 100, 100])
        t.setStyle(self.tableStyle)
        return t

    def getAvailableHrs(self, available):
        "Reorganize our data."

        hrsTotal = (available.total(), available.total(gc = True))
        hrs = []
        for w in self.lst.weatherTypes:
            w = w.lower()
            hrs.append((available.total(type = w)
                      , available.total(type = w, gc = True)))

        return (hrsTotal, hrs[0], hrs[1], hrs[2])            
        
    def getAvailableTable(self, text, available):
        "Worker function for creating a table of available hours."
        hrsTotal, hrsLowFreq, hrsHiFreq1, hrsHiFreq2 = \
            self.getAvailableHrs(available)

        data = [[self.pg(text, bold = True)
                ]
              , self.hrsPg('Hours Total', hrsTotal)  
              , self.hrsPg('Hours for Low Freq', hrsLowFreq)
              , self.hrsPg('Hours for Hi Freq 1', hrsHiFreq1)
              , self.hrsPg('Hours for Hi Freq 2', hrsHiFreq2)
               ]

        t = Table(data, colWidths = [100, 100, 100])
        t.setStyle(self.tableStyle)
        return t

    def getAvailableNewAstronomyTableGradeA(self):
        txt = 'Available for NEW Astronomy during %s (Grade A Carry Over Only)' % self.semester
        return self.getAvailableTable(txt
            , self.lst.remainingFromGradeACarryoverPs)


    def getAvailableNewAstronomyTable(self):
        txt = 'Available for NEW Astronomy during %s (All Grades Carry Over)' % self.semester
        return self.getAvailableTable(txt
                                    , self.lst.remainingPs)

    def getTotalRequestedTable(self):
        txt = 'Originally Requested Astronomy for semester %s' % self.semester
        return self.getAvailableTable(txt
                                    , self.lst.originalRequestedPs)
        

    def hrsPg(self, text, hrs, bold = False):
        "This is common enough when reporting on hours"
        if bold:
            text =  "<b>%s</b>" % text
        return [self.pg(text) # label
              , self.pg("%5.2f" % hrs[0]) # total hrs
              , self.pg("GC[%5.2f]" % hrs[1]) # hrs in Gal. Center
               ]
Exemple #7
0
class LstPressureReport(Report):

    """
    This class is responsible for producing a report on the LST
    pressures for all the given sessions.  It is basically a tabular
    representation of what the plots show.
    """

    def __init__(self, filename):
        super(LstPressureReport, self).__init__(filename, orientation="landscape", topMargin=50)

        # make first style sheet font a little smaller
        self.styleSheet.fontSize = 6

        # a second style sheet for headers
        self.styleSheet2 = getSampleStyleSheet()["Normal"]
        self.styleSheet2.fontSize = 8

        # redefine table style to include an inner grid
        self.tableStyle = TableStyle(
            [
                ("TOPPADDING", (0, 0), (-1, -1), 0),
                ("BOTTOMPADDING", (0, 0), (-1, -1), 0),
                ("LINEABOVE", (0, 1), (-1, 1), 1, colors.black),
                ("INNERGRID", (0, 0), (-1, -1), 1, colors.black),
                ("BOX", (0, 0), (-1, -1), 1, colors.black),
            ]
        )

        self.lst = LstPressures()

        self.title = "LST Pressures"
        self.titleOffset = 0

        self.fltFrmt = "%5.2f"

    def report(
        self, sessions=None, debug=False, carryOverUseNextSemester=True, adjustWeatherBins=True, hideSponsors=True
    ):

        if sessions is not None:
            self.title += " for %s" % ",".join([s.name for s in sessions])
            self.titleOffset = 100 + len(self.title)

        # crunch the numbers
        self.lst.carryOverUseNextSemester = carryOverUseNextSemester
        self.lst.adjustWeatherBins = adjustWeatherBins
        self.lst.hideSponsors = hideSponsors
        self.lst.getPressures(sessions)

        # now mak'm pretty
        h1 = self.tableHeader("Totals:")
        t1 = self.createTotalsTable()

        h2 = self.tableHeader("Availability:")
        t2 = self.createAvailableTable()

        h3 = self.tableHeader("Carryover:")
        t3 = self.createCarryoverTable()

        h4 = self.tableHeader("Remaining:")
        t4 = self.createRemainingTable()

        h5 = self.tableHeader("Requested:")
        t5 = self.createRequestedTable()

        h6 = self.tableHeader("Allocated:")
        t6 = self.createAllocatedTable()

        b = self.getBreak()  # Paragraph('<br/>', self.styleSheet)

        elements = [h1, t1, h2, t2, h3, t3, h4, t4, h5, t5, h6, t6]  # , b  # , b  # , b  # , b

        # sponsors aren't really part of the 'debug section', yet we don't want
        # them there if they aren't needed: they start page two!
        if not hideSponsors:
            for s in self.lst.sponsors:
                hs = self.tableHeader("%s:" % s)
                ts = self.createSponsorTable(s)
                elements.extend([hs, ts, b])

        if debug:
            debugElements = self.createDebugElements()
            elements.extend(debugElements)

        # write the document to disk (or something)
        self.doc.build(elements, onFirstPage=self.makeHeaderFooter, onLaterPages=self.makeHeaderFooter)

    def createTotalsTable(self):
        "Simply one header row, and the row of total data"
        rows = [self.createLstRow(), self.createRow("Total", self.lst.totalPs, self.fltFrmt)]
        t = Table(rows, colWidths=[30] * self.lst.hrs)
        t.setStyle(self.tableStyle)
        return t

    def createRequestedTable(self):
        return self.createPressureTable(self.lst.requestedTotalPs, self.lst.requestedPs)

    def createCarryoverTable(self):
        return self.createPressureTable(self.lst.carryoverTotalPs, self.lst.carryoverPs)

    def createRemainingTable(self):
        return self.createPressureTable(self.lst.remainingTotalPs, self.lst.remainingPs)

    def createSponsorTable(self, sponsor):
        return self.createPressureTable(self.lst.sponsoredTotalPs[sponsor], self.lst.sponsoredPs[sponsor])

    def createAllocatedTable(self):

        # different from the other tables
        rows = [self.createLstRow(), self.createRow("Total", self.lst.newAstronomyTotalPs, self.fltFrmt)]
        for w in self.lst.weatherTypes:
            for g in self.lst.grades:
                # make sure our row lable fits
                if w == "Excellent":
                    label = "Ex_%s" % g
                else:
                    label = "%s_%s" % (w, g)
                rows.append(self.createRow(label, self.lst.gradePs[g].getType(w), self.fltFrmt))

        t = Table(rows, colWidths=[30] * self.lst.hrs)
        t.setStyle(self.tableStyle)
        return t

    def createPressureTable(self, totals, types):
        "Common pattern: display total, then break it down by weather type."
        rows = [self.createLstRow()]
        dataRows = [self.createRow("Total", totals, self.fltFrmt)]
        for w in self.lst.weatherTypes:
            row = self.createRow(self.cropWeatherLabel(w), types.getType(w), self.fltFrmt)
            dataRows.append(row)
        rows.extend(dataRows)

        t = Table(rows, colWidths=[30] * self.lst.hrs)
        t.setStyle(self.tableStyle)
        return t

    def createLstRow(self):
        "Every table begins with the LSTs 0-23"
        return self.createRow("LST", range(self.lst.hrs), "%d")

    def createAvailableTable(self):
        return self.createPressureTable(self.lst.weather.availabilityTotal, self.lst.weather.availability)

    def createRemainingTable(self):
        return self.createPressureTable(self.lst.remainingTotalPs, self.lst.remainingPs)

    def cropWeatherLabel(self, w):
        if w == "Excellent":
            return "Ex"
        else:
            return w

    def createRow(self, label, data, frmt):
        rows = [self.pg(label, bold=True)]
        dataRows = [self.pg(frmt % d) for d in data]
        rows.extend(dataRows)
        return rows

    def tableHeader(self, text):
        return Paragraph("<b>%s</b>" % text, self.styleSheet2)

    def getDataRow(self, title, data):
        row = [self.pg(title)]
        rowData = [self.pg("%5.2f" % d) for d in data]
        row.extend(rowData)
        return row

    def createDebugElements(self):

        els = [self.pg("Debug Info:", bold=True)]

        # how did we calculate pressures?
        method = "Next Semester Time" if self.lst.carryOverUseNextSemester else "Remaining Time"
        msg = "Calculated Carryover using " + method
        els.append(self.getBreak())
        els.append(self.pg(msg))
        msg = "Adjusted Weather Bins? " + str(self.lst.adjustWeatherBins)
        els.append(self.getBreak())
        els.append(self.pg(msg))

        # warnings ?
        valid, msgs = self.lst.checkPressures()
        if not valid:
            els.append(self.getBreak())
            els.append(self.pg("Accounting ERRORS:", bold=True))
            for msg in msgs:
                els.append(self.pg(msg))

        # details on changes
        els.append(self.getBreak())
        els.append(self.pg("Original Grade A Pressure before Adjustments", bold=True))
        els.append(self.createOriginalGradePsTable())
        els.append(self.getBreak())
        els.append(self.pg("Adjustments made to Grade A Pressures", bold=True))
        els.append(self.createChangesTable())

        # breakdown of pre-assigned time
        els.append(self.getBreak())
        els.append(self.pg("Maintenance Pressure", bold=True))
        els.append(self.createPressureTable(self.lst.maintenancePs.allTypes(), self.lst.maintenancePs))
        els.append(self.getBreak())
        els.append(self.pg("Shutdown Pressure", bold=True))
        els.append(self.createPressureTable(self.lst.shutdownPs.allTypes(), self.lst.shutdownPs))
        els.append(self.getBreak())
        els.append(self.pg("Testing Pressure", bold=True))
        els.append(self.createPressureTable(self.lst.testingPs.allTypes(), self.lst.testingPs))
        els.append(self.getBreak())

        # non traditional sessions
        if len(self.lst.badSessions) > 0:
            ss = self.createSessionElements("Session's without pressures (bad):", self.lst.badSessions)
            els.extend(ss)
        if len(self.lst.futureSessions) > 0:
            ss = self.createSessionElements("Session's for future semesters:", self.lst.futureSessions)
            els.extend(ss)
        if len(self.lst.semesterSessions) > 0:
            ss = self.createSessionElements("Session's using semester time:", self.lst.semesterSessions)
            els.extend(ss)

        # session details
        els.append(self.getBreak())
        els.append(self.pg("Session Details:", bold=True))
        data = [self.createLstRow()]
        for name in sorted(self.lst.pressuresBySession.keys()):
            cat, subcat, ps, total = self.lst.pressuresBySession[name]
            if subcat == "":
                label = "%s: (%s, %5.2f)" % (name, cat, total)
            else:
                label = "%s: (%s, %s, %5.2f)" % (name, cat, subcat, total)
            data.append(self.getDataRow(label, ps))
        widths = [120]
        widths.extend([25] * (self.lst.hrs - 1))
        t = Table(data, colWidths=widths)
        t.setStyle(self.tableStyle)
        els.append(t)

        return els

    def createSessionElements(self, header, sessions):
        "Print out a list of sessions"
        els = [self.getBreak()]
        els.append(self.pg(header, bold=True))
        for s in sessions:
            els.append(self.pg(s.__str__()))
        return els

    def createOriginalGradePsTable(self):

        # different from the other tables
        rows = [self.createLstRow()]
        for w in self.lst.weatherTypes:
            if w == "Excellent":
                label = "Ex_A"
            else:
                label = "%s_A" % w
            row = self.createRow(label, self.lst.originalGradePs["A"].getType(w), self.fltFrmt)
            rows.append(row)

        t = Table(rows, colWidths=[30] * self.lst.hrs)
        t.setStyle(self.tableStyle)
        return t

    def createChangesTable(self):

        # different from the other tables
        rows = [self.createLstRow()]
        for w in self.lst.weatherTypes:
            if w == "Excellent":
                label = "Ex_A"
            else:
                label = "%s_A" % w
            row = self.createRow(label, self.lst.changes.getType(w), self.fltFrmt)
            rows.append(row)

        t = Table(rows, colWidths=[30] * self.lst.hrs)
        t.setStyle(self.tableStyle)
        return t