PYTHON   18

course py

Guest on 16th June 2022 01:27:31 AM

  1. #! /usr/bin/python
  2.  
  3. from xml.dom import minidom, Node
  4. from reportlab.graphics import renderPDF
  5.  
  6. from reportlab.lib import colors
  7. from reportlab.graphics.shapes import *
  8. from reportlab.lib.units import inch
  9. from reportlab.pdfgen import canvas
  10. from reportlab.lib.pagesizes import letter,  landscape
  11.  
  12. import sys
  13. import re
  14.  
  15. VERBOSE = 0  # print out diagnostic info?
  16.  
  17. #use to fill in blocks of time in the 'occupied' dictionary
  18. bitmask = [2**k-1 for k in range(0,109)]
  19.  
  20. xwidth = 1.3*inch
  21. xleft = (8.5*inch - 5*xwidth)/2
  22. yincr = 0.15*inch
  23. yincr8 = 0.1*inch
  24. xincr = 0.02*inch
  25. cinq = 6  # 5 minutes; 1 hour = 12* cinq = 1 inch
  26. xincr0 = 0
  27.  
  28.  
  29. def get_data(xmltree,tagname):
  30.         tag = xmltree.getElementsByTagName(tagname)
  31.         try:
  32.                 return tag[0].childNodes[0].data.strip()
  33.         except:
  34.                 return None
  35.  
  36. def setup(semester,d):         
  37.        
  38.         d.setPageSize(letter)
  39.         d.setFillColor(colors.navy)
  40.         d.setFont("Helvetica",18)
  41.         d.drawString(0.5*inch, 10*inch,"Statistics course times for " + semester)
  42.  
  43.         d.setFont("Helvetica", 9)
  44.        
  45.         d.setStrokeColor(colors.pink)  
  46.         xgrid = [xleft+xwidth*x for x in range(0,6)]
  47.         ygrid = [(0.5 +y)*inch for y in range(0,10)]
  48.         d.grid(xgrid,ygrid)
  49.        
  50.         d.setFont("Helvetica",9)
  51.         d.translate(xleft,0.5*inch)  # new origin at SW corner of grid
  52.        
  53.         # write hours 9:00 to 6:00 in both margins
  54.         i = 0
  55.         while i < 10:
  56.                 j = 6 - i
  57.                 if j < 1:
  58.                         j += 12
  59.                 time = str(j) +':00'
  60.                 d.drawRightString(-0.1*inch, i*inch - 5, time)
  61.                 d.drawString(5.1*xwidth, i*inch - 5, time)
  62.                 i += 1
  63.        
  64.         #write days of week
  65.         weekdays = ['Monday','Tuesday','Wednesday','Thursday','Friday']
  66.         i = 0
  67.         while i < 5:
  68.                 d.drawCentredString( (i+0.5)*xwidth,9.1*inch,weekdays[i])
  69.                 i += 1
  70.  
  71. def tabulate(semester='FALL'):
  72.         d.setFont("Times-Roman",9)
  73.         global occupied
  74. # Bits will show which of 9x12 time slots are occupied.
  75. # Initally empty for each day.
  76.         occupied = dict(Mon=0,Tue=0,Wed=0,Thu=0,Fri=0) 
  77.  
  78.         unscheduled = []
  79.        
  80.         for x in courses:
  81.                 sem = get_data(x,'semester')
  82.                 if not re.search(semester,sem) and not re.search('WHOLE',sem):
  83.                         if VERBOSE: print "skip semester =\t" + sem
  84.                         continue
  85.                        
  86.                 id = get_data(x,'id')
  87.                 if not id:
  88.                         if VERBOSE: print "no id\n\n"
  89.                         continue
  90.                 else:
  91.                         if VERBOSE: print "\n\nid = \t" + id
  92.                 room = get_data(x,'classroom')
  93.                 name = get_data(x,'name')
  94.                 if room and len(re.findall('24 H',room)) > 0:
  95.                         room = '24 HH'
  96.                
  97.                 if VERBOSE: print "name = \t" + name
  98.  
  99.                 time =  get_data(x,'time')
  100.                 if not re.search('\d',time):
  101.                         if VERBOSE: print "bad time = \t" + time
  102.                         unscheduled.append(id + ": " + name)
  103.                         continue
  104.                 times =  time.split(";") # needed for Stat 625
  105.                 for time in times:             
  106.                         days = re.findall('Mon|Tue|Wed|Thu|Fri',time)
  107.                         hours = re.findall('\d\d?:\d\d',time)
  108.                         if len(hours) != 2:
  109.                                 print "Need from and to:\t" + str(hours)
  110.                                 continue
  111.                         if VERBOSE: print "time = \t" + time
  112.                         if VERBOSE: print "hours = \t" + str(hours)
  113.                         for day in days:
  114.                                 draw_time_block(day,hours,id,room)                     
  115.        
  116.         # print id and names of courses without set times
  117.         d.setFont("Times-Roman",8)
  118.         xx = 4*inch
  119.         yy = 10.2*inch
  120.        
  121.         d.drawString(xx, yy,"Unscheduled courses: ")
  122.         for c in unscheduled:
  123.                 yy -= yincr8
  124.                 d.drawString(xx, yy,c) 
  125.  
  126.         d.save()
  127.                                        
  128. def draw_time_block(day,hours,id,room):
  129.         """ Draws the time blocks for each class over the grid."""
  130.         wdays = dict(Mon=0,Tue=1,Wed=2,Thu=3,Fri=4)
  131.        
  132.         if VERBOSE:
  133.                 print "d_t_b:\n" + day + "\n" + str(hours) + "\n" + id + "\n" + str(room)  + "\n\n"
  134.         X = float(wdays[day])  # numerical location for day
  135.         Time = []
  136.         for hhmm in hours:
  137.                 tt = hhmm.split(':')
  138.                 hh = int(tt[0])
  139.                 mm = int(tt[1])
  140.                 if hh < 7:
  141.                         hh += 12
  142.                 Time.append( (18-hh)*12 - mm/5 ) # multiples of 5 min before 6PM
  143.                
  144.         if len(Time) !=2:
  145.                 if VERBOSE: print "bad times\t" + str(Time) + "\n"
  146.                 return
  147.         # Time[0] = start time, in multiples of cinq before 6PM
  148.         # Time[1] = end time
  149.         yy = Time[1]*cinq
  150.         dy = (Time[0]- Time[1]) * cinq
  151.         xx = X* xwidth  + xincr0
  152.         dx = 0.5 * xwidth
  153.  
  154.         # mark time blocks as occupied
  155.         mask = bitmask[Time[0]] ^ bitmask[Time[1]]
  156. #       print "mask =\t" + str(struct.pack(">L",mask)) + "\n"
  157.         d.setStrokeColor(colors.maroon)
  158.         if occupied[day] &  mask:
  159.                 if VERBOSE: print "Overlap with occupied time"
  160. #               d.setStrokeColor(colors.green)
  161.                 xx += xwidth*0.5
  162.         else:
  163.                 if VERBOSE: print "Unoccupied time"
  164. #               d.setStrokeColor(colors.maroon)
  165.                 occupied[day]  = occupied[day] | mask
  166. #       d.setStrokeColor(maroon)
  167.         if room and re.findall('24 H',room):
  168.                 d.setFillColor(colors.yellow)
  169.         else:
  170.                 d.setFillColor(colors.wheat)
  171.        
  172.         d.rect(xx,yy,dx,dy,fill=1)
  173.        
  174.         # write course time, course id, and place inside rectangle
  175.         d.setFillColor(colors.navy)
  176.         yy = Time[0]*cinq - yincr
  177.         d.drawString(xx+xincr,yy,"-".join(hours))
  178.         yy -= yincr
  179.         d.drawString(xx+xincr,yy,id)
  180.         if room:
  181.                 room = " ".join(re.split('\s+',room)[0:2])  # first two words
  182.                 yy -= yincr
  183.                 d.drawString(xx+xincr,yy,room)
  184.  
  185.  
  186. ##########
  187.        
  188. try:
  189.         directory = sys.argv[1]
  190.         infile = directory + "/courses" + directory + ".xml"
  191. except IndexError:
  192.         print "Usage:\t python course.py YYYY-YY"
  193.         print "Program reads from YYYY-YY/coursesYYYY-YY.xml"
  194. else:
  195.         outfile = infile.replace('.xml','_table.pdf')
  196.         print "Reading from " + infile + "\nWriting to " + outfile + "\n"
  197.         #file = 'courses2009-10.xml'
  198.         xmldoc = minidom.parse(infile)
  199.         semesters = get_data(xmldoc,'year').split('/')
  200.         courses = xmldoc.getElementsByTagName('course')
  201.         d = canvas.Canvas(outfile)
  202.        
  203.         # Do it:                       
  204.         setup(semesters[0],d)          
  205.         tabulate('FALL')
  206.         setup(semesters[1],d)
  207.         tabulate('SPRING')

Raw Paste


Login or Register to edit or fork this paste. It's free.