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 __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 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')
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()
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)
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 ]
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