# HG changeset patch # User Brecht De Man # Date 1439828430 -7200 # Node ID f1201566b54b6f3f0410ed1e71c075f76eaffff2 # Parent 4dd1cb18b77cb100618e2fe867f8754718a79294 Scripts: modification to timeline plots: do not save (/show) plot if empty, e.g. legacy result files with no timing data diff -r 4dd1cb18b77c -r f1201566b54b README.txt --- a/README.txt Wed Aug 12 10:31:10 2015 +0200 +++ b/README.txt Mon Aug 17 18:20:30 2015 +0200 @@ -35,6 +35,7 @@ QUICK START + Using the example project: 1. Make sure your system sample rate corresponds with the sample rate of the audio files, if the input XML file enforces the given sample rate. 2. Run pythonServer.py (make sure you have Python installed). @@ -44,6 +45,7 @@ LEGACY + The APE interface and most of the functionality of the interface is inspired by the APE toolbox for MATLAB [1]. See https://code.soundsoftware.ac.uk/projects/ape for the source code and corresponding paper. @@ -81,10 +83,15 @@ In Firefox, go to Tools>Web Developer>Web Console, or hit Cmd + Alt + K. +REMOTE TESTS + +As the test is browser-based, it can be run remotely from a web server without modification. To allow for remote storage of the output XML files (as opposed to saving them locally on the subject’s machine, which is the default if no ‘save’ path is specified or found), a PHP script on the server needs to accept the output XML files. An example of such script will be included in a future version. + + SCRIPTS -The tool comes with a few handy Python scripts for easy extraction of ratings or comments, and visualisation of ratings and timelines. See below for a quick guide on how to use them. All scripts written for Python 2.7. Visualisation requires the free matplotlib toolbox (http://matplotlib.org), numpy and scipy. -By default, the scripts can be run from the ‘scripts’ folder, with the result files in the ‘saves’ folder (the default location where result XMLs are stored). +The tool comes with a few handy Python (2.7) scripts for easy extraction of ratings or comments, and visualisation of ratings and timelines. See below for a quick guide on how to use them. All scripts written for Python 2.7. Visualisation requires the free matplotlib toolbox (http://matplotlib.org), numpy and scipy. +By default, the scripts can be run from the ‘scripts’ folder, with the result files in the ‘saves’ folder (the default location where result XMLs are stored). Each script takes the XML file folder as an argument, along with other arguments in some cases. comment_parser.py Extracts comments from the output XML files corresponding with the different subjects found in ‘saves/’. It creates a folder per ‘audioholder’/page it finds, and stores a CSV file with comments for every ‘audioelement’/fragment within these respective ‘audioholders’/pages. In this CSV file, every line corresponds with a subject/output XML file. Depending on the settings, the first column containing the name of the corresponding XML file can be omitted (for anonymisation). @@ -102,6 +109,9 @@ Requires the free matplotlib library. At this point, more than one subjects are needed for this script to work. + timeline_view_movement.py + Creates a timeline for every subject, for every ‘audioholder’/page, corresponding with any of the output XML files found in ‘/saves’. It shows the marker movements of the different fragments, along with when each fragment was played (red regions). Automatically takes fragment names, rating axis title, rating axis labels, and audioholder name from the XML file (if available). + timeline_view.py Creates a timeline for every subject, for every ‘audioholder’/page, corresponding with any of the output XML files found in ‘/saves’. It shows when and for how long the subject listened to each of the fragments. diff -r 4dd1cb18b77c -r f1201566b54b scripts/timeline_view.py --- a/scripts/timeline_view.py Wed Aug 12 10:31:10 2015 +0200 +++ b/scripts/timeline_view.py Mon Aug 17 18:20:30 2015 +0200 @@ -73,6 +73,7 @@ # get list of all page names for audioholder in root.findall("./audioholder"): # iterate over pages page_name = audioholder.get('id') # get page name + plot_empty = True # check if any data is plotted if page_name is None: # ignore 'empty' audio_holders break @@ -96,7 +97,7 @@ # for page [page_name], print comments related to fragment [id] for tuple in data: - audioelement = tuple[1] + audioelement = tuple[1] if audioelement is not None: # Check it exists audio_id = str(audioelement.get('id')) audioelements_names.append(audio_id) @@ -104,6 +105,9 @@ # for this audioelement, loop over all listen events listen_events = audioelement.findall("./metric/metricresult/[@name='elementListenTracker']/event") for event in listen_events: + # mark this plot as not empty + plot_empty = False + # get testtime: start and stop start_time = float(event.find('testtime').get('start'))-time_offset stop_time = float(event.find('testtime').get('stop'))-time_offset @@ -133,21 +137,22 @@ if audioholder_time is not None and show_audioholder_time: time_offset = float(audioholder_time.text) - # set plot parameters - plt.title('Timeline ' + file + ": "+page_name) - plt.xlabel('Time [seconds]') - plt.ylabel('Fragment') - plt.ylim(0, N_audioelements+1) + if not plot_empty: + # set plot parameters + plt.title('Timeline ' + file + ": "+page_name) + plt.xlabel('Time [seconds]') + plt.ylabel('Fragment') + plt.ylim(0, N_audioelements+1) - #y-ticks: fragment IDs, top to bottom - plt.yticks(range(N_audioelements, 0, -1), audioelements_names) # show fragment names + #y-ticks: fragment IDs, top to bottom + plt.yticks(range(N_audioelements, 0, -1), audioelements_names) # show fragment names - #plt.show() # uncomment to show plot; comment when just saving - #exit() + #plt.show() # uncomment to show plot; comment when just saving + #exit() - plt.savefig(timeline_folder+subject_id+"-"+page_name+".pdf", bbox_inches='tight') - plt.close() + plt.savefig(timeline_folder+subject_id+"-"+page_name+".pdf", bbox_inches='tight') + plt.close() #TODO: if 'nonsensical' or unknown: dashed line until next event #TODO: Vertical lines for fragment looping point diff -r 4dd1cb18b77c -r f1201566b54b scripts/timeline_view_movement.py --- a/scripts/timeline_view_movement.py Wed Aug 12 10:31:10 2015 +0200 +++ b/scripts/timeline_view_movement.py Mon Aug 17 18:20:30 2015 +0200 @@ -69,6 +69,7 @@ # get list of all page names for audioholder in root.findall("./audioholder"): # iterate over pages page_name = audioholder.get('id') # get page name + plot_empty = True # check if any data is plotted if page_name is None: # ignore 'empty' audio_holders print "Skipping empty audioholder name from "+subject_id+"." @@ -139,6 +140,9 @@ # draw all segments except final one for event in move_events: + # mark this plot as not empty + plot_empty = False + # get time and final position of move event new_time = float(event.find("./time").text)-time_offset new_position = float(event.find("./position").text) @@ -223,31 +227,31 @@ last_audioholder_duration = audioholder_time-time_offset time_offset = audioholder_time - - # set plot parameters - plt.title('Timeline ' + file + ": "+page_name) - plt.xlabel('Time [seconds]') - plt.xlim(0, last_audioholder_duration) - plt.ylabel('Rating') # default - plt.ylim(0, 1) # rating between 0 and 1 + if not plot_empty: # if plot is not empty, show or store + # set plot parameters + plt.title('Timeline ' + file + ": "+page_name) + plt.xlabel('Time [seconds]') + plt.xlim(0, last_audioholder_duration) + plt.ylabel('Rating') # default + plt.ylim(0, 1) # rating between 0 and 1 - #y-ticks: labels on rating axis - label_positions = [] - label_text = [] - scale_tags = root.findall("./BrowserEvalProjectDocument/audioHolder/interface/scale") - scale_title = root.find("./BrowserEvalProjectDocument/audioHolder/interface/title") - for tag in scale_tags: - label_positions.append(float(tag.get('position'))/100) # on a scale from 0 to 100 - label_text.append(tag.text) - if len(label_positions) > 0: # if any labels available - plt.yticks(label_positions, label_text) # show rating axis labels - # set label Y-axis - if scale_title is not None: - plt.ylabel(scale_title.text) + #y-ticks: labels on rating axis + label_positions = [] + label_text = [] + scale_tags = root.findall("./BrowserEvalProjectDocument/audioHolder/interface/scale") + scale_title = root.find("./BrowserEvalProjectDocument/audioHolder/interface/title") + for tag in scale_tags: + label_positions.append(float(tag.get('position'))/100) # on a scale from 0 to 100 + label_text.append(tag.text) + if len(label_positions) > 0: # if any labels available + plt.yticks(label_positions, label_text) # show rating axis labels + # set label Y-axis + if scale_title is not None: + plt.ylabel(scale_title.text) - #plt.show() # uncomment to show plot; comment when just saving - #exit() + #plt.show() # uncomment to show plot; comment when just saving + #exit() - plt.savefig(timeline_folder+subject_id+"-"+page_name+".pdf", bbox_inches='tight') - plt.close() + plt.savefig(timeline_folder+subject_id+"-"+page_name+".pdf", bbox_inches='tight') + plt.close() \ No newline at end of file