From e3481a4a35091b32b6fbee80c1c9ba2b6d7b50d6 Mon Sep 17 00:00:00 2001 From: erdgeist Date: Sun, 22 Dec 2024 21:53:57 +0100 Subject: Rework of halfnarp and fullnarp into a self contained repository. Still WIP --- scripts/create_corr_array_pretalx.py | 50 ++++++++++++++++++++++ scripts/gen_css_tables.py | 83 ++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 scripts/create_corr_array_pretalx.py create mode 100755 scripts/gen_css_tables.py (limited to 'scripts') diff --git a/scripts/create_corr_array_pretalx.py b/scripts/create_corr_array_pretalx.py new file mode 100644 index 0000000..dd9221d --- /dev/null +++ b/scripts/create_corr_array_pretalx.py @@ -0,0 +1,50 @@ +#!venv/bin/python + +# convert halfnarp's output into the correlation array that can later +# be served by halfnarp to show clusters of talks by your audience's +# preferences +# +# Run this script with a single parameter, a file containing the output +# of halfnarp2.py -e and place this script's output in a file that is +# being served statically, e.g. corr_array_38c3.json + +import json +import sys +import itertools +from collections import defaultdict + +# load in list of talk preferences, which is list of strings with talk ids +with open(sys.argv[1]) as data_file: + corr = json.load(data_file) + +all_sums = dict(defaultdict()) +all_events = {} +l = len(corr) + +for arr in corr: + + for x in arr: + all_events[x] = 1 + + for x, y in itertools.combinations_with_replacement(sorted(arr), 2): + if x in all_sums.keys(): + all_sums[x][y] = 1 + all_sums[x].get(y, 1) + else: + all_sums[x] = defaultdict() + +all_events = sorted(set(all_events)) + +out_strings = defaultdict(str) + +for x, y in itertools.combinations(all_events, 2): + xyc = all_sums[x].get(y, 0) + xc = all_sums[x].get(x, 0) + yc = all_sums[y].get(y, 0) +# print (x, y, both, xcount, ycount) + xy_corr = 4.0 * l * xyc * xyc * (xc + yc) / (xc*xc*yc*yc) if xc * yc > 0 else 0 + if xy_corr > 9: + xy_corr = 9 + out_strings[x] += str(int(xy_corr)) + +out_dict = { 'event_ids': all_events, 'event_corrs': list(out_strings.values()) } +print (json.dumps(out_dict, separators=(',', ':'))) diff --git a/scripts/gen_css_tables.py b/scripts/gen_css_tables.py new file mode 100755 index 0000000..4bc5ea8 --- /dev/null +++ b/scripts/gen_css_tables.py @@ -0,0 +1,83 @@ +#!python3 + +# This script generates the css tables needed for halfnarp to work +# properly with different start and end dates, rooms and numers of +# days. Adapt the to your conference's needs and place the result +# in the css document, e.g. style_38c3_tables.css + +start_y = 400 +starttime = 10 +endtime = 28 +rooms = 3 +days = 4 +columns = days * rooms # how many columns does +event_gap = { 'large': 5, 'medium': 3, 'small': 2 } # how much is an event shorter than what the grid would allow in px +block_length = 210 + +time_grid = 5 # what is the granularity of Fahrplan raster in minutes +elem_per_hour = 60 / time_grid # how many sections does one hour get + +# how many pixels are in one hour vertically in LARGE, MEDIUM, SMALL +hour_height={ 'large': 300, 'medium': 160, 'small': 120 } + +# What is the height of one grid element +grid_height={ 'large': hour_height['large'] / elem_per_hour, 'medium': hour_height['medium'] / elem_per_hour, 'small': hour_height['small'] / elem_per_hour } + +for size in ['large', 'medium', 'small']: + y = start_y + for hour in range(starttime, endtime): + for minute in range(0,60,time_grid): + print ( '.size-' + size + ' .time_' + str(hour % 24).zfill(2) + str(minute).zfill(2) + ' { top: ' + str(y) + 'px; }' ) + y += grid_height[size] + +for size in ['large', 'medium', 'small']: + for duration in range(300,12000,100): + height = hour_height[size] * duration / 3600 - event_gap[size] + print ( '.size-' + size + ' .duration_' + str(duration) + ' { min-height: ' + str(height) + 'px; max-height: ' + str(height) + 'px; }') + print ( '.size-' + size + ' .wholeblock { height: ' + str(hour_height[size] * block_length / 60) + 'px; }' ) + +print ( '.size-large .grid { height: ' + str(grid_height['large']) + 'px; font-size: 1em; }' ) +print ( '.size-medium .grid { height: ' + str(grid_height['medium'])+ 'px; font-size: 0.5em; }' ) +print ( '.size-small .grid { height: ' + str(grid_height['small']) + 'px; font-size: 0.3em; }' ) + +gap = 4 +width = ( 100 - gap * ( 1 + rooms ) ) / rooms +for room in range(rooms): + print ( '.in-calendar .room' + str(room+1) +' { left: ' + str(gap * (room + 1) + width * room ) + '%; }' ) + +print ('.in-calendar .event, .in-calendar .room-label, .in-calendar .grid { position: absolute; width: ' + str(width)+ '%; }' ) +print ('.in-calendar .r, .in-calendar .l { width: ' + str(width) + '%; }') +print ('.in-calendar .rr, .in-calendar .ll { width: ' + str(2*width+gap) + '%; }') +print ('.in-calendar .rrr, .in-calendar .lll { width: ' + str(3*width+2*gap) + '%; }') +print ('.in-calendar .rrrr, .in-calendar .llll { width: ' + str(4*width+3*gap) + '%; }') +print ('.in-calendar .r, .in-calendar .rr, .in-calendar .rrr, .in-calendar .rrrr { margin-left: ' + str(width / 2) + '% ; }') +print ('.in-calendar .l { margin-left: -' + str(width / 2) + '% ; }') +print ('.in-calendar .ll { margin-left: -' + str(width / 2 + gap + width) + '% ; }') +print ('.in-calendar .lll { margin-left: -' + str(width / 2 + gap * 2 + width * 2) + '% ; }') +print ('.in-calendar .llll { margin-left: -' + str(width / 2 + gap * 3 + width * 3) + '% ; }') + +gap = 0.5 +width = ( 100 - gap * ( 1 + columns ) ) / columns +for day in range(days): + for room in range(rooms): + print ( '.in-calendar.alldays .day_' + str(day+1) + '.room' + str(room+1) +' { left: ' + str(gap * (day*rooms + room + 1) + width * (day * rooms + room ) ) + '%; }' ) + +print ('.wholeday, .wholeblock { width: ' + str(100 / days)+ '% }') +print ('.in-calendar.alldays .event, .in-calendar.alldays .room-label, .in-calendar.alldays .grid { width: ' + str(width)+ '%; }' ) + +print ('.in-calendar.alldays .r, .in-calendar.alldays .l { width: ' + str(width) + '%; }') +print ('.in-calendar.alldays .rr, .in-calendar.alldays .ll { width: ' + str(2*width+gap) + '%; }') +print ('.in-calendar.alldays .rrr, .in-calendar.alldays .lll { width: ' + str(3*width+2*gap) + '%; }') +print ('.in-calendar.alldays .rrrr, .in-calendar.alldays .llll { width: ' + str(4*width+3*gap) + '%; }') + +print ('.in-calendar.alldays .r, .in-calendar.alldays .rr, .in-calendar.alldays .rrr, .in-calendar.alldays .rrrr { margin-left: ' + str(width / 2) + '% ; }') +print ('.in-calendar.alldays .l { margin-left: -' + str(width / 2) + '% ; }') +print ('.in-calendar.alldays .ll { margin-left: -' + str(width / 2 + gap + width) + '% ; }') +print ('.in-calendar.alldays .lll { margin-left: -' + str(width / 2 + gap * 2 + width * 2) + '% ; }') +print ('.in-calendar.alldays .llll { margin-left: -' + str(width / 2 + gap * 3 + width * 3) + '% ; }') + +print ('.r, .rr, .rrr, .rrrr, .l, .ll, .lll, .llll { height: 4px; }') + +for size in ['large', 'medium', 'small']: + print ('.size-' + size +' .wholeday { height: ' + str( ( endtime - starttime ) * hour_height[size] ) + 'px; }' ) + print ('.size-' + size +' .duration_inf { height: ' + str( 7 * hour_height[size] ) + 'px; }' ) -- cgit v1.2.3