Skip to content

Commit

Permalink
State used for Term 3 2018
Browse files Browse the repository at this point in the history
  • Loading branch information
jiegillet committed Aug 1, 2019
1 parent df043db commit 6d971a6
Show file tree
Hide file tree
Showing 7 changed files with 286 additions and 162 deletions.
127 changes: 127 additions & 0 deletions Global Chart/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#!/usr/local/bin/python3
import pymysql
import collections
import os

def get_all_enrollments():
db = pymysql.connect(host="dbc01.oist.jp", # your host, usually localhost
user="gs_readonly", # your username
passwd=***REMOVED***, # your password
db="grad_school") # name of the database

# you must create a Cursor object. It will let
# you execute all the queries you need
cur = db.cursor()

# Use all the SQL you like
cur.execute("SELECT student_id, co.course_id \
FROM student_main s \
JOIN class_registration c ON s.id=c.student_main_id\
JOIN gsclass g ON g.id=c.gsclass_id\
JOIN course co ON co.id=g.course_id\
WHERE classification='OIST Student'\
ORDER BY preferred_n")

enrollment = collections.defaultdict(set)

for student, course in cur.fetchall():
enrollment[course].add(student)

db.close()
return enrollment

def get_term_courses(year):

db = pymysql.connect(host="dbc01.oist.jp", # your host, usually localhost
user="gs_readonly", # your username
passwd=***REMOVED***, # your password
db="grad_school") # name of the database

# you must create a Cursor object. It will let
# you execute all the queries you need
cur = db.cursor()

enrollments = []
for term in [1,2,3]:
cur.execute("SELECT co.course_id \
FROM gsclass g \
JOIN course co ON co.id=g.course_id\
WHERE class_id LIKE '{}_{}_%'\
AND co.course_id NOT IN (\"A406\",\"A407\",\"A408\", \
\"IND\",\"IWS\",\"SPT\") \
ORDER BY course_id".format(year, term))

enrollments.append(set(cur.fetchall()))

db.close()
return enrollments

def draw_chart(enrollment, courses, term):

courses = sorted([c[0] for c in courses])

chart_path = "courses_collisions_term_{}.tex".format(term)

title = "Student Overlap Chart for all Years and Terms"

width = 277/(len(courses)+1)
height = 180/(len(courses)+1)

# Writing LaTeX file
f = open(chart_path, 'w')
f.write("\\documentclass[landscape,a4paper]{article}\n"
"\\usepackage[dvipsnames, table]{xcolor}\n"
"\\usepackage{tikz, geometry}\n"
"\\newgeometry{margin=1cm}\n"
"\\begin{document}\n\n"
"\\centering\n"
"\\pagestyle{empty}\n\n")

# Title
f.write(title + "\n\\vspace{2mm}\n\n")
f.write("\\begin{tikzpicture}\n")

# General style
f.write("\n% Cell style\n")
f.write("\\tikzstyle{{cell}}=[draw, rectangle, minimum height={}mm, minimum width={}mm, anchor=north west]\n"
.format(height, width))

# Headers
f.write("\n% Courses - Vertical\n")
for i, course in enumerate(courses):
f.write("\\node[cell] at (0, {}mm) {{{}}}; \n"
.format(171-(i+1)*height, course))

f.write("\n% Courses - Horizontal\n")
for i, course in enumerate(courses):
f.write("\\node[cell] at ({}mm,171mm) {{{}}}; \n"
.format((i+1)*width, course))

# Overlap
f.write("\n% Overlap \n")
for i, courseA in enumerate(courses):
for j, courseB in enumerate(courses):
overlap = len(enrollment[courseA].intersection(enrollment[courseB]))
if i==j:
f.write("\\node[cell, fill=Gray] at ({}mm,{}mm) {{{}}}; \n"
.format((i+1)*width, 171-(i+1)*height, overlap))
elif overlap > 0:
f.write("\\node[cell, fill = red] at ({}mm,{}mm) {{{}}}; \n"
.format((i+1)*width, 171-(j+1)*height, overlap))
else:
f.write("\\node[cell] at ({}mm,{}mm) {{}}; \n"
.format((i+1)*width, 171-(j+1)*height))


f.write("\\end{tikzpicture}\n"
"\\end{document}")
f.close()

os.system("pdflatex -output-directory=. {}".format(chart_path))
os.system("rm *.aux *.log")

if __name__ == '__main__':
all_enrollment = get_all_enrollments()
term_courses = get_term_courses(2019)
for term, courses in enumerate(term_courses):
draw_chart(all_enrollment, courses, term + 1)
Empty file modified SQL/get_courses.sql
100644 → 100755
Empty file.
40 changes: 21 additions & 19 deletions Scheduler.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/usr/bin/env python3
import random as rd
import copy
import time
Expand All @@ -11,10 +12,9 @@
TO DO:
- teaching labs
- room preferences
- no students picks a course
'''

year = 2017
year = 2018
term = 3

timestamp = int(time.time())
Expand Down Expand Up @@ -171,16 +171,17 @@ def generate_timeslots(self):
# Lists each participants per course, prints a message when a course picked isn't in the list
def get_student_in_courses(self):
sic = { course:[] for course in self.courses }
nonav = []
nonav = set()
for id in self.students.keys():
for course in self.students[id][1:]:
if course not in self.courses.keys():
if course not in nonav:
print("\n{} not in the list of available courses".format(course))
nonav.append(course)
nonav.add(course)
else:
sic[course].append(id)

for course in nonav:
print("\n{} not in the list of available courses".format(course))

draw_chart.draw_chart(year, term, sic, output_path)

f = open(sic_path, 'w')
Expand All @@ -194,7 +195,7 @@ def get_student_in_courses(self):
# Checks if a timeslot is available
def free_slot(self, day, start, room, length, timeslots):
# Return true if all the consecutive chunks minute slots for the course are available
return all([([day, start + k * chunks, room] in timeslots) for k in range(length / chunks)])
return all([([day, start + k * chunks, room] in timeslots) for k in range(length // chunks)])

# Initializes a population of random schedules
def initialize_pop(self, size):
Expand Down Expand Up @@ -233,9 +234,9 @@ def random_creature(self):
else:
start = rd.choice(range(start_day, end_day, chunks))

room = rd.choice(self.rooms.keys())
room = rd.choice(list(self.rooms.keys()))

for k in range(length / chunks):
for k in range(length // chunks):
ts.remove([day, start + k * chunks, room])
# Structure: day, start time, stop time, room, course, session. Course is fixed.
p.append([day, start, start + length - chunks, room, course, session])
Expand Down Expand Up @@ -325,19 +326,19 @@ def breed_population(self, top_pop):
def print_schedule(self, schedule):
# Sort the schedule items by weekday and time
for p in sorted(schedule, key=lambda k: k[0] * 10000 + k[1]):
s = "{}, from {}:{:02d} to {}:{:02}, course {} ({}, {}) in {} (" \
.format(weekdays[p[0]], p[1] / 60, p[1] % 60, (p[2] + chunks) / 60, (p[2] + chunks) % 60
, p[4], self.courses[p[4]][0][0], self.courses[p[4]][0][1], p[3])
s += ", ".join([self.students[id][0] for id in self.student_in_courses.get(p[4])])
s += ")"
s = "{}, from {}:{:02d} to {}:{:02}, course {} ({}, {}) in {} ({})" \
.format(weekdays[p[0]], p[1] // 60, p[1] % 60, (p[2] + chunks) // 60, (p[2] + chunks) % 60
, p[4], self.courses[p[4]][0][0], self.courses[p[4]][0][1], p[3]
, ", ".join([self.students[id][0] for id in self.student_in_courses.get(p[4])]))
print(s)

def export_schedule(self, schedule):
f = open(schedule_path, "w")
f.write("Day,Start time,End time,Course ID,Room\n")
for p in sorted(schedule, key=lambda k: k[0] * 10000 + k[1]):
f.write("{},{}:{:02d},{}:{:02d},{},{}\n".format(weekdays[p[0]], p[1] / 60, p[1] % 60, (p[2] + chunks) / 60,
(p[2] + chunks) % 60, p[4], p[3]))
f.write("{},{}:{:02d},{}:{:02d},{},{}\n".format(weekdays[p[0]]
, p[1] // 60, p[1] % 60, (p[2] + chunks) // 60
, (p[2] + chunks) % 60, p[4], p[3]))
f.close()

# Importing schedule
Expand Down Expand Up @@ -367,7 +368,8 @@ def checkschedule(self):
# Time related
for time in range(start, stop + 1, chunks):
s = "\n{}, from {}:{:02d} to {}:{:02}, course {}" \
.format(weekdays[day], time / 60, time % 60, (time + chunks) / 60, (time + chunks) % 60, course)
.format(weekdays[day], time // 60, time % 60
, (time + chunks) // 60, (time + chunks) % 60, course)
if hToMin(12,0) <= time < hToMin(13,0): # Lunch time
warn += s + " happens during lunch"
if day == 3 and hToMin(16,0) <= time < hToMin(17,0): # Tea time
Expand All @@ -394,12 +396,12 @@ def checkschedule(self):


if __name__ == '__main__':
# mysql.get_students(input_path, year, term)
# mysql.get_students(input_path, year, term)
s = Schedule()
try:
schedule_path = sys.argv[1] # One argument: scheduled mofified by hand
s.import_schedule(schedule_path)
warning_path = schedule_path.replace("schedule","warnings").replace("csv","txt")
warning_path = schedule_path.replace("_schedule","_warnings").replace("csv","txt")
s.checkschedule()

except IndexError: # No arguments
Expand Down
57 changes: 9 additions & 48 deletions draw_chart.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#!/usr/local/bin/python3
import os

def draw_chart(year, term, student_in_courses, output_path):

chart_path = os.path.join(output_path, "{}_{}_courses_collisions.tex".format(year, term))
chart_path = os.path.join(output_path, "{}_{}_courses_collisions.tex"
.format(year, term))

sic = student_in_courses
courses = sorted(sic.keys())
Expand Down Expand Up @@ -30,15 +32,18 @@ def draw_chart(year, term, student_in_courses, output_path):
f.write("\\tikzstyle{{cell}}=[draw, rectangle, minimum height={}mm, minimum width={}mm, anchor=north west]\n"
.format(height, width))

# Courses
# Headers
f.write("\n% Courses - Vertical\n")
for i, course in enumerate(courses):
f.write("\\node[cell] at (0, {}mm) {{{}}}; \n".format(171-(i+1)*height, course))
f.write("\\node[cell] at (0, {}mm) {{{}}}; \n"
.format(171-(i+1)*height, course))

f.write("\n% Courses - Horizontal\n")
for i, course in enumerate(courses):
f.write("\\node[cell] at ({}mm,171mm) {{{}}}; \n".format((i+1)*width, course))
f.write("\\node[cell] at ({}mm,171mm) {{{}}}; \n"
.format((i+1)*width, course))

# Overlap
f.write("\n% Overlap \n")
for i, courseA in enumerate(courses):
for j, courseB in enumerate(courses):
Expand All @@ -54,50 +59,6 @@ def draw_chart(year, term, student_in_courses, output_path):
.format((i+1)*width, 171-(j+1)*height, overlap))




# # Grid
# f.write("\n% Grid\n")
# f.write("\\tikzstyle{grid}=[draw, rectangle, minimum height=171mm, anchor=north west]\n")
# pos = 12
# for i, day in enumerate(weekdays):
# for j in range(width[i]):
# f.write("\\node[grid, minimum width={}mm] at ({}mm,-9mm) {{ }}; \n"
# .format(cellWidth, pos))
# pos += cellWidth
# pos += 1
#
#
# # Hours
# f.write("\n% Hours\n")
# f.write("\\tikzstyle{hours}=[draw, rectangle, minimum height=19mm, minimum width=11mm, anchor=north west]\n")
# pos = -9
# for i in range(9,18):
# f.write("\\node[hours, label={{[shift={{(0,-6mm)}}]north:{}:00}}] at (0,{}mm) {{}}; \n".format(i,pos))
# pos -= 19

# # Schedule
# f.write("\n% Schedule\n")
# f.write("\\tikzstyle{{course}}=[draw, rectangle,anchor=north west,text centered,"
# "minimum width={}mm, text width={}mm]\n".format(cellWidth,0.82 *cellWidth))
# xpos=11
# for day in timeslots:
# xpos+=1
# for j in day:
# for day, start, stop, room, course in j:
# sizes={"x":xpos,
# "y":-9-171.0*(start-start_day)/(end_day-start_day),
# "height":171.0*(stop-start)/(end_day-start_day),
# "color":courses[course][2],
# "text":"{{\\bfseries \\color{{white}} \\sffamily \\tiny {}"\
# " ({})"\
# "\\\\ {} \\\\ {} \\\\ {}:{:02d}--{}:{:02d}}}"\
# .format(courses[course][0], course,
# courses[course][1], room, start/60, start%60,stop/60,stop%60)}
# f.write("\\node[course, minimum height={height}mm, fill={color}]" \
# " at ({x}mm,{y}mm) \n {{{text}}}; \n".format(**sizes))
# xpos += cellWidth

f.write("\\end{tikzpicture}\n"
"\\end{document}")
f.close()
Expand Down
Loading

0 comments on commit 6d971a6

Please sign in to comment.