annotate scripts/generate_report.py @ 1316:279930a008ca

All interfaces support comment boxes. Comment box identification matches presented tag (for instance, AB will be Comment on fragment A, rather than 1). Tighter buffer loading protocol, audioObjects register with the buffer rather than checking for buffer existence (which can be buggy depending on the buffer state). Buffers now have a state to ensure exact location in loading chain (downloading, decoding, LUFS, ready).
author Nicholas Jillings <nickjillings@users.noreply.github.com>
date Fri, 29 Jan 2016 11:11:57 +0000
parents
children 8540d153caec b5bf2f57187c
rev   line source
nickjillings@1316 1 #!/usr/bin/python
nickjillings@1316 2 # -*- coding: utf-8 -*-
nickjillings@1316 3
nickjillings@1316 4 import xml.etree.ElementTree as ET
nickjillings@1316 5 import os # for getting files from directory
nickjillings@1316 6 import operator # for sorting data with multiple keys
nickjillings@1316 7 import sys # for accessing command line arguments
nickjillings@1316 8 import subprocess # for calling pdflatex
nickjillings@1316 9 import shlex # for calling pdflatex
nickjillings@1316 10 import matplotlib.pyplot as plt # plots
nickjillings@1316 11 import numpy as np # numbers
nickjillings@1316 12
nickjillings@1316 13 # Command line arguments
nickjillings@1316 14 assert len(sys.argv)<4, "generate_report takes at most 2 command line arguments\n"+\
nickjillings@1316 15 "Use: python generate_report.py [results_folder] [no_render | -nr]"
nickjillings@1316 16
nickjillings@1316 17 render_figures = True
nickjillings@1316 18
nickjillings@1316 19 # XML results files location
nickjillings@1316 20 if len(sys.argv) == 1:
nickjillings@1316 21 folder_name = "../saves/" # Looks in 'saves/' folder from 'scripts/' folder
nickjillings@1316 22 print "Use: python generate_report.py [results_folder] [no_render | -nr]"
nickjillings@1316 23 print "Using default path: " + folder_name
nickjillings@1316 24 elif len(sys.argv) == 2:
nickjillings@1316 25 folder_name = sys.argv[1] # First command line argument is folder
nickjillings@1316 26 elif len(sys.argv) == 3:
nickjillings@1316 27 folder_name = sys.argv[1] # First command line argument is folder
nickjillings@1316 28 assert sys.argv[2] in ('no_render','-nr'), "Second argument not recognised. \n" +\
nickjillings@1316 29 "Use: python generate_report.py [results_folder] [no_render | -nr]"
nickjillings@1316 30 # Second command line argument is [no_render | -nr]
nickjillings@1316 31 render_figures = False
nickjillings@1316 32
nickjillings@1316 33 def isNaN(num):
nickjillings@1316 34 return num != num
nickjillings@1316 35
nickjillings@1316 36 # Turn number of seconds (int) to '[minutes] min [seconds] s' (string)
nickjillings@1316 37 def seconds2timestr(time_in_seconds):
nickjillings@1316 38 if time_in_seconds is not None and not isNaN(time_in_seconds):
nickjillings@1316 39 time_in_minutes = int(time_in_seconds/60)
nickjillings@1316 40 remaining_seconds = int(time_in_seconds%60)
nickjillings@1316 41 return str(time_in_minutes) + " min " + str(remaining_seconds) + " s"
nickjillings@1316 42 else:
nickjillings@1316 43 return 'N/A'
nickjillings@1316 44
nickjillings@1316 45 # stats initialisation
nickjillings@1316 46 number_of_XML_files = 0
nickjillings@1316 47 number_of_pages = 0
nickjillings@1316 48 number_of_fragments = 0
nickjillings@1316 49 total_empty_comments = 0
nickjillings@1316 50 total_not_played = 0
nickjillings@1316 51 total_not_moved = 0
nickjillings@1316 52 time_per_page_accum = 0
nickjillings@1316 53
nickjillings@1316 54 # arrays initialisation
nickjillings@1316 55 page_names = []
nickjillings@1316 56 real_page_names = [] # regardless of differing numbers of fragments
nickjillings@1316 57 subject_count = [] # subjects per audioholder name
nickjillings@1316 58 page_count = []
nickjillings@1316 59 duration_page = [] # duration of experiment in function of page content
nickjillings@1316 60 duration_order = [] # duration of experiment in function of page number
nickjillings@1316 61 fragments_per_page = [] # number of fragments for corresponding page
nickjillings@1316 62
nickjillings@1316 63 # survey stats
nickjillings@1316 64 gender = []
nickjillings@1316 65 age = []
nickjillings@1316 66
nickjillings@1316 67 # get username if available
nickjillings@1316 68 for name in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'):
nickjillings@1316 69 user = os.environ.get(name)
nickjillings@1316 70 if user:
nickjillings@1316 71 break
nickjillings@1316 72 else:
nickjillings@1316 73 user = ''
nickjillings@1316 74
nickjillings@1316 75
nickjillings@1316 76 # begin LaTeX document
nickjillings@1316 77 header = r'''\documentclass[11pt, oneside]{article}
nickjillings@1316 78 \usepackage{geometry}
nickjillings@1316 79 \geometry{a4paper}
nickjillings@1316 80 \usepackage[parfill]{parskip} % empty line instead of indent
nickjillings@1316 81 \usepackage{graphicx} % figures
nickjillings@1316 82 \usepackage[space]{grffile} % include figures with spaces in paths
nickjillings@1316 83 \usepackage{hyperref}
nickjillings@1316 84 \usepackage{tikz} % pie charts
nickjillings@1316 85 \title{Report}
nickjillings@1316 86 \author{'''+\
nickjillings@1316 87 user+\
nickjillings@1316 88 r'''}
nickjillings@1316 89 \graphicspath{{'''+\
nickjillings@1316 90 folder_name+\
nickjillings@1316 91 r'''}}
nickjillings@1316 92 %\setcounter{section}{-1} % Summary section 0 so number of sections equals number of files
nickjillings@1316 93 \begin{document}
nickjillings@1316 94 \maketitle
nickjillings@1316 95 This is an automatically generated report using the `generate\_report.py' Python script
nickjillings@1316 96 included with the Web Audio Evaluation Tool \cite{WAET} distribution which can be found
nickjillings@1316 97 at \texttt{code.soundsoftware.ac.uk/projects/webaudioevaluationtool}.
nickjillings@1316 98 \tableofcontents
nickjillings@1316 99
nickjillings@1316 100 '''
nickjillings@1316 101
nickjillings@1316 102 footer = '\n\t\t'+r'''\begin{thebibliography}{9}
nickjillings@1316 103 \bibitem{WAET} % reference to accompanying publication
nickjillings@1316 104 Nicholas Jillings, Brecht De Man, David Moffat and Joshua D. Reiss,
nickjillings@1316 105 ``Web Audio Evaluation Tool: A browser-based listening test environment,''
nickjillings@1316 106 presented at the 12th Sound and Music Computing Conference, July 2015.
nickjillings@1316 107 \end{thebibliography}
nickjillings@1316 108 \end{document}'''
nickjillings@1316 109
nickjillings@1316 110 body = ''
nickjillings@1316 111
nickjillings@1316 112 # make sure folder_name ends in '/'
nickjillings@1316 113 folder_name = os.path.join(folder_name, '')
nickjillings@1316 114
nickjillings@1316 115 # generate images for later use
nickjillings@1316 116 if render_figures:
nickjillings@1316 117 subprocess.call("python timeline_view_movement.py '"+folder_name+"'", shell=True)
nickjillings@1316 118 subprocess.call("python score_parser.py '"+folder_name+"'", shell=True)
nickjillings@1316 119 subprocess.call("python score_plot.py '"+folder_name+"ratings/'", shell=True)
nickjillings@1316 120
nickjillings@1316 121 # get every XML file in folder
nickjillings@1316 122 files_list = os.listdir(folder_name)
nickjillings@1316 123 for file in files_list: # iterate over all files in files_list
nickjillings@1316 124 if file.endswith(".xml"): # check if XML file
nickjillings@1316 125 number_of_XML_files += 1
nickjillings@1316 126 tree = ET.parse(folder_name + file)
nickjillings@1316 127 root = tree.getroot()
nickjillings@1316 128
nickjillings@1316 129 # PRINT name as section
nickjillings@1316 130 body+= '\n\section{'+file[:-4].capitalize()+'}\n' # make section header from name without extension
nickjillings@1316 131
nickjillings@1316 132 # reset for new subject
nickjillings@1316 133 total_duration = 0
nickjillings@1316 134 page_number = 0
nickjillings@1316 135
nickjillings@1316 136 individual_table = '\n' # table with stats for this individual test file
nickjillings@1316 137 timeline_plots = '' # plots of timeline (movements and plays)
nickjillings@1316 138
nickjillings@1316 139 # DEMO survey stats
nickjillings@1316 140 # get gender
nickjillings@1316 141 this_subjects_gender = root.find("./posttest/radio/[@id='gender']")
nickjillings@1316 142 if this_subjects_gender is not None:
nickjillings@1316 143 gender.append(this_subjects_gender.get("name"))
nickjillings@1316 144 else:
nickjillings@1316 145 gender.append('UNAVAILABLE')
nickjillings@1316 146 # get age
nickjillings@1316 147 this_subjects_age = root.find("./posttest/number/[@id='age']")
nickjillings@1316 148 if this_subjects_age is not None:
nickjillings@1316 149 age.append(this_subjects_age.text)
nickjillings@1316 150 #TODO add plot of age
nickjillings@1316 151
nickjillings@1316 152 # get list of all page names
nickjillings@1316 153 for audioholder in root.findall("./audioholder"): # iterate over pages
nickjillings@1316 154 page_name = audioholder.get('id') # get page name
nickjillings@1316 155
nickjillings@1316 156 if page_name is None: # ignore 'empty' audio_holders
nickjillings@1316 157 print "WARNING: " + file + " contains empty audio holder. (evaluation_stats.py)"
nickjillings@1316 158 break # move on to next
nickjillings@1316 159
nickjillings@1316 160 number_of_comments = 0 # for this page
nickjillings@1316 161 number_of_missing_comments = 0 # for this page
nickjillings@1316 162 not_played = [] # for this page
nickjillings@1316 163 not_moved = [] # for this page
nickjillings@1316 164
nickjillings@1316 165 if audioholder.find("./metric/metricresult[@id='testTime']") is not None: # check if time is included
nickjillings@1316 166 # 'testTime' keeps total duration: subtract time so far for duration of this audioholder
nickjillings@1316 167 duration = float(audioholder.find("./metric/metricresult[@id='testTime']").text) - total_duration
nickjillings@1316 168
nickjillings@1316 169 # total duration of test
nickjillings@1316 170 total_duration += duration
nickjillings@1316 171 else:
nickjillings@1316 172 duration = float('nan')
nickjillings@1316 173 total_duration = float('nan')
nickjillings@1316 174
nickjillings@1316 175 # number of audio elements
nickjillings@1316 176 audioelements = audioholder.findall("./audioelement") # get audioelements
nickjillings@1316 177 number_of_fragments += len(audioelements) # add length of this list to total
nickjillings@1316 178
nickjillings@1316 179 # number of comments (interesting if comments not mandatory)
nickjillings@1316 180 for audioelement in audioelements:
nickjillings@1316 181 response = audioelement.find("./comment/response")
nickjillings@1316 182 was_played = audioelement.find("./metric/metricresult/[@name='elementFlagListenedTo']")
nickjillings@1316 183 was_moved = audioelement.find("./metric/metricresult/[@name='elementFlagMoved']")
nickjillings@1316 184 if response.text is not None and len(response.text) > 1:
nickjillings@1316 185 number_of_comments += 1
nickjillings@1316 186 else:
nickjillings@1316 187 number_of_missing_comments += 1
nickjillings@1316 188 if was_played is not None and was_played.text == 'false':
nickjillings@1316 189 not_played.append(audioelement.get('id'))
nickjillings@1316 190 if was_moved is not None and was_moved.text == 'false':
nickjillings@1316 191 not_moved.append(audioelement.get('id'))
nickjillings@1316 192
nickjillings@1316 193 # update global counters
nickjillings@1316 194 total_empty_comments += number_of_missing_comments
nickjillings@1316 195 total_not_played += len(not_played)
nickjillings@1316 196 total_not_moved += len(not_moved)
nickjillings@1316 197
nickjillings@1316 198 # PRINT alerts when elements not played or markers not moved
nickjillings@1316 199 # number of audio elements not played
nickjillings@1316 200 if len(not_played) > 1:
nickjillings@1316 201 body += '\t\t\\emph{\\textbf{ATTENTION: '+str(len(not_played))+\
nickjillings@1316 202 ' fragments were not listened to in '+page_name+'! }}'+\
nickjillings@1316 203 ', '.join(not_played)+'\\\\ \n'
nickjillings@1316 204 if len(not_played) == 1:
nickjillings@1316 205 body += '\t\t\\emph{\\textbf{ATTENTION: one fragment was not listened to in '+page_name+'! }}'+\
nickjillings@1316 206 not_played[0]+'\\\\ \n'
nickjillings@1316 207
nickjillings@1316 208 # number of audio element markers not moved
nickjillings@1316 209 if len(not_moved) > 1:
nickjillings@1316 210 body += '\t\t\\emph{\\textbf{ATTENTION: '+str(len(not_moved))+\
nickjillings@1316 211 ' markers were not moved in '+page_name+'! }}'+\
nickjillings@1316 212 ', '.join(not_moved)+'\\\\ \n'
nickjillings@1316 213 if len(not_moved) == 1:
nickjillings@1316 214 body += '\t\t\\emph{\\textbf{ATTENTION: one marker was not moved in '+page_name+'! }}'+\
nickjillings@1316 215 not_moved[0]+'\\\\ \n'
nickjillings@1316 216
nickjillings@1316 217 # PRINT song-specific statistic
nickjillings@1316 218 individual_table += '\t\t'+page_name+'&'+\
nickjillings@1316 219 str(number_of_comments) + '/' +\
nickjillings@1316 220 str(number_of_comments+number_of_missing_comments)+'&'+\
nickjillings@1316 221 seconds2timestr(duration)+'\\\\\n'
nickjillings@1316 222
nickjillings@1316 223 # get timeline for this audioholder
nickjillings@1316 224 img_path = 'timelines_movement/'+file[:-4]+'-'+page_name+'.pdf'
nickjillings@1316 225
nickjillings@1316 226 # check if available
nickjillings@1316 227 if os.path.isfile(folder_name+img_path):
nickjillings@1316 228 # SHOW timeline image
nickjillings@1316 229 timeline_plots += '\\includegraphics[width=\\textwidth]{'+\
nickjillings@1316 230 folder_name+img_path+'}\n\t\t'
nickjillings@1316 231
nickjillings@1316 232 # keep track of duration in function of page index
nickjillings@1316 233 if len(duration_order)>page_number:
nickjillings@1316 234 duration_order[page_number].append(duration)
nickjillings@1316 235 else:
nickjillings@1316 236 duration_order.append([duration])
nickjillings@1316 237
nickjillings@1316 238 # keep list of audioholder ids and count how many times each audioholder id
nickjillings@1316 239 # was tested, how long it took, and how many fragments there were
nickjillings@1316 240 # (if number of fragments is different, store as different audioholder id)
nickjillings@1316 241 if page_name in page_names:
nickjillings@1316 242 page_index = page_names.index(page_name) # get index
nickjillings@1316 243 # check if number of audioelements the same
nickjillings@1316 244 if len(audioelements) == fragments_per_page[page_index]:
nickjillings@1316 245 page_count[page_index] += 1
nickjillings@1316 246 duration_page[page_index].append(duration)
nickjillings@1316 247 else: # make new entry
nickjillings@1316 248 alt_page_name = page_name+"("+str(len(audioelements))+")"
nickjillings@1316 249 if alt_page_name in page_names: # if already there
nickjillings@1316 250 alt_page_index = page_names.index(alt_page_name) # get index
nickjillings@1316 251 page_count[alt_page_index] += 1
nickjillings@1316 252 duration_page[alt_page_index].append(duration)
nickjillings@1316 253 else:
nickjillings@1316 254 page_names.append(alt_page_name)
nickjillings@1316 255 page_count.append(1)
nickjillings@1316 256 duration_page.append([duration])
nickjillings@1316 257 fragments_per_page.append(len(audioelements))
nickjillings@1316 258 else:
nickjillings@1316 259 page_names.append(page_name)
nickjillings@1316 260 page_count.append(1)
nickjillings@1316 261 duration_page.append([duration])
nickjillings@1316 262 fragments_per_page.append(len(audioelements))
nickjillings@1316 263
nickjillings@1316 264 # number of subjects per audioholder regardless of differing numbers of
nickjillings@1316 265 # fragments (for inclusion in box plots)
nickjillings@1316 266 if page_name in real_page_names:
nickjillings@1316 267 page_index = real_page_names.index(page_name) # get index
nickjillings@1316 268 subject_count[page_index] += 1
nickjillings@1316 269 else:
nickjillings@1316 270 real_page_names.append(page_name)
nickjillings@1316 271 subject_count.append(1)
nickjillings@1316 272
nickjillings@1316 273 # bookkeeping
nickjillings@1316 274 page_number += 1 # increase page count for this specific test
nickjillings@1316 275 number_of_pages += 1 # increase total number of pages
nickjillings@1316 276 time_per_page_accum += duration # total duration (for average time spent per page)
nickjillings@1316 277
nickjillings@1316 278 # PRINT table with statistics about this test
nickjillings@1316 279 body += '\t\t'+r'''\begin{tabular}{|p{3.5cm}|c|p{2.5cm}|}
nickjillings@1316 280 \hline
nickjillings@1316 281 \textbf{Song name} & \textbf{Comments} & \textbf{Duration} \\ \hline '''+\
nickjillings@1316 282 individual_table+'\t\t'+\
nickjillings@1316 283 r'''\hline
nickjillings@1316 284 \textbf{TOTAL} & & \textbf{'''+\
nickjillings@1316 285 seconds2timestr(total_duration)+\
nickjillings@1316 286 r'''}\\
nickjillings@1316 287 \hline
nickjillings@1316 288 \end{tabular}
nickjillings@1316 289
nickjillings@1316 290 '''
nickjillings@1316 291 # PRINT timeline plots
nickjillings@1316 292 body += timeline_plots
nickjillings@1316 293
nickjillings@1316 294 # join to footer
nickjillings@1316 295 footer = body + footer
nickjillings@1316 296
nickjillings@1316 297 # empty body again
nickjillings@1316 298 body = ''
nickjillings@1316 299
nickjillings@1316 300 # PRINT summary of everything (at start)
nickjillings@1316 301 # unnumbered so that number of sections equals number of files
nickjillings@1316 302 body += '\section*{Summary}\n\t\t\\addcontentsline{toc}{section}{Summary}\n'
nickjillings@1316 303
nickjillings@1316 304 # PRINT table with statistics
nickjillings@1316 305 body += '\t\t\\begin{tabular}{ll}\n\t\t\t'
nickjillings@1316 306 body += r'Number of XML files: &' + str(number_of_XML_files) + r'\\'+'\n\t\t\t'
nickjillings@1316 307 body += r'Number of pages: &' + str(number_of_pages) + r'\\'+'\n\t\t\t'
nickjillings@1316 308 body += r'Number of fragments: &' + str(number_of_fragments) + r'\\'+'\n\t\t\t'
nickjillings@1316 309 body += r'Number of empty comments: &' + str(total_empty_comments) +\
nickjillings@1316 310 " (" + str(round(100.0*total_empty_comments/number_of_fragments,2)) + r"\%)\\"+'\n\t\t\t'
nickjillings@1316 311 body += r'Number of unplayed fragments: &' + str(total_not_played) +\
nickjillings@1316 312 " (" + str(round(100.0*total_not_played/number_of_fragments,2)) + r"\%)\\"+'\n\t\t\t'
nickjillings@1316 313 body += r'Number of unmoved markers: &' + str(total_not_moved) +\
nickjillings@1316 314 " (" + str(round(100.0*total_not_moved/number_of_fragments,2)) + r"\%)\\"+'\n\t\t\t'
nickjillings@1316 315 body += r'Average time per page: &' + seconds2timestr(time_per_page_accum/number_of_pages) + r"\\"+'\n\t\t'
nickjillings@1316 316 body += '\\end{tabular} \\vspace{1.5cm} \\\\ \n'
nickjillings@1316 317
nickjillings@1316 318 # Average duration for first, second, ... page
nickjillings@1316 319 body += "\t\t\\vspace{.5cm} \n\n\t\tAverage duration per page (see also Figure \\ref{fig:avgtimeperpage}): \\\\ \n\t\t"
nickjillings@1316 320 body += r'''\begin{tabular}{lll}
nickjillings@1316 321 \textbf{Page} & \textbf{Duration} & \textbf{\# subjects}\\'''
nickjillings@1316 322 tpp_averages = [] # store average time per page
nickjillings@1316 323 for page_number in range(len(duration_order)):
nickjillings@1316 324 body += '\n\t\t\t'+str(page_number+1) + "&" +\
nickjillings@1316 325 seconds2timestr(sum(duration_order[page_number])/len(duration_order[page_number])) +\
nickjillings@1316 326 "&"+str(len(duration_order[page_number]))+r"\\"
nickjillings@1316 327 tpp_averages.append(sum(duration_order[page_number])/len(duration_order[page_number]))
nickjillings@1316 328
nickjillings@1316 329 body += '\n\t\t\\end{tabular} \\vspace{1.5cm} \\\\ \n\n\t\t'
nickjillings@1316 330
nickjillings@1316 331 # SHOW bar plot of average time per page
nickjillings@1316 332 plt.bar(range(1,len(duration_order)+1), np.array(tpp_averages)/60)
nickjillings@1316 333 plt.xlabel('Page order')
nickjillings@1316 334 plt.xlim(.8, len(duration_order)+1)
nickjillings@1316 335 plt.xticks(np.arange(1,len(duration_order)+1)+.4, range(1,len(duration_order)+1))
nickjillings@1316 336 plt.ylabel('Average time [minutes]')
nickjillings@1316 337 plt.savefig(folder_name+"time_per_page.pdf", bbox_inches='tight')
nickjillings@1316 338 plt.close()
nickjillings@1316 339 #TODO add error bars
nickjillings@1316 340
nickjillings@1316 341
nickjillings@1316 342 # Sort pages by number of audioelements, then by duration
nickjillings@1316 343
nickjillings@1316 344 # average duration and number of subjects per page
nickjillings@1316 345 average_duration_page = []
nickjillings@1316 346 number_of_subjects_page = []
nickjillings@1316 347 for line in duration_page:
nickjillings@1316 348 number_of_subjects_page.append(len(line))
nickjillings@1316 349 average_duration_page.append(sum(line)/len(line))
nickjillings@1316 350
nickjillings@1316 351 # combine and sort in function of number of audioelements and duration
nickjillings@1316 352 combined_list = [page_names, average_duration_page, fragments_per_page, number_of_subjects_page]
nickjillings@1316 353 combined_list = sorted(zip(*combined_list), key=operator.itemgetter(1, 2)) # sort
nickjillings@1316 354
nickjillings@1316 355 # Show average duration for all songs
nickjillings@1316 356 body += r'''\vspace{.5cm}
nickjillings@1316 357 Average duration per audioholder (see also Figure \ref{fig:avgtimeperaudioholder}): \\
nickjillings@1316 358 \begin{tabular}{llll}
nickjillings@1316 359 \textbf{Audioholder} & \textbf{Duration} & \textbf{\# subjects} & \textbf{\# fragments} \\'''
nickjillings@1316 360 audioholder_names_ordered = []
nickjillings@1316 361 average_duration_audioholder_ordered = []
nickjillings@1316 362 number_of_subjects = []
nickjillings@1316 363 for page_index in range(len(page_names)):
nickjillings@1316 364 audioholder_names_ordered.append(combined_list[page_index][0])
nickjillings@1316 365 average_duration_audioholder_ordered.append(combined_list[page_index][1])
nickjillings@1316 366 number_of_subjects.append(combined_list[page_index][3])
nickjillings@1316 367 body += '\n\t\t\t'+combined_list[page_index][0] + "&" +\
nickjillings@1316 368 seconds2timestr(combined_list[page_index][1]) + "&" +\
nickjillings@1316 369 str(combined_list[page_index][3]) + "&" +\
nickjillings@1316 370 str(combined_list[page_index][2]) + r"\\"
nickjillings@1316 371 body += '\n\t\t\\end{tabular}\n'
nickjillings@1316 372
nickjillings@1316 373 # SHOW bar plot of average time per page
nickjillings@1316 374 plt.bar(range(1,len(audioholder_names_ordered)+1), np.array(average_duration_audioholder_ordered)/60)
nickjillings@1316 375 plt.xlabel('Audioholder')
nickjillings@1316 376 plt.xlim(.8, len(audioholder_names_ordered)+1)
nickjillings@1316 377 plt.xticks(np.arange(1,len(audioholder_names_ordered)+1)+.4, audioholder_names_ordered, rotation=90)
nickjillings@1316 378 plt.ylabel('Average time [minutes]')
nickjillings@1316 379 plt.savefig(folder_name+"time_per_audioholder.pdf", bbox_inches='tight')
nickjillings@1316 380 plt.close()
nickjillings@1316 381
nickjillings@1316 382 # SHOW bar plot of average time per page
nickjillings@1316 383 plt.bar(range(1,len(audioholder_names_ordered)+1), number_of_subjects)
nickjillings@1316 384 plt.xlabel('Audioholder')
nickjillings@1316 385 plt.xlim(.8, len(audioholder_names_ordered)+1)
nickjillings@1316 386 plt.xticks(np.arange(1,len(audioholder_names_ordered)+1)+.4, audioholder_names_ordered, rotation=90)
nickjillings@1316 387 plt.ylabel('Number of subjects')
nickjillings@1316 388 ax = plt.gca()
nickjillings@1316 389 ylims = ax.get_ylim()
nickjillings@1316 390 yint = np.arange(int(np.floor(ylims[0])), int(np.ceil(ylims[1]))+1)
nickjillings@1316 391 plt.yticks(yint)
nickjillings@1316 392 plt.savefig(folder_name+"subjects_per_audioholder.pdf", bbox_inches='tight')
nickjillings@1316 393 plt.close()
nickjillings@1316 394
nickjillings@1316 395 # SHOW both figures
nickjillings@1316 396 body += r'''
nickjillings@1316 397 \begin{figure}[htbp]
nickjillings@1316 398 \begin{center}
nickjillings@1316 399 \includegraphics[width=.65\textwidth]{'''+\
nickjillings@1316 400 folder_name+'time_per_page.pdf'+\
nickjillings@1316 401 r'''}
nickjillings@1316 402 \caption{Average time spent per page.}
nickjillings@1316 403 \label{fig:avgtimeperpage}
nickjillings@1316 404 \end{center}
nickjillings@1316 405 \end{figure}
nickjillings@1316 406
nickjillings@1316 407 '''
nickjillings@1316 408 body += r'''\begin{figure}[htbp]
nickjillings@1316 409 \begin{center}
nickjillings@1316 410 \includegraphics[width=.65\textwidth]{'''+\
nickjillings@1316 411 folder_name+'time_per_audioholder.pdf'+\
nickjillings@1316 412 r'''}
nickjillings@1316 413 \caption{Average time spent per audioholder.}
nickjillings@1316 414 \label{fig:avgtimeperaudioholder}
nickjillings@1316 415 \end{center}
nickjillings@1316 416 \end{figure}
nickjillings@1316 417
nickjillings@1316 418 '''
nickjillings@1316 419 body += r'''\begin{figure}[htbp]
nickjillings@1316 420 \begin{center}
nickjillings@1316 421 \includegraphics[width=.65\textwidth]{'''+\
nickjillings@1316 422 folder_name+'subjects_per_audioholder.pdf'+\
nickjillings@1316 423 r'''}
nickjillings@1316 424 \caption{Number of subjects per audioholder.}
nickjillings@1316 425 \label{fig:subjectsperaudioholder}
nickjillings@1316 426 \end{center}
nickjillings@1316 427 \end{figure}
nickjillings@1316 428
nickjillings@1316 429 '''
nickjillings@1316 430 #TODO add error bars
nickjillings@1316 431 #TODO layout of figures
nickjillings@1316 432
nickjillings@1316 433 # SHOW boxplot per audioholder
nickjillings@1316 434 #TODO order in decreasing order of participants
nickjillings@1316 435 for audioholder_name in page_names: # get each name
nickjillings@1316 436 # plot boxplot if exists (not so for the 'alt' names)
nickjillings@1316 437 if os.path.isfile(folder_name+'ratings/'+audioholder_name+'-ratings-box.pdf'):
nickjillings@1316 438 body += r'''\begin{figure}[htbp]
nickjillings@1316 439 \begin{center}
nickjillings@1316 440 \includegraphics[width=.65\textwidth]{'''+\
nickjillings@1316 441 folder_name+"ratings/"+audioholder_name+'-ratings-box.pdf'+\
nickjillings@1316 442 r'''}
nickjillings@1316 443 \caption{Box plot of ratings for audioholder '''+\
nickjillings@1316 444 audioholder_name+' ('+str(subject_count[real_page_names.index(audioholder_name)])+\
nickjillings@1316 445 ''' participants).}
nickjillings@1316 446 \label{fig:boxplot'''+audioholder_name.replace(" ", "")+'''}
nickjillings@1316 447 \end{center}
nickjillings@1316 448 \end{figure}
nickjillings@1316 449
nickjillings@1316 450 '''
nickjillings@1316 451
nickjillings@1316 452 # DEMO pie chart of gender distribution among subjects
nickjillings@1316 453 genders = ['male', 'female', 'other', 'preferNotToSay', 'UNAVAILABLE']
nickjillings@1316 454 # TODO: get the above automatically
nickjillings@1316 455 gender_distribution = ''
nickjillings@1316 456 for item in genders:
nickjillings@1316 457 number = gender.count(item)
nickjillings@1316 458 if number>0:
nickjillings@1316 459 gender_distribution += str("{:.2f}".format((100.0*number)/len(gender)))+\
nickjillings@1316 460 '/'+item.capitalize()+' ('+str(number)+'),\n'
nickjillings@1316 461
nickjillings@1316 462 body += r'''
nickjillings@1316 463 % Pie chart of gender distribution
nickjillings@1316 464 \def\angle{0}
nickjillings@1316 465 \def\radius{3}
nickjillings@1316 466 \def\cyclelist{{"orange","blue","red","green"}}
nickjillings@1316 467 \newcount\cyclecount \cyclecount=-1
nickjillings@1316 468 \newcount\ind \ind=-1
nickjillings@1316 469 \begin{figure}[htbp]
nickjillings@1316 470 \begin{center}\begin{tikzpicture}[nodes = {font=\sffamily}]
nickjillings@1316 471 \foreach \percent/\name in {'''+\
nickjillings@1316 472 gender_distribution+\
nickjillings@1316 473 r'''} {\ifx\percent\empty\else % If \percent is empty, do nothing
nickjillings@1316 474 \global\advance\cyclecount by 1 % Advance cyclecount
nickjillings@1316 475 \global\advance\ind by 1 % Advance list index
nickjillings@1316 476 \ifnum6<\cyclecount % If cyclecount is larger than list
nickjillings@1316 477 \global\cyclecount=0 % reset cyclecount and
nickjillings@1316 478 \global\ind=0 % reset list index
nickjillings@1316 479 \fi
nickjillings@1316 480 \pgfmathparse{\cyclelist[\the\ind]} % Get color from cycle list
nickjillings@1316 481 \edef\color{\pgfmathresult} % and store as \color
nickjillings@1316 482 % Draw angle and set labels
nickjillings@1316 483 \draw[fill={\color!50},draw={\color}] (0,0) -- (\angle:\radius)
nickjillings@1316 484 arc (\angle:\angle+\percent*3.6:\radius) -- cycle;
nickjillings@1316 485 \node at (\angle+0.5*\percent*3.6:0.7*\radius) {\percent\,\%};
nickjillings@1316 486 \node[pin=\angle+0.5*\percent*3.6:\name]
nickjillings@1316 487 at (\angle+0.5*\percent*3.6:\radius) {};
nickjillings@1316 488 \pgfmathparse{\angle+\percent*3.6} % Advance angle
nickjillings@1316 489 \xdef\angle{\pgfmathresult} % and store in \angle
nickjillings@1316 490 \fi
nickjillings@1316 491 };
nickjillings@1316 492 \end{tikzpicture}
nickjillings@1316 493 \caption{Representation of gender across subjects}
nickjillings@1316 494 \label{default}
nickjillings@1316 495 \end{center}
nickjillings@1316 496 \end{figure}
nickjillings@1316 497
nickjillings@1316 498 '''
nickjillings@1316 499 # problem: some people entered twice?
nickjillings@1316 500
nickjillings@1316 501 #TODO
nickjillings@1316 502 # time per page in function of number of fragments (plot)
nickjillings@1316 503 # time per participant in function of number of pages
nickjillings@1316 504 # plot total time for each participant
nickjillings@1316 505 # show 'count' per page (in order)
nickjillings@1316 506
nickjillings@1316 507 # clear up page_index <> page_count <> page_number confusion
nickjillings@1316 508
nickjillings@1316 509
nickjillings@1316 510 texfile = header+body+footer # add bits together
nickjillings@1316 511
nickjillings@1316 512 print 'pdflatex -output-directory="'+folder_name+'"" "'+ folder_name + 'Report.tex"' # DEBUG
nickjillings@1316 513
nickjillings@1316 514 # write TeX file
nickjillings@1316 515 with open(folder_name + 'Report.tex','w') as f:
nickjillings@1316 516 f.write(texfile)
nickjillings@1316 517 proc=subprocess.Popen(shlex.split('pdflatex -output-directory="'+folder_name+'" "'+ folder_name + 'Report.tex"'))
nickjillings@1316 518 proc.communicate()
nickjillings@1316 519 # run again
nickjillings@1316 520 proc=subprocess.Popen(shlex.split('pdflatex -output-directory="'+folder_name+'" "'+ folder_name + 'Report.tex"'))
nickjillings@1316 521 proc.communicate()
nickjillings@1316 522
nickjillings@1316 523 #TODO remove auxiliary LaTeX files
nickjillings@1316 524 try:
nickjillings@1316 525 os.remove(folder_name + 'Report.aux')
nickjillings@1316 526 os.remove(folder_name + 'Report.log')
nickjillings@1316 527 os.remove(folder_name + 'Report.out')
nickjillings@1316 528 os.remove(folder_name + 'Report.toc')
nickjillings@1316 529 except OSError:
nickjillings@1316 530 pass
nickjillings@1316 531