def generate_chart_image(chart_data_dict: dict) -> Path: """ Create the chart image with given input, return image Path. :param chart_data_dict: dict :return: Path object """ fig = plt.figure(figsize=(19.20, 10.80)) # set proportion/size in inches, 1080p ax = plt.subplot(xlim=(-0, 105), ylim=(-0, 100)) plt.subplots_adjust(left=0.05, right=0.95, top=0.9, bottom=0.1, wspace=0.01, hspace=0.01) # TODO: hide vertical axis, top and right border lines. set_axis() ax.grid(False) # No grid # if custom chart parameters affecting avatar layout, # pass chart_data_dict['chart_params'] to generate_avatar_coords avatar_coord_dict = generate_avatar_coords( chart_data_dict['score-students_dict'], chart_data_dict['class_id']) add_avatars_to_plot(ax, avatar_coord_dict) image_location = definitions.DATABASE.save_chart_image( chart_data_dict, plt) return image_location
def generate_chart_image(chart_data_dict: dict): """ Create the chart image with given input. :param chart_data_dict: dict :return: None """ fig = plt.figure(figsize=(16, 9)) # set proportion/size in inches, ax = plt.subplot(xlim=(-0, 105), ylim=(-0, 100)) plt.subplots_adjust(left=0.05, right=0.95, top=0.9, bottom=0.1, wspace=0.01, hspace=0.01) # TODO: hide vertical axis, top and right border lines. set_axis() ax.grid(False) # No grid # if custom chart parameters affecting avatar layout, pass chart_data_dict['chart_params'] to generate_avatar_coords # nominally, avatar_coord_dict will be chart_data_dict['score-avatar_dict'] avatar_coord_dict = generate_avatar_coords( chart_data_dict['score-avatar_dict']) add_avatars_to_plot(ax, avatar_coord_dict) image_location = save_chart_image(chart_data_dict) return image_location
def generate_chart_image(chart_data_dict: dict): """ :param chart_data_dict: dict :return: None """ fig = plt.figure(figsize=(16, 9)) # set proportion/size in inches, ax = plt.subplot(xlim=(-0, 105), ylim=(-0, 100)) plt.subplots_adjust(left=0.05, right=0.95, top=0.9, bottom=0.1, wspace=0.01, hspace=0.01) # TODO: hide vertical axis, top and right border lines. set_axis() ax.grid(False) # No grid # if custom chart parameters affecting avatar layout, pass chart_data_dict['chart_params'] to generate_avatar_coords # nominally, avatar_coord_dict will be chart_data_dict['score-avatar_dict'] avatar_coord_dict = generate_avatar_coords( chart_data_dict['score-avatar_dict']) add_avatars_to_plot(ax, avatar_coord_dict) # Maximise displayed image. mng = plt.get_current_fig_manager() mng.window.state("zoomed") # Show image. plt.show() save_chart_image(chart_data_dict)
def test_generate_avatar_coords(self): test_generate_avatar_coords_result = { 'foo': [(0.0, 5), (10.0, 35)], 'spam': [(0.0, 15), (10.0, 45)], 'dead': [(0.0, 25), (10.0, 55)], 'parrot': [(0.0, 35), (10.0, 65)], 'halibut': [(0.0, 45), (10.0, 75)], 'patties': [(0.0, 55), (10.0, 85)], 'original': [(10.0, 5)], 'recipe': [(10.0, 15)], 'chicken': [(10.0, 25)], } assert generate_avatar_coords( self.test_score_avatar_dict) == test_generate_avatar_coords_result
def test_generate_avatar_coords_backends(self, request, monkeypatch, database_backend): test_database = request.getfixturevalue(database_backend) test_database.default_avatar_path = 'mocked_default_avatar_path' test_existing_class = NewClass.from_dict( test_full_class_data_set['json_dict_rep']) for student in test_existing_class: if student.avatar_id: Path(test_existing_class.temp_avatars_dir, student.avatar_id).write_text(student.avatar_id) # Create class in db: test_database.create_class(test_existing_class) # Find class id to load: classes = test_database.get_classes() test_class_id = classes[0].id # test_class = Class.from_dict(test_full_class_data_set['json_dict_rep']) test_class = test_database.load_class(test_class_id) monkeypatch.setattr(process_chart_data.definitions, 'DATABASE', test_database) # student_score_entry_sequence = [0, 1, 3, None, 50, 99, 100, 1, 2, 3, 4, None, 6, 7, 8] test_student_scores_dict = { 0: [test_class.students[0]], # Cali 1: [ test_class.students[1], # Monty test_class.students[7] ], # Regina 3: [ test_class.students[2], # Abby test_class.students[9] ], # Alex # No score, not returned: None: [test_class.students[3], # Zach # test_class.students[11]], # Edgar 50: [test_class.students[4]], # Janell 99: [test_class.students[5]], # Matthew 100: [test_class.students[6]], # Olivia 2: [test_class.students[8]], # Ashley 4: [test_class.students[10]], # Melissa 6: [test_class.students[12]], # Danielle 7: [test_class.students[13]], # Kayla 8: [test_class.students[14]], # Jaleigh } # Vary calls for actual avatars based on backend. test_generate_avatar_coords_result = { **{ 'mocked_default_avatar_path': [(0.0, 15), (0.0, 25), (0.0, 45), (0.0, 55), (0.0, 65), (10.0, 15), (10.0, 25), (50.0, 5), (100.0, 5), (100.0, 15)], }, **({ test_database.get_avatar_path_class_filename( test_class.id, test_class.students[8].avatar_id): [(0.0, 35)], # Ashley test_database.get_avatar_path_class_filename( test_class.id, test_class.students[0].avatar_id): [(0.0, 5)], # Cali test_database.get_avatar_path_class_filename( test_class.id, test_class.students[12].avatar_id): [(10.0, 5)], # Danielle } if isinstance(test_database, JSONDatabase) else { test_database.get_avatar_path(test_class.students[8].avatar_id): [(0.0, 35)], # Ashley test_database.get_avatar_path(test_class.students[0].avatar_id): [(0.0, 5)], # Cali test_database.get_avatar_path(test_class.students[12].avatar_id): [(10.0, 5)], # Danielle }), } assert generate_avatar_coords( test_student_scores_dict, test_class.id) == test_generate_avatar_coords_result
def test_generate_avatar_coords_generic_api(self, monkeypatch, empty_generic_database): test_database = empty_generic_database test_database.default_avatar_path = 'mocked_default_avatar_path' test_class = Class.from_dict(test_full_class_data_set['json_dict_rep']) student_score_entry_sequence = [ 0, 1, 3, None, 50, 99, 100, 1, 2, 3, 4, None, 6, 7, 8 ] # Mock out avatar_paths with readable strings. avatar_paths = [ f'path to {student.avatar_id}' if student.avatar_id is not None else test_database.default_avatar_path for student in test_class.students ] # Format those avatar_paths to remove students who did not submit a score: mocked_get_avatar_path_return_values = [ avatar_paths[student_score_entry_sequence.index(score)] for score in student_score_entry_sequence if score is not None ] avatar_path = (path for path in mocked_get_avatar_path_return_values) avatar_ids = [student.avatar_id for student in test_class] def mocked_get_avatar_path(avatar_id): """ Strictly speaking does not need a mock, as should raise error, but re-mocking method for clarity. """ assert avatar_id in avatar_ids # deepcode ignore unguarded~next~call: No guard - let error propagate, should not reach StopIteration. return next(avatar_path) test_database.get_avatar_path = mocked_get_avatar_path monkeypatch.setattr(process_chart_data.definitions, 'DATABASE', test_database) test_student_scores_dict = { 0: [test_class.students[0]], # Cali 1: [ test_class.students[1], # Monty test_class.students[7] ], # Regina 3: [ test_class.students[2], # Abby test_class.students[9] ], # Alex # No score, not returned: None: [test_class.students[3], # Zach # test_class.students[11]], # Edgar 50: [test_class.students[4]], # Janell 99: [test_class.students[5]], # Matthew 100: [test_class.students[6]], # Olivia 2: [test_class.students[8]], # Ashley 4: [test_class.students[10]], # Melissa 6: [test_class.students[12]], # Danielle 7: [test_class.students[13]], # Kayla 8: [test_class.students[14]], # Jaleigh } test_generate_avatar_coords_result = { 'mocked_default_avatar_path': [(0.0, 15), (0.0, 25), (0.0, 35), (0.0, 45), (0.0, 55), (0.0, 65), (10.0, 15), (10.0, 25), (50.0, 5), (100.0, 5)], 'path to Ashley_avatar.png': [(100.0, 15)], 'path to Cali_avatar.png': [(0.0, 5)], 'path to Danielle_avatar.png': [(10.0, 5)] } assert generate_avatar_coords( test_student_scores_dict, test_class.id) == test_generate_avatar_coords_result