In [1]:
from sessions import *
from venueordering import *
from pylatex_textboxes import *
from formatting_solver import *

In [2]:
import itertools as it
import pandas as pd
import datetime

In [36]:
df = pd.read_excel("con_data/items_01-02-2019.xlsx", )
df.loc[12,:]


Out[36]:
Title                                                 PowerPoint Roulette
Description             Otherwise known as "Here is my 10 minute Power...
Short Title                                                           NaN
Format                                                       Presentation
Duration                                                               30
Day                                                              Saturday
Time                                                                12:30
Room                                                             Reynolds
Venue                                                 St George’s College
Tracks                                                                NaN
Parent                                                                NaN
Participants            Alexis Hemsley,Jonathan Durnford,Matt Woods,Al...
Other Participants                                                    NaN
Notes for Organizers                                                  NaN
Notes for Speakers                                                    NaN
Name: 12, dtype: object

In [37]:
day2date = {
    "Saturday":datetime.date(2019,1,12),
    "Sunday":datetime.date(2019,1,13),
}

def load_grenadine_session(prog_item):
    title = prog_item['Title']
    print(title)
    id = prog_item.name
    
    date = day2date[prog_item['Day']]
    start_time = datetime.datetime.strptime(prog_item["Time"], "%H:%M").time()

    start = datetime.datetime.combine(date, start_time)
    end = start + datetime.timedelta(minutes=int(prog_item["Duration"]))
    
    people = prog_item["Participants"]
    
    tags = prog_item["Tracks"].split(",")
    tags.append(prog_item["Format"])
    
    if title=="Lunch" or title=="Dinner" or title=="Breakfast":
        tags.append("Break")
            

    venues = [prog_item['Room']]
            
    description = prog_item['Description']
    return session(id, start, end, title, tags, people, venues, description)


def fetch_sessions(path):
    df = pd.read_excel(path,keep_default_na=False) #keep_default_na stops emptystring being converted to nan
    return [load_grenadine_session(df.loc[ii,:]) 
            for ii in range(len(df))
            if len(df.loc[ii,"Day"])>0 #must have Day set
           ]

In [38]:
def all_venues(sessions):
    return set().union(*(ss.venues for ss in sessions))

def replace_room_with_rooms(sessions, old, *news):
    for sess in sessions:
        if old in sess.venues:
            #print(sess.title)
            sess.venues.remove(old)
            sess.venues.update(news)
    
    sessions
    

"Find multiple copies of events for different rooms at the same time, and convert them to single events in spanning rooms"
def bridge_rooms(sessions):
    bridged_sessions = []
    
    sessions.sort(key=lambda x: (x.start, x.end, x.title))
    for _, matchs in it.groupby(sessions, lambda x: (x.start, x.end, x.title)):
        matchs = list(matchs) #GoldPlate: this doesn't have to be done
        head = matchs[0]
        tail = matchs[1:]
        for sess in tail:
            head.venues.update(sess.venues)
        bridged_sessions.append(head)
        
    
    sessions[:]=bridged_sessions[:]
    return sessions

def fill_empty_room_slots(sessions):
    venues = all_venues(sessions)
    for ss in sessions:
        if len(ss.venues)==0:
            print(ss.title)
            ss.venues = venues
    sessions

In [39]:
sessions = fetch_sessions("con_data/items_01-02-2019.xlsx")


Great Books You've Never Heard Of!
Open Board Gaming
Fluttering Souls - Session 1
Future Spaces
Nerf Wars!
Open Videogaming
The History of D&D's most famous and strange monsters
D&D Adventure League - Session 1
Ideas Clash Workshop
Welcome to GenghisCon!
Lunch
Comics, make one today!
PowerPoint Roulette
D&D and tulpas - writing level 3 characters
Future of Work – what will I be doing in 2030?
Open Board Gaming
Fluttering Souls - Session 2
- The perils of writing/publishing vampires
Future of Transport – how will we get around in 2050?
D&D Adventure League - Session 2
Feminism in SF and Fantasy
Afternoon Tea with Grant Stone
Fluttering Souls - Designing the Game
- Doctor Who - The Clock Strikes 13
Utopias: Real and Imagined
Make your own LARP weapon!
Rites of Passage: Role Models in TV
Makers' Mutterings
LARP Duel
Dinner
Rebel Empire Makeup
Ask Me Anything! - Sexuality, Gender and Expression!
I volunteer as tribute!
Rebel Empire Performance
Open Board Gaming
The Dark Room
Sky Talk
Rock Band!
Texas Hold'em Poker Tournament (18+)
Johann Sebastian Joust
Wrestling as Fandom
Solving the world's problems one infinity gauntlet at a time
Breakfast
Open Board Gaming
Why are we awake?
Fluttering Souls Session 3
Sustainable Transport and Energy
Realistic Uses and Abuses of SuperPowers
Masculinity in Games
D&D Adventure League - Session 3
House Darksun - Medieval Combat Demonstration
Kamen Rider
Making the MegaCorp RPG
Lunch
Countdown to Infinity
Super Smash Bros Ultimate!
Hack your Jeans
Hannibal: Eat the Rude
Rites of Passage: Sorting Hat Ceremony
AGM and Election for GenghisCon 2020!
Zelda: a Link to the Past Randomizer
GenghisCon Auction
VR Freeplay
The Sorcerer Supreme RPG
Closing Ceremony and packup
Dinner
Sequels Versus Remakes
- Streaming 101
JackBox Game Night!
- Game Development on a Budget
- Speaking Elvish 101

In [40]:
# Remove sessions that are not really program items from the book's perspective
#nonevent_rooms = set(["Meeting Room 1", 'Meetings on 5 foyer', 'Boardroom foyer'])
#sessions = [sess for sess in sessions 
#            if sess.venues==set() or sess.venues-nonevent_rooms != set()]

In [41]:
#replace_room_with_rooms(sessions, 'Swan Rooms', 'Swan Room, Black', 'Swan Room, White')
bridge_rooms(sessions);
fill_empty_room_slots(sessions)


Breakfast

In [42]:
set(tuple(cc.venues) for cc in sessions)


Out[42]:
{('Dining Hall',),
 ('Elsey 1',),
 ('Georgian',),
 ('Georgian',
  'Robertson Cafe',
  'Reynolds',
  'Outside',
  'Dining Hall',
  'Elsey 1'),
 ('Outside',),
 ('Reynolds',),
 ('Robertson Cafe',)}

In [43]:
venue_order = ('Georgian',
  'Robertson Cafe',
  'Reynolds',
  'Outside',
  'Dining Hall',
  'Elsey 1')

In [44]:
from pylatex.utils import escape_latex, NoEscape
from pylatex.utils import NoEscape
from pagelayout import Multicols
from itertools import groupby
from pylatex.base_classes import Environment

class Minipage(Environment):
    def __init__(self, width):
        Environment.__init__(self,arguments=[width])


def write_descriptions(sessions, doc):
    for day_name, day_session in groupby(sessions, lambda ss: ss.day):
        #with doc.create(Section(day_name,numbering=False)):
            with doc.create(Multicols(2)):
                doc.append(NoEscape("[\section*{%s}]" %day_name))
                for session in day_session:
                    if len(session.description)==0:
                        continue
                    title = session.title
                    with doc.create(Subsection(title,numbering=False, label=False)):
                        with doc.create(Description()) as desc:
                            doc.append(Command("setlength",[NoEscape("\itemsep"),"0pt"]))
                            doc.append(Command("setlength",[NoEscape("\parsep"),"0pt"]))
                            doc.append(Command("setlength",[NoEscape("\parskip"),"0pt"]))
                            desc.add_item("When:", session.day+", "+session.start_time+" – "+session.end_time)

                            if len(session.venues)>0:
                                desc.add_item("Where:", ", ".join(session.venues))
                            if len(session.people)>0:
                                desc.add_item("Who:", ", ".join(session.people))
                            #if len(session.tags)>0:
                            #    desc.add_item("Tags:", ", ".join(session.tags))
                        doc.append(session.description)
                doc.append(Command("newpage"))

In [45]:
import pylatex
from pylatex import Document, Section, Subsection, Subsubsection, Table, Package, lists
from pylatex.lists import Description

from pylatex.utils import escape_latex, NoEscape
from itertools import groupby
from pylatex.base_classes.command import Options
from pylatex.utils import escape_latex

def write_venues(doc, tt_solver):
    doc.append(textpos_origin('0.9cm','1cm'))
    doc.append(TextcolorboxStyle('sharp corners','center upper', valign='center',
                                 colframe='blue!50!black',colback='blue!10!white',
                                 boxsep='0pt',top='0mm',bottom='0mm',left='0mm',right='1mm'))
            
    for venue in tt_solver.venues:
        
        venue_words = venue.split()
        if len(venue_words) == 2:
            #Split the string onto two lines if it exactly 2 words
            venue_text = venue_words[0] + '\n' + venue_words[1]
        else:
            venue_text = venue
        
        doc.append(FixedTextbox(venue_text,
                                tt_solver.get_venue_x(venue),
                                '0cm', 
                                '1.5cm',
                                tt_solver.get_venue_width())
                               )

def make_pretty_timetable(doc,sessions, tt_solver):
        
    for date, day_sessions in groupby(sessions, lambda ss: ss.start.date()):   
        day_str = str(DAYS[date.weekday()])
        with doc.create(Subsection(NoEscape(day_str+" \hfill "+day_str+" \hfill "+day_str), numbering=False)):
           
            write_venues(doc,tt_solver)
            doc.append(TextcolorboxStyle('rounded corners', 'center upper', valign='center',
                                 colframe='blue!50!black',colback='white!10!white',
                                 boxsep='1pt',top='0mm',bottom='0mm',left='0mm',right='0mm'))
            
            day_sessions = sorted(day_sessions, key = lambda ss: -len(ss.venues) or -len(tt_solver.venues)-1)
            for session in day_sessions:
                #print("*", session.title)
                colback = tt_solver.get_color(session)
                tcb_options = Options(colback=colback) if colback else None
                doc.append(FixedTextbox(NoEscape('%s \\\\ \\tcbfontsize{0.75} %s -- %s ' % 
                                                     tuple(map(escape_latex, (session.title, session.start_time, session.end_time)))),
                                        tt_solver.get_x(session),
                                        tt_solver.get_y(session), 
                                        tt_solver.get_height(session),
                                        tt_solver.get_width(session),
                                        tcb_options=tcb_options))

            doc.append(Command('newpage'))

In [46]:
doc = Document(documentclass="scrreprt")
margins=['tmargin=0.5cm','bmargin=2cm','lmargin=1.5cm','rmargin=1cm',]
doc.packages.append(Package('geometry', options=margins))
doc.packages.append(Package('xcolor', options=["svgnames","dvipsnames"]))
doc.packages.append(Package("microtype"))

#doc.packages.append(Package("draftwatermark"))
doc.append(Command("newgeometry",arguments=",".join(margins)))
#doc.append(Command("SetWatermarkText", "Draft v0.7.0"))
#doc.append(Command("SetWatermarkScale", "0.5"))
#doc.append(Command("SetWatermarkColor", "0.9,0.3,0.3", "rgb"))


#############
tt_solver = timetable_metric_solver(sessions,
                                    hour_len=1.7,
                                    venue_width=2.15,
                                    units='cm',
                                    overlap=0.05,
                                    voffset=1.7,             
                                    venue_order = venue_order,
                                    get_tag_colors = get_tag_colors_mono
                                    )

make_pretty_timetable(doc,sessions, tt_solver)
write_descriptions(sessions,doc)

###############
with open("out/exported.tex", 'w') as fh:
    doc.dump(fh)
#####
    
from IPython.display import FileLink, FileLinks
    
#!lualatex --output-directory=out --interaction=nonstopmode out/exported.tex
FileLinks("./out")


Out[46]:
./out/
  exported_days.tex
  exported.tex
./out/.ipynb_checkpoints/
  exported-checkpoint.tex

In [ ]:


In [14]:
sessions[12].people


Out[14]:
['Stephen Dedman', 'Andrew Williams', 'Luke Chandler-Hopkins', 'Chris Creagh']

In [15]:
#ROOMs/DAYS

import pylatex
from pylatex import Document, Section, Subsection, Subsubsection, Table, Package,lists
from pylatex.lists import Description
from pylatex.base_classes import Command


from itertools import groupby

from collections import defaultdict
vds = defaultdict(lambda : defaultdict(list))
for date, day_sessions in groupby(sessions, lambda ss: ss.start.date()):
    for sess in day_sessions:
        for venue in sess.venues:
            vds[venue][date].append(sess)

#################################
doc = Document(documentclass="article")
doc.packages.append(Package('enumitem'))
doc.packages.append(Package('calc'))
doc.append(NoEscape(r"\setlist[description]{leftmargin=!,labelwidth=\widthof{\bfseries 13:00  –  14:00}}"))
for venue in vds.keys():
    doc.append(Command("newpage"))
    doc.append(Command("pagestyle","empty"))
    doc.append(Command("LARGE"))
    doc.append(NoEscape(r"\renewcommand{\familydefault}{\sfdefault}"))
    for date in sorted(vds[venue]):
        day = DAYS[date.weekday()]
        with doc.create(Section(NoEscape("\Huge %s\\\\ %s" % (day,venue)), numbering=False)):
            
            with doc.create(Description()) as sched:
                sesses = sorted(vds[venue][date], key=lambda ss: ss.start)
                for sess in sesses:
                    sched.add_item(NoEscape("%s%s" % (sess.start_time, sess.end_time)), sess.title)
            doc.append(Command("newpage"))
            
                

from IPython.display import FileLink, FileLinks
with open("out/exported_days.tex", 'w') as temp_out:
    doc.dump(temp_out)

#!lualatex --output-directory=out --interaction=nonstopmode exported_days.tex
FileLinks("./out")


Out[15]:

In [ ]:


In [ ]: