From 20f730f13e1f728310caec23973fbdd69c8cd067 Mon Sep 17 00:00:00 2001 From: stephenworsley <49274989+stephenworsley@users.noreply.github.com> Date: Wed, 10 Apr 2019 10:12:12 +0100 Subject: [PATCH 01/12] Add files via upload --- my-WOPI.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 my-WOPI.py diff --git a/my-WOPI.py b/my-WOPI.py new file mode 100644 index 0000000..c334fb9 --- /dev/null +++ b/my-WOPI.py @@ -0,0 +1,61 @@ +import argparse +import json +import matplotlib.pyplot as plt +import matplotlib +from math import pi +import numpy as np + +def checkConfig(config): + if type(config['axes']) is not list: + raise Exception("'axes' should be a list. 'axes' was: {}".format(type(config['axes']))) + if type(config['values']) is not list: + raise Exception("'values' should be a list. 'values' was: {}".format(type(config['values']))) + if len(config['values']) != len(config['axes']): + raise Exception("Length of 'axes' and 'values' should be the same. Length of 'axes' was {}, " + "length of 'values' was {}".format(len(config['values']), len(config['axes']))) + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("-c", "--config", type=str, + help="config file") + parser.add_argument("-s", "--save", type=str, + help="save plot as an image") + args = parser.parse_args() + + with open(args.config) as json_file: + config = json.load(json_file) + checkConfig(config) + + number_of_axes = len(config['axes']) + angle = 2*pi / number_of_axes + angles = [angle*x for x in range(number_of_axes)] + # angles2 = [angle*x for x in range(number_of_axes+1)] + values = config['values'] + # values2 = true_values + true_values[:1] + labels = config['axes'] + + polygon_coords = np.array(list(zip(angles,values))) + + ax = plt.subplot(111, polar=True) + plt.xticks(angles, labels) + plt.title(config['title']) + polygon = matplotlib.patches.Polygon(polygon_coords, alpha=0.1) + ax.add_patch(polygon) + # ax.plot(angles2, values2) + # ax.fill(angles2, values2, 'b', alpha=0.1) + ax.set_rmax(5) + + if args.save is None: + plt.show() + else: + plt.savefig(args.save, format='png') + + + + + + +main() + +#if __name__ == "__main_": +# main() \ No newline at end of file From ccf4d3fe5c58038bee0b852782c04af47fff150c Mon Sep 17 00:00:00 2001 From: stephenworsley <49274989+stephenworsley@users.noreply.github.com> Date: Fri, 12 Apr 2019 10:38:04 +0100 Subject: [PATCH 02/12] Add files via upload --- my-WOPI.py | 206 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 177 insertions(+), 29 deletions(-) diff --git a/my-WOPI.py b/my-WOPI.py index c334fb9..0222716 100644 --- a/my-WOPI.py +++ b/my-WOPI.py @@ -1,61 +1,209 @@ import argparse import json import matplotlib.pyplot as plt +import matplotlib.animation as animation import matplotlib from math import pi import numpy as np +import datetime -def checkConfig(config): - if type(config['axes']) is not list: - raise Exception("'axes' should be a list. 'axes' was: {}".format(type(config['axes']))) - if type(config['values']) is not list: - raise Exception("'values' should be a list. 'values' was: {}".format(type(config['values']))) - if len(config['values']) != len(config['axes']): - raise Exception("Length of 'axes' and 'values' should be the same. Length of 'axes' was {}, " - "length of 'values' was {}".format(len(config['values']), len(config['axes']))) +def cleanConfig(config): + if 'title' not in config: + config['title'] = '' + if 'axes' not in config: + raise Exception("'axes' does not exist in config file.") + else: + if type(config['axes']) is not list: + raise Exception("'axes' should be a list. 'axes' had type: {}".format(type(config['axes']))) + if 'groups' not in config: + raise Exception("'groups' does not exist in config file.") + if type(config['groups']) is not dict: + raise Exception("'groups' should be a dict. 'axes' had type: {}".format(type(config['groups']))) + if 'animated' not in config: + config['animated'] = False + if type(config['animated']) is not bool: + raise Exception("'animated' should be a bool value. 'animated' had type {}".format(type(config['animated']))) + if 'colormap' not in config: + config['colormap'] = 'tab20' + if 'frame_length' not in config: + config['frame_length'] = 400 -def main(): + date_dict = dict() + frames_missing = False + has_frames = False + name_list = [] + data_set = set() + for group, content in config['groups'].items(): + if type(content) is not dict: + raise Exception("{0} should be a dict. {0} had type: {1}".format(type(content),group)) + if 'name' not in content: + content['name'] = group + if content['name'] not in name_list: + name_list.append(content['name']) + if 'data' not in content: + raise Exception("'data' does not exist in group '{}'.".format(group)) + if type(content['data']) is not list: + raise Exception("'data' in group '{}' is not a list") + if len(content['data']) != len(config['axes']): + raise Exception("the size of data in group '{}' conflicts with the number of axes" + .format(group)) + for x in content['data']: + if not isinstance(x,(int, float)): + raise Exception("data in group'{}' is not numerical".format(group)) + data_set.add(x) + if config['animated']: + if not ('date' in content or 'frame' in content): + raise Exception("insufficient data in group '{}' to assign a frame" + .format(group)) + if 'date' in content: + date_dict.setdefault(content['date'], []).append(group) + if 'frame' in content: + if type(content['frame']) is not int: + raise Exception("'frame' in group {} does not have type int".format(group)) + # if content['frame'] < 0 + # raise Exception ("'frame' in group {} is negative".format(group)) + has_frames = True + else: + frames_missing = True + else: + content['frame'] = 0 + if 'max' not in config: + config['max'] = max(data_set) + 1 + if 'min' not in config: + config['min'] = min(data_set) - 1 + + if config['animated']: + if has_frames and frames_missing: + raise Exception("frame data is incomplete") + i = 0 + for date in sorted(date_dict, key=lambda date: datetime.datetime.strptime(date, "%d/%m/%Y")): + group_list = date_dict[date] + if not has_frames: + for group in group_list: + config['groups'][group]['frame'] = i + i += 1 + + cm = matplotlib.cm.get_cmap(config['colormap']) + palette = [matplotlib.colors.to_rgb(cm(x/len(name_list))) for x in range(len(name_list))] + color_set = set() + color_frame_dict = dict() + name_color_dict = dict() + name_frame_set = set() + for group, content in config['groups'].items(): + + if 'color' not in content: + content['color'] = 'default' + elif content['color'] != 'default': + if not matplotlib.colors.is_color_like(content['color']): + raise Exception("group '{}' does not have a valid color.".format(group)) + normalized_color = matplotlib.colors.to_rgb(content['color']) + color_set.add(normalized_color) + if (normalized_color,content['frame']) in color_frame_dict: + raise Exception("group '{}' has shares a conflicting color with group '{}'" + .format(group,color_frame_dict[(normalized_color,content['frame'])])) + else: + color_frame_dict[(normalized_color,content['frame'])] = group + + if content['name'] in name_color_dict: + if content['color'] != name_color_dict[content['name']]: + raise Exception("the group name '{}' is assigned two different colors" + .format(content['name'])) + else: + name_color_dict[content['name']] = content['color'] + if (content['name'],content['frame']) in name_frame_set: + raise Exception("two groups share the name '{}' and the frame '{}'" + .format(content['name'],content['frame'])) + else: + name_frame_set.add((content['name'],content['frame'])) + + for group, content in config['groups'].items(): + if content['color'] == 'default': + if content['name'] in name_color_dict: + content['color'] = name_color_dict[content['name']] + else: + color_assigned = False + for col in palette: + if col not in color_set: + content['color'] = col + name_color_dict[content['name']] = col + color_set.add(col) + color_assigned = True + break + if not color_assigned: + raise Exception("insufficient colors in colormap '{}'".format(config['colormap'])) + + +def orderFrames(config): + frame_dict = dict() + for group, content in config['groups'].items(): + frame_dict.setdefault(content['frame'],[]).append(group) + ordered_frame_list = sorted(frame_dict) + min = ordered_frame_list[0] + max = ordered_frame_list[-1] + total_frame_list = [frame_dict[frame+min] if frame+min in frame_dict else (frame,[]) + for frame in range(max-min+1)] + return total_frame_list + + +def parseCommands(): parser = argparse.ArgumentParser() parser.add_argument("-c", "--config", type=str, help="config file") parser.add_argument("-s", "--save", type=str, help="save plot as an image") args = parser.parse_args() + return args + +def setConfig(args): with open(args.config) as json_file: config = json.load(json_file) - checkConfig(config) + cleanConfig(config) + return config + + +def main(): + args = parseCommands() + config = setConfig(args) + frame_list = orderFrames(config) number_of_axes = len(config['axes']) angle = 2*pi / number_of_axes angles = [angle*x for x in range(number_of_axes)] - # angles2 = [angle*x for x in range(number_of_axes+1)] - values = config['values'] - # values2 = true_values + true_values[:1] labels = config['axes'] + fig = plt.figure() + ax = plt.subplot(111, polar=True, animated=False) - polygon_coords = np.array(list(zip(angles,values))) + def update_fig(i): + ax.clear() + plt.xticks(angles, labels) + plt.title(config['title']) + ax.set_rmax(config['max']) + ax.set_rmin(config['min']) - ax = plt.subplot(111, polar=True) - plt.xticks(angles, labels) - plt.title(config['title']) - polygon = matplotlib.patches.Polygon(polygon_coords, alpha=0.1) - ax.add_patch(polygon) - # ax.plot(angles2, values2) - # ax.fill(angles2, values2, 'b', alpha=0.1) - ax.set_rmax(5) + group_list = frame_list[i] + for group in group_list: + patch_color = config['groups'][group]['color'] + values = config['groups'][group]['data'] + polygon_coords = np.array(list(zip(angles,values))) - if args.save is None: - plt.show() - else: - plt.savefig(args.save, format='png') + polygon = matplotlib.patches.Polygon(polygon_coords, color=patch_color, alpha=0.4) + ax.add_patch(polygon) + plt.draw() + update_fig(0) + if config['animated']: + ani = animation.FuncAnimation(fig, update_fig, len(frame_list), interval=config['frame_length']) + if args.save is None: + plt.show() + else: + if config['animated']: + plt.savefig(args.save, format='png') + else: + ani.save(args.save) main() - -#if __name__ == "__main_": -# main() \ No newline at end of file From 7eab90af11a98ef65320f16304ff9b679faa95fc Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Fri, 12 Apr 2019 16:35:47 +0100 Subject: [PATCH 03/12] Full version --- .idea/vcs.xml | 6 ++ WOPI_config_writer.py | 38 +++++++ my-WOPI.py | 246 ++++++++++++++++++++++++++++++++++++++++++ test_my-WOPI.py | 0 4 files changed, 290 insertions(+) create mode 100644 .idea/vcs.xml create mode 100644 WOPI_config_writer.py create mode 100644 my-WOPI.py create mode 100644 test_my-WOPI.py diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/WOPI_config_writer.py b/WOPI_config_writer.py new file mode 100644 index 0000000..9070065 --- /dev/null +++ b/WOPI_config_writer.py @@ -0,0 +1,38 @@ +import json + +# class Config +# def __init__(self, ) + +def save_json(j_dict, file): + with open(file, 'w') as outfile: + json.dump(j_dict,outfile) + + +def write_heli_data(angles, blades, blade_length=8, fat=True): + blade_offsets = [int(angles*x/blades) for x in range(blades)] + base = [1 for x in range(angles)] + blade_names = ['blade_{}'.format(x) for x in range(blades)] + axes = ['' for x in range(angles)] + + heli_dict = {'title': 'helicopter', 'colormap': 'jet', 'axes': axes, 'animated': True, 'frame_length': 40} + + groups = dict() + for t in range(angles): + for b in range(blades): + pos = (t+blade_offsets[b]) % angles + data = base.copy() + data[pos] = blade_length + if fat: + data[(pos+1) % angles] = blade_length + content = {'name':blade_names[b], + 'data':data, + 'frame':t} + g_name = 'group_{}_{}'.format(b,t) + groups[g_name] = content + heli_dict['groups'] = groups + return heli_dict + +h_dict = write_heli_data(20,4) +file = 'helicopter_3.json' + +save_json(h_dict, file) \ No newline at end of file diff --git a/my-WOPI.py b/my-WOPI.py new file mode 100644 index 0000000..0dcd9b7 --- /dev/null +++ b/my-WOPI.py @@ -0,0 +1,246 @@ +import argparse +import json +import matplotlib.pyplot as plt +import matplotlib.animation as animation +import matplotlib +from math import pi +import numpy as np +import datetime + +def cleanConfig(config): + """ + Cleans the configuration data and raises exceptions where appropriate. + + Args: + + * config (dict) + """ + if 'title' not in config: + config['title'] = '' + if 'axes' not in config: + raise Exception("'axes' does not exist in config file.") + else: + if type(config['axes']) is not list: + raise Exception("'axes' should be a list. 'axes' had type: {}".format(type(config['axes']))) + if 'groups' not in config: + raise Exception("'groups' does not exist in config file.") + if type(config['groups']) is not dict: + raise Exception("'groups' should be a dict. 'axes' had type: {}".format(type(config['groups']))) + if 'animated' not in config: + config['animated'] = False + if type(config['animated']) is not bool: + raise Exception("'animated' should be a bool value. 'animated' had type {}".format(type(config['animated']))) + if 'colormap' not in config: + config['colormap'] = 'tab20' + if 'frame_length' not in config: + config['frame_length'] = 400 + + date_dict = dict() + frames_missing = False + has_frames = False + name_set = set() + data_set = set() + for group, content in config['groups'].items(): + if type(content) is not dict: + raise Exception("{0} should be a dict. {0} had type: {1}".format(type(content),group)) + if 'name' not in content: + content['name'] = group + name_set.add(content['name']) + if 'data' not in content: + raise Exception("'data' does not exist in group '{}'.".format(group)) + if type(content['data']) is not list: + raise Exception("'data' in group '{}' is not a list") + if len(content['data']) != len(config['axes']): + raise Exception("the size of data in group '{}' conflicts with the number of axes" + .format(group)) + for x in content['data']: + if not isinstance(x,(int, float)): + raise Exception("data in group'{}' is not numerical".format(group)) + data_set.add(x) + if config['animated']: + if not ('date' in content or 'frame' in content): + raise Exception("insufficient data in group '{}' to assign a frame" + .format(group)) + if 'date' in content: + date_dict.setdefault(content['date'], []).append(group) + if 'frame' in content: + if type(content['frame']) is not int: + raise Exception("'frame' in group {} does not have type int".format(group)) + has_frames = True + else: + frames_missing = True + else: + content['frame'] = 0 + if 'max' not in config: + config['max'] = max(data_set) + 1 + if 'min' not in config: + config['min'] = min(data_set) - 1 + + if config['animated']: + if has_frames and frames_missing: + raise Exception("frame data is incomplete") + # if frames_missing is True and an exception has not been raised then all groups must have dates. + # 'frame' data is then assumed to be in chronological order and the config file is updated accordingly. + if not has_frames: + i = 0 + for date in sorted(date_dict, key=lambda date: datetime.datetime.strptime(date, "%d/%m/%Y")): + group_list = date_dict[date] + + for group in group_list: + config['groups'][group]['frame'] = i + i += 1 + + # if no color is specified for a group then one will be assigned. If there is a group with the same name which + # already has a color, this one will be assigned, otherwise one will be chosen using the specified colormap. + # Colors must be the same for all groups with the same name. Colors must be distinct on each frame. + cm = matplotlib.cm.get_cmap(config['colormap']) + palette = [matplotlib.colors.to_rgb(cm(x/len(name_set))) for x in range(len(name_set))] + color_set = set() + color_frame_dict = dict() + name_color_dict = dict() + name_frame_set = set() + for group, content in config['groups'].items(): + + if 'color' not in content: + content['color'] = 'default' + elif content['color'] != 'default': + if not matplotlib.colors.is_color_like(content['color']): + raise Exception("group '{}' does not have a valid color.".format(group)) + # Colors are normalized to rgb so they can be compared. + normalized_color = matplotlib.colors.to_rgb(content['color']) + color_set.add(normalized_color) + if (normalized_color,content['frame']) in color_frame_dict: + raise Exception("group '{}' has shares a conflicting color with group '{}'" + .format(group,color_frame_dict[(normalized_color,content['frame'])])) + else: + color_frame_dict[(normalized_color,content['frame'])] = group + if content['name'] in name_color_dict: + if content['color'] != name_color_dict[content['name']]: + raise Exception("the group name '{}' is assigned two different colors" + .format(content['name'])) + else: + name_color_dict[content['name']] = content['color'] + if (content['name'],content['frame']) in name_frame_set: + raise Exception("two groups share the name '{}' and the frame '{}'" + .format(content['name'],content['frame'])) + else: + name_frame_set.add((content['name'],content['frame'])) + for group, content in config['groups'].items(): + if content['color'] == 'default': + if content['name'] in name_color_dict: + content['color'] = name_color_dict[content['name']] + else: + color_assigned = False + for col in palette: + if col not in color_set: + content['color'] = col + name_color_dict[content['name']] = col + color_set.add(col) + color_assigned = True + break + if not color_assigned: + raise Exception("insufficient colors in colormap '{}'".format(config['colormap'])) + + +def orderFrames(config): + """ + Extracts a list of lists of groups, ordered by their frames. + + If a frame in between the start and end has no group with that frame, an empty list will be placed in that position. + + Args: + config (dict) + Returns: + list + """ + frame_dict = dict() + for group, content in config['groups'].items(): + frame_dict.setdefault(content['frame'],[]).append(group) + ordered_frame_list = sorted(frame_dict) + min_ = ordered_frame_list[0] + max_ = ordered_frame_list[-1] + total_frame_list = [frame_dict[frame+min_] if frame+min_ in frame_dict else (frame,[]) + for frame in range(max_-min_+1)] + return total_frame_list + + +def parseCommands(): + """ + Parses commands from the command line. + + Returns: + * argparse.ArgumentParser object + """ + parser = argparse.ArgumentParser() + parser.add_argument("-c", "--config", type=str, + help="config file") + parser.add_argument("-s", "--save", type=str, + help="save plot as an image") + args = parser.parse_args() + return args + + +def setConfig(args): + """ + Reads config file location from args, extracts json file to dict. + + Args: + + * args () + + Returns: + dict + """ + with open(args.config) as json_file: + config = json.load(json_file) + cleanConfig(config) + return config + + +def main(): + args = parseCommands() + config = setConfig(args) + frame_list = orderFrames(config) + + number_of_axes = len(config['axes']) + angle = 2*pi / number_of_axes + angles = [angle*x for x in range(number_of_axes)] + labels = config['axes'] + fig = plt.figure() + ax = plt.subplot(111, polar=True, animated=False) + + def update_fig(i): + ax.clear() + plt.xticks(angles, labels) + plt.title(config['title']) + ax.set_rmax(config['max']) + ax.set_rmin(config['min']) + + group_list = frame_list[i] + for group in group_list: + patch_color = config['groups'][group]['color'] + values = config['groups'][group]['data'] + polygon_coords = np.array(list(zip(angles,values))) + + polygon = matplotlib.patches.Polygon(polygon_coords, color=patch_color, alpha=0.4, + label=config['groups'][group]['name']) + ax.add_patch(polygon) + ax.legend(loc='lower right') + plt.draw() + + update_fig(0) + + if config['animated']: + ani = animation.FuncAnimation(fig, update_fig, len(frame_list), interval=config['frame_length'], repeat=True) + + + if args.save is None: + plt.show() + else: + if not config['animated']: + plt.savefig(args.save, format='png') + else: + ani.save(args.save) + + +main() diff --git a/test_my-WOPI.py b/test_my-WOPI.py new file mode 100644 index 0000000..e69de29 From 69a193342f5cd6fcc8080c10cdf66dc846c88baf Mon Sep 17 00:00:00 2001 From: stephenworsley <49274989+stephenworsley@users.noreply.github.com> Date: Fri, 12 Apr 2019 16:55:26 +0100 Subject: [PATCH 04/12] Add files via upload --- my-WOPI.py | 75 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 19 deletions(-) diff --git a/my-WOPI.py b/my-WOPI.py index 0222716..0dcd9b7 100644 --- a/my-WOPI.py +++ b/my-WOPI.py @@ -8,6 +8,13 @@ import datetime def cleanConfig(config): + """ + Cleans the configuration data and raises exceptions where appropriate. + + Args: + + * config (dict) + """ if 'title' not in config: config['title'] = '' if 'axes' not in config: @@ -31,15 +38,14 @@ def cleanConfig(config): date_dict = dict() frames_missing = False has_frames = False - name_list = [] + name_set = set() data_set = set() for group, content in config['groups'].items(): if type(content) is not dict: raise Exception("{0} should be a dict. {0} had type: {1}".format(type(content),group)) if 'name' not in content: content['name'] = group - if content['name'] not in name_list: - name_list.append(content['name']) + name_set.add(content['name']) if 'data' not in content: raise Exception("'data' does not exist in group '{}'.".format(group)) if type(content['data']) is not list: @@ -60,8 +66,6 @@ def cleanConfig(config): if 'frame' in content: if type(content['frame']) is not int: raise Exception("'frame' in group {} does not have type int".format(group)) - # if content['frame'] < 0 - # raise Exception ("'frame' in group {} is negative".format(group)) has_frames = True else: frames_missing = True @@ -75,16 +79,22 @@ def cleanConfig(config): if config['animated']: if has_frames and frames_missing: raise Exception("frame data is incomplete") - i = 0 - for date in sorted(date_dict, key=lambda date: datetime.datetime.strptime(date, "%d/%m/%Y")): - group_list = date_dict[date] - if not has_frames: + # if frames_missing is True and an exception has not been raised then all groups must have dates. + # 'frame' data is then assumed to be in chronological order and the config file is updated accordingly. + if not has_frames: + i = 0 + for date in sorted(date_dict, key=lambda date: datetime.datetime.strptime(date, "%d/%m/%Y")): + group_list = date_dict[date] + for group in group_list: config['groups'][group]['frame'] = i i += 1 + # if no color is specified for a group then one will be assigned. If there is a group with the same name which + # already has a color, this one will be assigned, otherwise one will be chosen using the specified colormap. + # Colors must be the same for all groups with the same name. Colors must be distinct on each frame. cm = matplotlib.cm.get_cmap(config['colormap']) - palette = [matplotlib.colors.to_rgb(cm(x/len(name_list))) for x in range(len(name_list))] + palette = [matplotlib.colors.to_rgb(cm(x/len(name_set))) for x in range(len(name_set))] color_set = set() color_frame_dict = dict() name_color_dict = dict() @@ -96,6 +106,7 @@ def cleanConfig(config): elif content['color'] != 'default': if not matplotlib.colors.is_color_like(content['color']): raise Exception("group '{}' does not have a valid color.".format(group)) + # Colors are normalized to rgb so they can be compared. normalized_color = matplotlib.colors.to_rgb(content['color']) color_set.add(normalized_color) if (normalized_color,content['frame']) in color_frame_dict: @@ -103,7 +114,6 @@ def cleanConfig(config): .format(group,color_frame_dict[(normalized_color,content['frame'])])) else: color_frame_dict[(normalized_color,content['frame'])] = group - if content['name'] in name_color_dict: if content['color'] != name_color_dict[content['name']]: raise Exception("the group name '{}' is assigned two different colors" @@ -115,7 +125,6 @@ def cleanConfig(config): .format(content['name'],content['frame'])) else: name_frame_set.add((content['name'],content['frame'])) - for group, content in config['groups'].items(): if content['color'] == 'default': if content['name'] in name_color_dict: @@ -134,18 +143,34 @@ def cleanConfig(config): def orderFrames(config): + """ + Extracts a list of lists of groups, ordered by their frames. + + If a frame in between the start and end has no group with that frame, an empty list will be placed in that position. + + Args: + config (dict) + Returns: + list + """ frame_dict = dict() for group, content in config['groups'].items(): frame_dict.setdefault(content['frame'],[]).append(group) ordered_frame_list = sorted(frame_dict) - min = ordered_frame_list[0] - max = ordered_frame_list[-1] - total_frame_list = [frame_dict[frame+min] if frame+min in frame_dict else (frame,[]) - for frame in range(max-min+1)] + min_ = ordered_frame_list[0] + max_ = ordered_frame_list[-1] + total_frame_list = [frame_dict[frame+min_] if frame+min_ in frame_dict else (frame,[]) + for frame in range(max_-min_+1)] return total_frame_list def parseCommands(): + """ + Parses commands from the command line. + + Returns: + * argparse.ArgumentParser object + """ parser = argparse.ArgumentParser() parser.add_argument("-c", "--config", type=str, help="config file") @@ -156,6 +181,16 @@ def parseCommands(): def setConfig(args): + """ + Reads config file location from args, extracts json file to dict. + + Args: + + * args () + + Returns: + dict + """ with open(args.config) as json_file: config = json.load(json_file) cleanConfig(config) @@ -187,20 +222,22 @@ def update_fig(i): values = config['groups'][group]['data'] polygon_coords = np.array(list(zip(angles,values))) - polygon = matplotlib.patches.Polygon(polygon_coords, color=patch_color, alpha=0.4) + polygon = matplotlib.patches.Polygon(polygon_coords, color=patch_color, alpha=0.4, + label=config['groups'][group]['name']) ax.add_patch(polygon) + ax.legend(loc='lower right') plt.draw() update_fig(0) if config['animated']: - ani = animation.FuncAnimation(fig, update_fig, len(frame_list), interval=config['frame_length']) + ani = animation.FuncAnimation(fig, update_fig, len(frame_list), interval=config['frame_length'], repeat=True) if args.save is None: plt.show() else: - if config['animated']: + if not config['animated']: plt.savefig(args.save, format='png') else: ani.save(args.save) From 33cffbd9b4cf492150b73a1fb89b862b76c95d0c Mon Sep 17 00:00:00 2001 From: stephenworsley <49274989+stephenworsley@users.noreply.github.com> Date: Fri, 12 Apr 2019 16:58:23 +0100 Subject: [PATCH 05/12] Add files via upload --- helicopter_3.json | 1 + testConfigEx.json | 45 +++++++++++++++++++++ testConfigFrameDataIncomplete.json | 64 ++++++++++++++++++++++++++++++ testConfigLong.json | 64 ++++++++++++++++++++++++++++++ 4 files changed, 174 insertions(+) create mode 100644 helicopter_3.json create mode 100644 testConfigEx.json create mode 100644 testConfigFrameDataIncomplete.json create mode 100644 testConfigLong.json diff --git a/helicopter_3.json b/helicopter_3.json new file mode 100644 index 0000000..44ee355 --- /dev/null +++ b/helicopter_3.json @@ -0,0 +1 @@ +{"title": "helicopter", "colormap": "jet", "axes": ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""], "animated": true, "frame_length": 40, "groups": {"group_0_0": {"name": "blade_0", "data": [8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 0}, "group_1_0": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 0}, "group_2_0": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 0}, "group_3_0": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1], "frame": 0}, "group_0_1": {"name": "blade_0", "data": [1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 1}, "group_1_1": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 1}, "group_2_1": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1], "frame": 1}, "group_3_1": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1], "frame": 1}, "group_0_2": {"name": "blade_0", "data": [1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 2}, "group_1_2": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 2}, "group_2_2": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1], "frame": 2}, "group_3_2": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1], "frame": 2}, "group_0_3": {"name": "blade_0", "data": [1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 3}, "group_1_3": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 3}, "group_2_3": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1], "frame": 3}, "group_3_3": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8], "frame": 3}, "group_0_4": {"name": "blade_0", "data": [1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 4}, "group_1_4": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 4}, "group_2_4": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1], "frame": 4}, "group_3_4": {"name": "blade_3", "data": [8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8], "frame": 4}, "group_0_5": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 5}, "group_1_5": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 5}, "group_2_5": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1], "frame": 5}, "group_3_5": {"name": "blade_3", "data": [8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 5}, "group_0_6": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 6}, "group_1_6": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1], "frame": 6}, "group_2_6": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1], "frame": 6}, "group_3_6": {"name": "blade_3", "data": [1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 6}, "group_0_7": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 7}, "group_1_7": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1], "frame": 7}, "group_2_7": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1], "frame": 7}, "group_3_7": {"name": "blade_3", "data": [1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 7}, "group_0_8": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 8}, "group_1_8": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1], "frame": 8}, "group_2_8": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8], "frame": 8}, "group_3_8": {"name": "blade_3", "data": [1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 8}, "group_0_9": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 9}, "group_1_9": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1], "frame": 9}, "group_2_9": {"name": "blade_2", "data": [8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8], "frame": 9}, "group_3_9": {"name": "blade_3", "data": [1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 9}, "group_0_10": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 10}, "group_1_10": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1], "frame": 10}, "group_2_10": {"name": "blade_2", "data": [8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 10}, "group_3_10": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 10}, "group_0_11": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1], "frame": 11}, "group_1_11": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1], "frame": 11}, "group_2_11": {"name": "blade_2", "data": [1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 11}, "group_3_11": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 11}, "group_0_12": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1], "frame": 12}, "group_1_12": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1], "frame": 12}, "group_2_12": {"name": "blade_2", "data": [1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 12}, "group_3_12": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 12}, "group_0_13": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1], "frame": 13}, "group_1_13": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8], "frame": 13}, "group_2_13": {"name": "blade_2", "data": [1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 13}, "group_3_13": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 13}, "group_0_14": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1], "frame": 14}, "group_1_14": {"name": "blade_1", "data": [8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8], "frame": 14}, "group_2_14": {"name": "blade_2", "data": [1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 14}, "group_3_14": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 14}, "group_0_15": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1], "frame": 15}, "group_1_15": {"name": "blade_1", "data": [8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 15}, "group_2_15": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 15}, "group_3_15": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 15}, "group_0_16": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1], "frame": 16}, "group_1_16": {"name": "blade_1", "data": [1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 16}, "group_2_16": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 16}, "group_3_16": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1], "frame": 16}, "group_0_17": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1], "frame": 17}, "group_1_17": {"name": "blade_1", "data": [1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 17}, "group_2_17": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 17}, "group_3_17": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1], "frame": 17}, "group_0_18": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8], "frame": 18}, "group_1_18": {"name": "blade_1", "data": [1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 18}, "group_2_18": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 18}, "group_3_18": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1], "frame": 18}, "group_0_19": {"name": "blade_0", "data": [8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8], "frame": 19}, "group_1_19": {"name": "blade_1", "data": [1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 19}, "group_2_19": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 19}, "group_3_19": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1], "frame": 19}}} \ No newline at end of file diff --git a/testConfigEx.json b/testConfigEx.json new file mode 100644 index 0000000..6996b54 --- /dev/null +++ b/testConfigEx.json @@ -0,0 +1,45 @@ +{ + "title": "test plot", + "axes": [ + "axis 1", + "axis 2", + "axis 3" + ], + "animated": true, + "groups": { + "groupA": { + "name": "Alice", + "data": [1,2,3], + "color": "blue", + "date": "01/02/2003" + }, + "groupB": { + "name": "Bob", + "data": [4,3,1], + "date": "04/05/2020" + }, + "groupC": { + "data": [4,3,1], + "color": "default", + "date": "05/06/2010" + }, + "groupA2": { + "name": "Alice", + "data": [2,3,4], + "date": "05/06/2010" + }, + "groupB2": { + "name": "Bob", + "data": [3,2,1], + "date": "01/02/2003" + }, + "groupA3": { + "name": "Alice", + "data": [2,3,4], + "color": "default", + "date": "04/05/2020" + } + + } +} + diff --git a/testConfigFrameDataIncomplete.json b/testConfigFrameDataIncomplete.json new file mode 100644 index 0000000..7a23a52 --- /dev/null +++ b/testConfigFrameDataIncomplete.json @@ -0,0 +1,64 @@ +{ + "title": "test plot", + "axes": [ + "axis 1", + "axis 2", + "axis 3", + "axis 4" + ], + "animated": true, + "groups": { + "groupA0": { + "name": "Alice", + "data": [1,2,3,4], + "color": "green", + "frame": 0 + }, + "groupB0": { + "name": "Bob", + "data": [2,3,4,3], + "color": "default", + "frame": 0 + }, + "groupC0": { + "name": "Charlie", + "data": [4,3,1,2], + "date": 0 + }, + "groupA1": { + "name": "Alice", + "data": [5,3,2,5], + "color": "default", + "frame": 2 + }, + "groupB1": { + "name": "Bob", + "data": [3,4,2,5], + "color": "default", + "frame": 2 + }, + "groupC1": { + "name": "Charlie", + "data": [6,4,2,2], + "date": 2 + }, + "groupA2": { + "name": "Alice", + "data": [6,7,4,3], + "color": "green", + "frame": 1 + }, + "groupB2": { + "name": "Bob", + "data": [6,5,1,1], + "color": "default", + "frame": 1 + }, + "groupC2": { + "name": "Charlie", + "data": [1,2,1,7], + "date": 1 + } + } +} + diff --git a/testConfigLong.json b/testConfigLong.json new file mode 100644 index 0000000..395130b --- /dev/null +++ b/testConfigLong.json @@ -0,0 +1,64 @@ +{ + "title": "test plot", + "axes": [ + "axis 1", + "axis 2", + "axis 3", + "axis 4" + ], + "animated": true, + "groups": { + "groupA0": { + "name": "Alice", + "data": [1,2,3,4], + "color": "green", + "frame": 0 + }, + "groupB0": { + "name": "Bob", + "data": [2,3,4,3], + "color": "default", + "frame": 0 + }, + "groupC0": { + "name": "Charlie", + "data": [4,3,1,2], + "frame": 0 + }, + "groupA1": { + "name": "Alice", + "data": [5,3,2,5], + "color": "default", + "frame": 2 + }, + "groupB1": { + "name": "Bob", + "data": [3,4,2,5], + "color": "default", + "frame": 2 + }, + "groupC1": { + "name": "Charlie", + "data": [6,4,2,2], + "frame": 2 + }, + "groupA2": { + "name": "Alice", + "data": [6,7,4,3], + "color": "green", + "frame": 1 + }, + "groupB2": { + "name": "Bob", + "data": [6,5,1,1], + "color": "default", + "frame": 1 + }, + "groupC2": { + "name": "Charlie", + "data": [1,2,1,7], + "frame": 1 + } + } +} + From 1d791274e0691b5d7eaa968b26b58b18fdf2b6be Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Wed, 17 Apr 2019 11:18:34 +0100 Subject: [PATCH 06/12] Added the function write_cm_fail to WOPI_config_writer.py for testing colormap errors --- WOPI_config_writer.py | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/WOPI_config_writer.py b/WOPI_config_writer.py index 9070065..ab8aa31 100644 --- a/WOPI_config_writer.py +++ b/WOPI_config_writer.py @@ -32,7 +32,32 @@ def write_heli_data(angles, blades, blade_length=8, fat=True): heli_dict['groups'] = groups return heli_dict -h_dict = write_heli_data(20,4) -file = 'helicopter_3.json' +# h_dict = write_heli_data(20,4) +# file = 'helicopter_3.json' +# +# save_json(h_dict, file) -save_json(h_dict, file) \ No newline at end of file +def write_cm_fail(angles, blade_length=8, fat=True): + base = [1 for x in range(angles)] + axes = ['' for x in range(angles)] + color_dict = {'title': 'colormap example', 'colormap': 'Accent', 'axes': axes} + + groups = dict() + for t in range(angles): + data = base.copy() + data[t] = blade_length + if fat: + data[(t+1) % angles] = blade_length + content = {'data': data,} + g_name = 'color_{}'.format(t) + groups[g_name] = content + color_dict['groups'] = groups + return color_dict + +c_dict_1 = write_cm_fail(9) +c_dict_2 = write_cm_fail(8) +file_1 = 'failed_cm.json' +file_2 = 'succeed_cm.json' + +save_json(c_dict_1, file_1) +save_json(c_dict_2, file_2) \ No newline at end of file From 9382f5c2c9a1f3e2cff995cbd58185d5ee8fe17f Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Wed, 17 Apr 2019 12:44:21 +0100 Subject: [PATCH 07/12] Added config files --- helicopter_3.json | 1 + testConfigEx.json | 45 +++++++++++++++++++++ testConfigFrameDataIncomplete.json | 64 ++++++++++++++++++++++++++++++ testConfigLong.json | 64 ++++++++++++++++++++++++++++++ 4 files changed, 174 insertions(+) create mode 100644 helicopter_3.json create mode 100644 testConfigEx.json create mode 100644 testConfigFrameDataIncomplete.json create mode 100644 testConfigLong.json diff --git a/helicopter_3.json b/helicopter_3.json new file mode 100644 index 0000000..44ee355 --- /dev/null +++ b/helicopter_3.json @@ -0,0 +1 @@ +{"title": "helicopter", "colormap": "jet", "axes": ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""], "animated": true, "frame_length": 40, "groups": {"group_0_0": {"name": "blade_0", "data": [8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 0}, "group_1_0": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 0}, "group_2_0": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 0}, "group_3_0": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1], "frame": 0}, "group_0_1": {"name": "blade_0", "data": [1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 1}, "group_1_1": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 1}, "group_2_1": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1], "frame": 1}, "group_3_1": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1], "frame": 1}, "group_0_2": {"name": "blade_0", "data": [1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 2}, "group_1_2": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 2}, "group_2_2": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1], "frame": 2}, "group_3_2": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1], "frame": 2}, "group_0_3": {"name": "blade_0", "data": [1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 3}, "group_1_3": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 3}, "group_2_3": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1], "frame": 3}, "group_3_3": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8], "frame": 3}, "group_0_4": {"name": "blade_0", "data": [1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 4}, "group_1_4": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 4}, "group_2_4": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1], "frame": 4}, "group_3_4": {"name": "blade_3", "data": [8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8], "frame": 4}, "group_0_5": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 5}, "group_1_5": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 5}, "group_2_5": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1], "frame": 5}, "group_3_5": {"name": "blade_3", "data": [8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 5}, "group_0_6": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 6}, "group_1_6": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1], "frame": 6}, "group_2_6": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1], "frame": 6}, "group_3_6": {"name": "blade_3", "data": [1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 6}, "group_0_7": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 7}, "group_1_7": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1], "frame": 7}, "group_2_7": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1], "frame": 7}, "group_3_7": {"name": "blade_3", "data": [1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 7}, "group_0_8": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 8}, "group_1_8": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1], "frame": 8}, "group_2_8": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8], "frame": 8}, "group_3_8": {"name": "blade_3", "data": [1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 8}, "group_0_9": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 9}, "group_1_9": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1], "frame": 9}, "group_2_9": {"name": "blade_2", "data": [8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8], "frame": 9}, "group_3_9": {"name": "blade_3", "data": [1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 9}, "group_0_10": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 10}, "group_1_10": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1], "frame": 10}, "group_2_10": {"name": "blade_2", "data": [8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 10}, "group_3_10": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 10}, "group_0_11": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1], "frame": 11}, "group_1_11": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1], "frame": 11}, "group_2_11": {"name": "blade_2", "data": [1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 11}, "group_3_11": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 11}, "group_0_12": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1], "frame": 12}, "group_1_12": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1], "frame": 12}, "group_2_12": {"name": "blade_2", "data": [1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 12}, "group_3_12": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 12}, "group_0_13": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1], "frame": 13}, "group_1_13": {"name": "blade_1", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8], "frame": 13}, "group_2_13": {"name": "blade_2", "data": [1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 13}, "group_3_13": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 13}, "group_0_14": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1], "frame": 14}, "group_1_14": {"name": "blade_1", "data": [8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8], "frame": 14}, "group_2_14": {"name": "blade_2", "data": [1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 14}, "group_3_14": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 14}, "group_0_15": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1], "frame": 15}, "group_1_15": {"name": "blade_1", "data": [8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 15}, "group_2_15": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 15}, "group_3_15": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 15}, "group_0_16": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1], "frame": 16}, "group_1_16": {"name": "blade_1", "data": [1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 16}, "group_2_16": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 16}, "group_3_16": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1], "frame": 16}, "group_0_17": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1], "frame": 17}, "group_1_17": {"name": "blade_1", "data": [1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 17}, "group_2_17": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 17}, "group_3_17": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1], "frame": 17}, "group_0_18": {"name": "blade_0", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8], "frame": 18}, "group_1_18": {"name": "blade_1", "data": [1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 18}, "group_2_18": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 18}, "group_3_18": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1], "frame": 18}, "group_0_19": {"name": "blade_0", "data": [8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8], "frame": 19}, "group_1_19": {"name": "blade_1", "data": [1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 19}, "group_2_19": {"name": "blade_2", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1], "frame": 19}, "group_3_19": {"name": "blade_3", "data": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 8, 1, 1, 1, 1], "frame": 19}}} \ No newline at end of file diff --git a/testConfigEx.json b/testConfigEx.json new file mode 100644 index 0000000..6996b54 --- /dev/null +++ b/testConfigEx.json @@ -0,0 +1,45 @@ +{ + "title": "test plot", + "axes": [ + "axis 1", + "axis 2", + "axis 3" + ], + "animated": true, + "groups": { + "groupA": { + "name": "Alice", + "data": [1,2,3], + "color": "blue", + "date": "01/02/2003" + }, + "groupB": { + "name": "Bob", + "data": [4,3,1], + "date": "04/05/2020" + }, + "groupC": { + "data": [4,3,1], + "color": "default", + "date": "05/06/2010" + }, + "groupA2": { + "name": "Alice", + "data": [2,3,4], + "date": "05/06/2010" + }, + "groupB2": { + "name": "Bob", + "data": [3,2,1], + "date": "01/02/2003" + }, + "groupA3": { + "name": "Alice", + "data": [2,3,4], + "color": "default", + "date": "04/05/2020" + } + + } +} + diff --git a/testConfigFrameDataIncomplete.json b/testConfigFrameDataIncomplete.json new file mode 100644 index 0000000..7a23a52 --- /dev/null +++ b/testConfigFrameDataIncomplete.json @@ -0,0 +1,64 @@ +{ + "title": "test plot", + "axes": [ + "axis 1", + "axis 2", + "axis 3", + "axis 4" + ], + "animated": true, + "groups": { + "groupA0": { + "name": "Alice", + "data": [1,2,3,4], + "color": "green", + "frame": 0 + }, + "groupB0": { + "name": "Bob", + "data": [2,3,4,3], + "color": "default", + "frame": 0 + }, + "groupC0": { + "name": "Charlie", + "data": [4,3,1,2], + "date": 0 + }, + "groupA1": { + "name": "Alice", + "data": [5,3,2,5], + "color": "default", + "frame": 2 + }, + "groupB1": { + "name": "Bob", + "data": [3,4,2,5], + "color": "default", + "frame": 2 + }, + "groupC1": { + "name": "Charlie", + "data": [6,4,2,2], + "date": 2 + }, + "groupA2": { + "name": "Alice", + "data": [6,7,4,3], + "color": "green", + "frame": 1 + }, + "groupB2": { + "name": "Bob", + "data": [6,5,1,1], + "color": "default", + "frame": 1 + }, + "groupC2": { + "name": "Charlie", + "data": [1,2,1,7], + "date": 1 + } + } +} + diff --git a/testConfigLong.json b/testConfigLong.json new file mode 100644 index 0000000..395130b --- /dev/null +++ b/testConfigLong.json @@ -0,0 +1,64 @@ +{ + "title": "test plot", + "axes": [ + "axis 1", + "axis 2", + "axis 3", + "axis 4" + ], + "animated": true, + "groups": { + "groupA0": { + "name": "Alice", + "data": [1,2,3,4], + "color": "green", + "frame": 0 + }, + "groupB0": { + "name": "Bob", + "data": [2,3,4,3], + "color": "default", + "frame": 0 + }, + "groupC0": { + "name": "Charlie", + "data": [4,3,1,2], + "frame": 0 + }, + "groupA1": { + "name": "Alice", + "data": [5,3,2,5], + "color": "default", + "frame": 2 + }, + "groupB1": { + "name": "Bob", + "data": [3,4,2,5], + "color": "default", + "frame": 2 + }, + "groupC1": { + "name": "Charlie", + "data": [6,4,2,2], + "frame": 2 + }, + "groupA2": { + "name": "Alice", + "data": [6,7,4,3], + "color": "green", + "frame": 1 + }, + "groupB2": { + "name": "Bob", + "data": [6,5,1,1], + "color": "default", + "frame": 1 + }, + "groupC2": { + "name": "Charlie", + "data": [1,2,1,7], + "frame": 1 + } + } +} + From b4a45bb6c99ff6efdc26513e7cd0284bdb17b8c8 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Wed, 17 Apr 2019 13:09:54 +0100 Subject: [PATCH 08/12] reorder functions, add checkType, other small changes --- my-WOPI.py | 124 ++++++++++++++++++++++++++++------------------------- 1 file changed, 66 insertions(+), 58 deletions(-) diff --git a/my-WOPI.py b/my-WOPI.py index 0dcd9b7..98a24d4 100644 --- a/my-WOPI.py +++ b/my-WOPI.py @@ -7,6 +7,45 @@ import numpy as np import datetime + +def parseCommands(): + """ + Parses commands from the command line. + + Returns: + * argparse.ArgumentParser object + """ + parser = argparse.ArgumentParser() + parser.add_argument("-c", "--config", type=str, + help="config file") + parser.add_argument("-s", "--save", type=str, + help="save plot as an image") + args = parser.parse_args() + return args + + +def setConfig(config_file): + """ + Reads config file location from args, extracts json file to dict. + + Args: + + * args () + + Returns: + dict + """ + with open(config_file) as json_file: + config = json.load(json_file) + cleanConfig(config) + return config + + +def checkType(dict_, key, type_): + if type(dict_[key]) is not type_: + raise Exception("{0} does not have type {1}. {0} had type {2}".format(key, type_, type(dict_[key]))) + + def cleanConfig(config): """ Cleans the configuration data and raises exceptions where appropriate. @@ -17,23 +56,23 @@ def cleanConfig(config): """ if 'title' not in config: config['title'] = '' + checkType(config, 'title', str) if 'axes' not in config: raise Exception("'axes' does not exist in config file.") - else: - if type(config['axes']) is not list: - raise Exception("'axes' should be a list. 'axes' had type: {}".format(type(config['axes']))) + checkType(config, 'axes', list) + if len(config['axes']) == 0: + raise Exception("'axes' should contain at least one axis.") if 'groups' not in config: raise Exception("'groups' does not exist in config file.") - if type(config['groups']) is not dict: - raise Exception("'groups' should be a dict. 'axes' had type: {}".format(type(config['groups']))) + checkType(config, 'groups', dict) if 'animated' not in config: config['animated'] = False - if type(config['animated']) is not bool: - raise Exception("'animated' should be a bool value. 'animated' had type {}".format(type(config['animated']))) + checkType(config, 'animated', bool) if 'colormap' not in config: config['colormap'] = 'tab20' if 'frame_length' not in config: config['frame_length'] = 400 + checkType(config, 'frame_length', int) date_dict = dict() frames_missing = False @@ -42,7 +81,7 @@ def cleanConfig(config): data_set = set() for group, content in config['groups'].items(): if type(content) is not dict: - raise Exception("{0} should be a dict. {0} had type: {1}".format(type(content),group)) + raise Exception("{0} should be a dict. {0} had type: {1}".format(type(content), group)) if 'name' not in content: content['name'] = group name_set.add(content['name']) @@ -54,7 +93,7 @@ def cleanConfig(config): raise Exception("the size of data in group '{}' conflicts with the number of axes" .format(group)) for x in content['data']: - if not isinstance(x,(int, float)): + if not isinstance(x, (int, float)): raise Exception("data in group'{}' is not numerical".format(group)) data_set.add(x) if config['animated']: @@ -72,13 +111,15 @@ def cleanConfig(config): else: content['frame'] = 0 if 'max' not in config: - config['max'] = max(data_set) + 1 + config['max'] = int(max(data_set) + 1) if 'min' not in config: - config['min'] = min(data_set) - 1 + config['min'] = int(min(data_set) - 1) + if config['min'] > 0: + config['min'] = 0 if config['animated']: if has_frames and frames_missing: - raise Exception("frame data is incomplete") + raise Exception("'frame' data is incomplete") # if frames_missing is True and an exception has not been raised then all groups must have dates. # 'frame' data is then assumed to be in chronological order and the config file is updated accordingly. if not has_frames: @@ -93,8 +134,8 @@ def cleanConfig(config): # if no color is specified for a group then one will be assigned. If there is a group with the same name which # already has a color, this one will be assigned, otherwise one will be chosen using the specified colormap. # Colors must be the same for all groups with the same name. Colors must be distinct on each frame. - cm = matplotlib.cm.get_cmap(config['colormap']) - palette = [matplotlib.colors.to_rgb(cm(x/len(name_set))) for x in range(len(name_set))] + cm = matplotlib.cm.get_cmap(config['colormap']) + palette = [matplotlib.colors.to_rgb(cm(x / len(name_set))) for x in range(len(name_set))] color_set = set() color_frame_dict = dict() name_color_dict = dict() @@ -109,22 +150,22 @@ def cleanConfig(config): # Colors are normalized to rgb so they can be compared. normalized_color = matplotlib.colors.to_rgb(content['color']) color_set.add(normalized_color) - if (normalized_color,content['frame']) in color_frame_dict: + if (normalized_color, content['frame']) in color_frame_dict: raise Exception("group '{}' has shares a conflicting color with group '{}'" - .format(group,color_frame_dict[(normalized_color,content['frame'])])) + .format(group, color_frame_dict[(normalized_color, content['frame'])])) else: - color_frame_dict[(normalized_color,content['frame'])] = group + color_frame_dict[(normalized_color, content['frame'])] = group if content['name'] in name_color_dict: if content['color'] != name_color_dict[content['name']]: raise Exception("the group name '{}' is assigned two different colors" .format(content['name'])) else: name_color_dict[content['name']] = content['color'] - if (content['name'],content['frame']) in name_frame_set: + if (content['name'], content['frame']) in name_frame_set: raise Exception("two groups share the name '{}' and the frame '{}'" - .format(content['name'],content['frame'])) + .format(content['name'], content['frame'])) else: - name_frame_set.add((content['name'],content['frame'])) + name_frame_set.add((content['name'], content['frame'])) for group, content in config['groups'].items(): if content['color'] == 'default': if content['name'] in name_color_dict: @@ -155,51 +196,19 @@ def orderFrames(config): """ frame_dict = dict() for group, content in config['groups'].items(): - frame_dict.setdefault(content['frame'],[]).append(group) + frame_dict.setdefault(content['frame'], []).append(group) ordered_frame_list = sorted(frame_dict) min_ = ordered_frame_list[0] max_ = ordered_frame_list[-1] - total_frame_list = [frame_dict[frame+min_] if frame+min_ in frame_dict else (frame,[]) + total_frame_list = [frame_dict[frame+min_] if frame+min_ in frame_dict else [] for frame in range(max_-min_+1)] return total_frame_list -def parseCommands(): - """ - Parses commands from the command line. - - Returns: - * argparse.ArgumentParser object - """ - parser = argparse.ArgumentParser() - parser.add_argument("-c", "--config", type=str, - help="config file") - parser.add_argument("-s", "--save", type=str, - help="save plot as an image") - args = parser.parse_args() - return args - - -def setConfig(args): - """ - Reads config file location from args, extracts json file to dict. - - Args: - - * args () - - Returns: - dict - """ - with open(args.config) as json_file: - config = json.load(json_file) - cleanConfig(config) - return config - - def main(): + """Reads a config file specified in the command line and creates a radar plot from the data.""" args = parseCommands() - config = setConfig(args) + config = setConfig(args.config) frame_list = orderFrames(config) number_of_axes = len(config['axes']) @@ -220,7 +229,7 @@ def update_fig(i): for group in group_list: patch_color = config['groups'][group]['color'] values = config['groups'][group]['data'] - polygon_coords = np.array(list(zip(angles,values))) + polygon_coords = np.array(list(zip(angles, values))) polygon = matplotlib.patches.Polygon(polygon_coords, color=patch_color, alpha=0.4, label=config['groups'][group]['name']) @@ -233,7 +242,6 @@ def update_fig(i): if config['animated']: ani = animation.FuncAnimation(fig, update_fig, len(frame_list), interval=config['frame_length'], repeat=True) - if args.save is None: plt.show() else: From c7964bddd3d94894479655b031f6823fa7bd475c Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Wed, 24 Apr 2019 11:56:40 +0100 Subject: [PATCH 09/12] main method now hidden locally --- my-WOPI.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/my-WOPI.py b/my-WOPI.py index 98a24d4..13a1aed 100644 --- a/my-WOPI.py +++ b/my-WOPI.py @@ -251,4 +251,7 @@ def update_fig(i): ani.save(args.save) -main() +# main() + +if __name__ == "__main__": + main() From 95b4fc9fbc8e8643c238128347ed5de814bd4f5c Mon Sep 17 00:00:00 2001 From: stephenworsley <49274989+stephenworsley@users.noreply.github.com> Date: Wed, 24 Apr 2019 11:59:08 +0100 Subject: [PATCH 10/12] got rid of commented main call --- my-WOPI.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/my-WOPI.py b/my-WOPI.py index 13a1aed..a920977 100644 --- a/my-WOPI.py +++ b/my-WOPI.py @@ -251,7 +251,5 @@ def update_fig(i): ani.save(args.save) -# main() - if __name__ == "__main__": main() From efd5bd78bc732fe58398509913a0a2f58d5dc529 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Tue, 30 Apr 2019 11:16:19 +0100 Subject: [PATCH 11/12] added comments and docstring to checkType --- my-WOPI.py | 27 ++++++++++++++++++++------- test_my-WOPI.py | 7 +++++++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/my-WOPI.py b/my-WOPI.py index a920977..fbb60be 100644 --- a/my-WOPI.py +++ b/my-WOPI.py @@ -13,7 +13,7 @@ def parseCommands(): Parses commands from the command line. Returns: - * argparse.ArgumentParser object + argparse.ArgumentParser object """ parser = argparse.ArgumentParser() parser.add_argument("-c", "--config", type=str, @@ -30,7 +30,7 @@ def setConfig(config_file): Args: - * args () + * config_file (string) Returns: dict @@ -42,6 +42,15 @@ def setConfig(config_file): def checkType(dict_, key, type_): + """ + Raises appropriate exception if the key points to the wrong type of value + + Args: + + * dict_ (dict) + * key (string) + * type_ (type) + """ if type(dict_[key]) is not type_: raise Exception("{0} does not have type {1}. {0} had type {2}".format(key, type_, type(dict_[key]))) @@ -74,7 +83,7 @@ def cleanConfig(config): config['frame_length'] = 400 checkType(config, 'frame_length', int) - date_dict = dict() + date_dict = dict() # keys are dates, values are all groups with that date frames_missing = False has_frames = False name_set = set() @@ -97,6 +106,7 @@ def cleanConfig(config): raise Exception("data in group'{}' is not numerical".format(group)) data_set.add(x) if config['animated']: + # extract enough information to be sure we can assign a frame to each group later if not ('date' in content or 'frame' in content): raise Exception("insufficient data in group '{}' to assign a frame" .format(group)) @@ -110,6 +120,7 @@ def cleanConfig(config): frames_missing = True else: content['frame'] = 0 + # pad the range of the plot appropriately if 'max' not in config: config['max'] = int(max(data_set) + 1) if 'min' not in config: @@ -137,11 +148,10 @@ def cleanConfig(config): cm = matplotlib.cm.get_cmap(config['colormap']) palette = [matplotlib.colors.to_rgb(cm(x / len(name_set))) for x in range(len(name_set))] color_set = set() - color_frame_dict = dict() - name_color_dict = dict() - name_frame_set = set() + color_frame_dict = dict() # keys are tuples of rgb color and frame, values are groups + name_color_dict = dict() # keys are names, values are colors (rgb) + name_frame_set = set() # elements are tuples of name and frame where these belong to the same group for group, content in config['groups'].items(): - if 'color' not in content: content['color'] = 'default' elif content['color'] != 'default': @@ -167,6 +177,8 @@ def cleanConfig(config): else: name_frame_set.add((content['name'], content['frame'])) for group, content in config['groups'].items(): + # colors are assigned to all groups, first checking for colors assigned to groups with the same name, + # otherwise choosing a color taken from our colormap if content['color'] == 'default': if content['name'] in name_color_dict: content['color'] = name_color_dict[content['name']] @@ -248,6 +260,7 @@ def update_fig(i): if not config['animated']: plt.savefig(args.save, format='png') else: + # animations do not seem to save properly ani.save(args.save) diff --git a/test_my-WOPI.py b/test_my-WOPI.py index e69de29..22244a7 100644 --- a/test_my-WOPI.py +++ b/test_my-WOPI.py @@ -0,0 +1,7 @@ +myWOPI = __import__("my-WOPI") +import pytest + +def test_checkType(): + td = {"goodkey":"badvalue"} + with pytest.raises(Exception): + my-WOPI.checkType(td,"goodkey",int) \ No newline at end of file From a391234a7cfc595032b0b030976896549ab8ba22 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Tue, 30 Apr 2019 11:22:31 +0100 Subject: [PATCH 12/12] added comment and tidied up whitespace --- my-WOPI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/my-WOPI.py b/my-WOPI.py index fbb60be..77cc539 100644 --- a/my-WOPI.py +++ b/my-WOPI.py @@ -242,13 +242,13 @@ def update_fig(i): patch_color = config['groups'][group]['color'] values = config['groups'][group]['data'] polygon_coords = np.array(list(zip(angles, values))) - polygon = matplotlib.patches.Polygon(polygon_coords, color=patch_color, alpha=0.4, label=config['groups'][group]['name']) ax.add_patch(polygon) ax.legend(loc='lower right') plt.draw() + # initialise the first frame of the animation if animated, plot if otherwise update_fig(0) if config['animated']: