From bfcaa77b8e6614b38aa340c40ea35026bf5e6cc4 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Wed, 18 Sep 2024 17:09:58 +0200 Subject: [PATCH 1/7] Add plots for blocks and vehicle services --- simba/report.py | 148 +++++++++++++++++++++++++++++++++++++++++++++++- simba/util.py | 13 +++++ 2 files changed, 160 insertions(+), 1 deletion(-) diff --git a/simba/report.py b/simba/report.py index a44c7d17..000a1c02 100644 --- a/simba/report.py +++ b/simba/report.py @@ -6,10 +6,14 @@ import re from typing import Iterable +import matplotlib.colors import matplotlib.pyplot as plt +import matplotlib.dates as mdates from spice_ev.report import aggregate_global_results, plot, generate_reports, aggregate_timeseries from spice_ev.util import sanitize +from simba import util + def open_for_csv(file_path): """ Create a file handle to write to. @@ -191,6 +195,9 @@ def generate_plots(schedule, scenario, args): extended_plots_path = args.results_directory.joinpath("extended_plots") extended_plots_path.mkdir(parents=True, exist_ok=True) + plot_blocks_dense(schedule, extended_plots_path) + plot_vehicle_services(schedule, extended_plots_path) + plot_consumption_per_rotation_distribution(extended_plots_path, schedule) plot_distance_per_rotation_distribution(extended_plots_path, schedule) plot_charge_type_distribution(extended_plots_path, scenario, schedule) @@ -596,12 +603,151 @@ def plot_gc_power_timeseries(extended_plots_path, scenario): # xaxis are datetime strings ax.set_xlim(time_values[0], time_values[-1]) - ax.tick_params(axis='x', rotation=30) + # ax.tick_params(axis='x', rotation=30) plt.savefig(extended_plots_path / f"{sanitize(gc)}_power_time_overview.png") plt.close(fig) +def plot_vehicle_services(schedule, output_path): + """Plots the rotations serviced by the same vehicle + + :param schedule: Provides the schedule data. + :type schedule; simba.schedule.Schedule + :param output_path: Path to the output folder + :type output_path: pathlib.Path + """ + + # find depots for every rotation + all_rotations = schedule.rotations + rotations_per_depot = {r.departure_name: [] for r in all_rotations.values()} + for rotation in all_rotations.values(): + rotations_per_depot[rotation.departure_name].append(rotation) + + def color_generator(): + # generates color according to vehicle_type and charging type of rotation + colors = util.cycling_generator(plt.rcParams['axes.prop_cycle'].by_key()["color"]) + color_per_vt = {vt: next(colors) for vt in schedule.vehicle_types} + color = None + while True: + rotation = yield color + color = color_per_vt[rotation.vehicle_type] + rgb = matplotlib.colors.to_rgb(color) + hsv = matplotlib.colors.rgb_to_hsv(rgb) + if rotation.charging_type == "depb": + pass + elif rotation.charging_type == "oppb": + hsv[-1] /= 2 + else: + raise NotImplementedError + color = matplotlib.colors.hsv_to_rgb(hsv) + + def vehicle_id_row_generator(): + # generate row ids by using the vehicle_id of the rotation + vehicle_id = None + while True: + rotation = yield vehicle_id + vehicle_id = rotation.vehicle_id + + # create instances of the generators + dense_row_generator = vehicle_id_row_generator() + color_gen = color_generator() + # initialize row_generator by yielding None + next(dense_row_generator) + next(color_gen) + + rotations_per_depot["All_Depots"] = all_rotations.values() + + output_path_folder = output_path / "vehicle_services" + output_path_folder.mkdir(parents=True, exist_ok=True) + for depot, rotations in rotations_per_depot.items(): + sorted_rotations = list( + sorted(rotations, + key=lambda x: (x.vehicle_type, x.charging_type, x.departure_time))) + fig, ax = create_plot_blocks(sorted_rotations, color_gen, dense_row_generator) + ax.set_xlabel("Vehicle ID") + ax.set_xlabel("Block") + fig.savefig(output_path_folder / f"{sanitize(depot)}_vehicle_services.png") + plt.close(fig) + + +def plot_blocks_dense(schedule, output_path): + """Plots the different loads (total, feedin, external) of all grid connectors. + + :param schedule: Provides the schedule data. + :type schedule; simba.schedule.Schedule + :param output_path: Path to the output folder + :type output_path: pathlib.Path + """ + # find depots for every rotation + all_rotations = schedule.rotations + rotations_per_depot = {r.departure_name: [] for r in all_rotations.values()} + for rotation in all_rotations.values(): + rotations_per_depot[rotation.departure_name].append(rotation) + + def color_generator(): + # Generates color according to rotation vehicle_type + + colors = util.cycling_generator(plt.rcParams['axes.prop_cycle'].by_key()["color"]) + color_per_vt = {vt: next(colors) for vt in schedule.vehicle_types} + color = None + while True: + rotation = yield color + color = color_per_vt[rotation.vehicle_type] + + def dense_row_generator(): + # Generates row id by trying to find lowes row with a rotation which arrived + arrival_times = [] + row_nr = None + while True: + rotation = yield row_nr + for i in range(len(arrival_times)): + at = arrival_times[i] + if at <= rotation.departure_time: + arrival_times[i] = rotation.arrival_time + row_nr = i + break + else: + arrival_times.append(rotation.arrival_time) + row_nr = len(arrival_times) - 1 + + rotations_per_depot["All_Depots"] = all_rotations.values() + # create instances of the generators + dense_row_generator = dense_row_generator() + color_gen = color_generator() + # initialize row_generator by yielding None + next(dense_row_generator) + next(color_gen) + output_path_folder = output_path / "block_distribution" + output_path_folder.mkdir(parents=True, exist_ok=True) + for depot, rotations in rotations_per_depot.items(): + fig, ax = create_plot_blocks(rotations, color_gen, dense_row_generator) + ax.set_xlabel("Block") + fig.savefig(output_path_folder / f"{sanitize(depot)}_block_distribution.png") + plt.close(fig) + + +def create_plot_blocks(rotations, color_generator, row_generator): + fig, ax = plt.subplots() + rotations = list(sorted(rotations, key=lambda r: r.departure_time)) + for rotation in rotations: + row_nr = row_generator.send(rotation) + width = rotation.arrival_time - rotation.departure_time + artist = ax.barh([row_nr], width=[width], height=0.8, left=rotation.departure_time, + label=rotation.id, color=color_generator.send(rotation)) + ax.bar_label(artist, labels=[rotation.id], label_type='center') + + ax.xaxis.set_major_locator(mdates.AutoDateLocator()) + ax.xaxis.set_major_formatter(mdates.DateFormatter('%D %H:%M')) + ax.yaxis.get_major_locator().set_params(integer=True) + ax.set_xlim(min(r.departure_time for r in rotations) - datetime.timedelta(minutes=10), + max(r.arrival_time for r in rotations) + datetime.timedelta(minutes=10)) + ax.set_xticklabels(ax.get_xticklabels(), rotation=30, ha='right') + ax.set_xlabel('Time') + fig.tight_layout() + return fig, ax + + def count_active_rotations(scenario, schedule): num_active_rotations = [0] * scenario.n_intervals for rotation in schedule.rotations.values(): diff --git a/simba/util.py b/simba/util.py index dcecc07f..e2afdce0 100644 --- a/simba/util.py +++ b/simba/util.py @@ -259,6 +259,19 @@ def cast_float_or_none(val: any) -> any: return None +def cycling_generator(cycle: []): + """Generator to loop over lists + :param cycle: list to cycle through + :type cycle: list() + :yields: iterated value + :rtype: Iterator[any] + """ + i = 0 + while True: + yield cycle[i % len(cycle)] + i += 1 + + def setup_logging(args, time_str): """ Setup logging. From afcc9c8e15f76002694384f17f4a90314596d277 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Thu, 19 Sep 2024 12:45:32 +0200 Subject: [PATCH 2/7] Fix sorting of block plots. Fix label size --- simba/report.py | 111 ++++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 60 deletions(-) diff --git a/simba/report.py b/simba/report.py index 000a1c02..93a740f8 100644 --- a/simba/report.py +++ b/simba/report.py @@ -609,6 +609,25 @@ def plot_gc_power_timeseries(extended_plots_path, scenario): plt.close(fig) +def ColorGenerator(vehicle_types): + # generates color according to vehicle_type and charging type of rotation + colors = util.cycling_generator(plt.rcParams['axes.prop_cycle'].by_key()["color"]) + color_per_vt = {vt: next(colors) for vt in vehicle_types} + color = None + while True: + rotation = yield color + color = color_per_vt[rotation.vehicle_type] + rgb = matplotlib.colors.to_rgb(color) + hsv = matplotlib.colors.rgb_to_hsv(rgb) + if rotation.charging_type == "depb": + pass + elif rotation.charging_type == "oppb": + hsv[-1] /= 2 + else: + raise NotImplementedError + color = matplotlib.colors.hsv_to_rgb(hsv) + + def plot_vehicle_services(schedule, output_path): """Plots the rotations serviced by the same vehicle @@ -624,50 +643,30 @@ def plot_vehicle_services(schedule, output_path): for rotation in all_rotations.values(): rotations_per_depot[rotation.departure_name].append(rotation) - def color_generator(): - # generates color according to vehicle_type and charging type of rotation - colors = util.cycling_generator(plt.rcParams['axes.prop_cycle'].by_key()["color"]) - color_per_vt = {vt: next(colors) for vt in schedule.vehicle_types} - color = None - while True: - rotation = yield color - color = color_per_vt[rotation.vehicle_type] - rgb = matplotlib.colors.to_rgb(color) - hsv = matplotlib.colors.rgb_to_hsv(rgb) - if rotation.charging_type == "depb": - pass - elif rotation.charging_type == "oppb": - hsv[-1] /= 2 - else: - raise NotImplementedError - color = matplotlib.colors.hsv_to_rgb(hsv) - - def vehicle_id_row_generator(): + def VehicleIdRowGenerator(): # generate row ids by using the vehicle_id of the rotation vehicle_id = None while True: rotation = yield vehicle_id vehicle_id = rotation.vehicle_id - # create instances of the generators - dense_row_generator = vehicle_id_row_generator() - color_gen = color_generator() - # initialize row_generator by yielding None - next(dense_row_generator) - next(color_gen) - rotations_per_depot["All_Depots"] = all_rotations.values() output_path_folder = output_path / "vehicle_services" output_path_folder.mkdir(parents=True, exist_ok=True) for depot, rotations in rotations_per_depot.items(): + # create instances of the generators + row_generator = VehicleIdRowGenerator() + color_generator = ColorGenerator(schedule.vehicle_types) + sorted_rotations = list( - sorted(rotations, - key=lambda x: (x.vehicle_type, x.charging_type, x.departure_time))) - fig, ax = create_plot_blocks(sorted_rotations, color_gen, dense_row_generator) - ax.set_xlabel("Vehicle ID") - ax.set_xlabel("Block") - fig.savefig(output_path_folder / f"{sanitize(depot)}_vehicle_services.png") + sorted(rotations, key=lambda x: (x.vehicle_type, x.charging_type, x.departure_time))) + fig, ax = create_plot_blocks(sorted_rotations, color_generator, row_generator) + ax.set_ylabel("Vehicle ID") + ax.tick_params(axis='y', labelsize=8) + fig.tight_layout() + # PDF so Block names stay readable + fig.savefig(output_path_folder / f"{sanitize(depot)}_vehicle_services.pdf") plt.close(fig) @@ -685,17 +684,7 @@ def plot_blocks_dense(schedule, output_path): for rotation in all_rotations.values(): rotations_per_depot[rotation.departure_name].append(rotation) - def color_generator(): - # Generates color according to rotation vehicle_type - - colors = util.cycling_generator(plt.rcParams['axes.prop_cycle'].by_key()["color"]) - color_per_vt = {vt: next(colors) for vt in schedule.vehicle_types} - color = None - while True: - rotation = yield color - color = color_per_vt[rotation.vehicle_type] - - def dense_row_generator(): + def DenseRowGenerator(): # Generates row id by trying to find lowes row with a rotation which arrived arrival_times = [] row_nr = None @@ -712,39 +701,41 @@ def dense_row_generator(): row_nr = len(arrival_times) - 1 rotations_per_depot["All_Depots"] = all_rotations.values() - # create instances of the generators - dense_row_generator = dense_row_generator() - color_gen = color_generator() - # initialize row_generator by yielding None - next(dense_row_generator) - next(color_gen) output_path_folder = output_path / "block_distribution" output_path_folder.mkdir(parents=True, exist_ok=True) for depot, rotations in rotations_per_depot.items(): - fig, ax = create_plot_blocks(rotations, color_gen, dense_row_generator) - ax.set_xlabel("Block") - fig.savefig(output_path_folder / f"{sanitize(depot)}_block_distribution.png") + # create instances of the generators + row_generator = DenseRowGenerator() + color_generator = ColorGenerator(schedule.vehicle_types) + # sort by departure_time and longest duration + sorted_rotations = list( + sorted(rotations, key=lambda r: (r.departure_time, -(r.departure_time-r.arrival_time)))) + fig, ax = create_plot_blocks(sorted_rotations, color_generator, row_generator) + ax.set_ylabel("Block") + ax.yaxis.get_major_locator().set_params(integer=True) + fig.tight_layout() + # PDF so Block names stay readable + fig.savefig(output_path_folder / f"{sanitize(depot)}_block_distribution.pdf") plt.close(fig) def create_plot_blocks(rotations, color_generator, row_generator): - fig, ax = plt.subplots() - rotations = list(sorted(rotations, key=lambda r: r.departure_time)) + # initialize row_generator by yielding None + next(row_generator) + next(color_generator) + + fig, ax = plt.subplots(figsize=(5, len(rotations) * 0.02 + 2)) for rotation in rotations: row_nr = row_generator.send(rotation) width = rotation.arrival_time - rotation.departure_time artist = ax.barh([row_nr], width=[width], height=0.8, left=rotation.departure_time, label=rotation.id, color=color_generator.send(rotation)) - ax.bar_label(artist, labels=[rotation.id], label_type='center') - + ax.bar_label(artist, labels=[rotation.id], label_type='center', fontsize=2) ax.xaxis.set_major_locator(mdates.AutoDateLocator()) ax.xaxis.set_major_formatter(mdates.DateFormatter('%D %H:%M')) - ax.yaxis.get_major_locator().set_params(integer=True) ax.set_xlim(min(r.departure_time for r in rotations) - datetime.timedelta(minutes=10), max(r.arrival_time for r in rotations) + datetime.timedelta(minutes=10)) - ax.set_xticklabels(ax.get_xticklabels(), rotation=30, ha='right') - ax.set_xlabel('Time') - fig.tight_layout() + ax.tick_params(axis='x', rotation=30) return fig, ax From 3b78a9d23b1fe5482956e3b46b70e1e5a94832a9 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Thu, 19 Sep 2024 14:21:53 +0200 Subject: [PATCH 3/7] Add legend and add png output --- simba/report.py | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/simba/report.py b/simba/report.py index 93a740f8..27e3cacd 100644 --- a/simba/report.py +++ b/simba/report.py @@ -9,6 +9,7 @@ import matplotlib.colors import matplotlib.pyplot as plt import matplotlib.dates as mdates +from matplotlib.patches import Patch from spice_ev.report import aggregate_global_results, plot, generate_reports, aggregate_timeseries from spice_ev.util import sanitize @@ -619,12 +620,16 @@ def ColorGenerator(vehicle_types): color = color_per_vt[rotation.vehicle_type] rgb = matplotlib.colors.to_rgb(color) hsv = matplotlib.colors.rgb_to_hsv(rgb) + value = hsv[-1] if rotation.charging_type == "depb": - pass + if value >= 0.5: + value -= 0.3 elif rotation.charging_type == "oppb": - hsv[-1] /= 2 + if value < 0.5: + value += 0.3 else: raise NotImplementedError + hsv[-1] = value color = matplotlib.colors.hsv_to_rgb(hsv) @@ -663,10 +668,21 @@ def VehicleIdRowGenerator(): sorted(rotations, key=lambda x: (x.vehicle_type, x.charging_type, x.departure_time))) fig, ax = create_plot_blocks(sorted_rotations, color_generator, row_generator) ax.set_ylabel("Vehicle ID") - ax.tick_params(axis='y', labelsize=8) + # Vehicle ids need small fontsize to fit + ax.tick_params(axis='y', labelsize=6) + # add legend + handles = [] + vts = {f"{rotation.vehicle_type}_{rotation.charging_type}": rotation + for rotation in sorted_rotations} + for key, rot in vts.items(): + handles.append(Patch(color=color_generator.send(rot), label=key)) + # Position legend at the top outside of the plot + ax.legend(handles=handles, loc='lower center', bbox_to_anchor=(0.5, 1), + ncol=len(handles)//2, prop={"size": 7}) fig.tight_layout() # PDF so Block names stay readable fig.savefig(output_path_folder / f"{sanitize(depot)}_vehicle_services.pdf") + fig.savefig(output_path_folder / f"{sanitize(depot)}_vehicle_services.png") plt.close(fig) @@ -709,32 +725,38 @@ def DenseRowGenerator(): color_generator = ColorGenerator(schedule.vehicle_types) # sort by departure_time and longest duration sorted_rotations = list( - sorted(rotations, key=lambda r: (r.departure_time, -(r.departure_time-r.arrival_time)))) + sorted(rotations, + key=lambda r: (r.departure_time, -(r.departure_time - r.arrival_time)))) fig, ax = create_plot_blocks(sorted_rotations, color_generator, row_generator) ax.set_ylabel("Block") ax.yaxis.get_major_locator().set_params(integer=True) + ax.set_ylim(0, 125) fig.tight_layout() # PDF so Block names stay readable fig.savefig(output_path_folder / f"{sanitize(depot)}_block_distribution.pdf") + fig.savefig(output_path_folder / f"{sanitize(depot)}_block_distribution.png") plt.close(fig) -def create_plot_blocks(rotations, color_generator, row_generator): +def create_plot_blocks(sorted_rotations, color_generator, row_generator): # initialize row_generator by yielding None next(row_generator) next(color_generator) - - fig, ax = plt.subplots(figsize=(5, len(rotations) * 0.02 + 2)) - for rotation in rotations: + y_size = len(sorted_rotations) * 0.02 + 1.5 + fig, ax = plt.subplots(figsize=(7, y_size)) + for rotation in sorted_rotations: row_nr = row_generator.send(rotation) width = rotation.arrival_time - rotation.departure_time artist = ax.barh([row_nr], width=[width], height=0.8, left=rotation.departure_time, label=rotation.id, color=color_generator.send(rotation)) ax.bar_label(artist, labels=[rotation.id], label_type='center', fontsize=2) + + # Large heights create too much margin with default value of margins: Reduce value to 0.01 + ax.axes.margins(y=0.01) ax.xaxis.set_major_locator(mdates.AutoDateLocator()) ax.xaxis.set_major_formatter(mdates.DateFormatter('%D %H:%M')) - ax.set_xlim(min(r.departure_time for r in rotations) - datetime.timedelta(minutes=10), - max(r.arrival_time for r in rotations) + datetime.timedelta(minutes=10)) + ax.set_xlim(min(r.departure_time for r in sorted_rotations) - datetime.timedelta(minutes=30), + max(r.arrival_time for r in sorted_rotations) + datetime.timedelta(minutes=30)) ax.tick_params(axis='x', rotation=30) return fig, ax From 605d45294174d31cc0ad85ccad7727e980ac0587 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Thu, 19 Sep 2024 14:29:23 +0200 Subject: [PATCH 4/7] Add legend to blocks_dense --- simba/report.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/simba/report.py b/simba/report.py index 27e3cacd..3953b7fe 100644 --- a/simba/report.py +++ b/simba/report.py @@ -730,7 +730,16 @@ def DenseRowGenerator(): fig, ax = create_plot_blocks(sorted_rotations, color_generator, row_generator) ax.set_ylabel("Block") ax.yaxis.get_major_locator().set_params(integer=True) - ax.set_ylim(0, 125) + # add legend + handles = [] + vts = {f"{rotation.vehicle_type}_{rotation.charging_type}": rotation + for rotation in sorted_rotations} + for key, rot in vts.items(): + handles.append(Patch(color=color_generator.send(rot), label=key)) + # Position legend at the top outside of the plot + ax.legend(handles=handles, loc='lower center', bbox_to_anchor=(0.5, 1), + ncol=len(handles)//2, prop={"size": 7}) + fig.tight_layout() # PDF so Block names stay readable fig.savefig(output_path_folder / f"{sanitize(depot)}_block_distribution.pdf") From 18d9b90be03aeba198791dbd57cc06f9f600d87c Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Thu, 19 Sep 2024 14:44:22 +0200 Subject: [PATCH 5/7] Add minimum ncols --- simba/report.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/simba/report.py b/simba/report.py index 3953b7fe..4f0b8a55 100644 --- a/simba/report.py +++ b/simba/report.py @@ -678,7 +678,7 @@ def VehicleIdRowGenerator(): handles.append(Patch(color=color_generator.send(rot), label=key)) # Position legend at the top outside of the plot ax.legend(handles=handles, loc='lower center', bbox_to_anchor=(0.5, 1), - ncol=len(handles)//2, prop={"size": 7}) + ncol=len(handles)//2+1, prop={"size": 7}) fig.tight_layout() # PDF so Block names stay readable fig.savefig(output_path_folder / f"{sanitize(depot)}_vehicle_services.pdf") @@ -738,7 +738,7 @@ def DenseRowGenerator(): handles.append(Patch(color=color_generator.send(rot), label=key)) # Position legend at the top outside of the plot ax.legend(handles=handles, loc='lower center', bbox_to_anchor=(0.5, 1), - ncol=len(handles)//2, prop={"size": 7}) + ncol=len(handles)//2+1, prop={"size": 7}) fig.tight_layout() # PDF so Block names stay readable From 8ecd6732ad671cf2f1f9f52a8747a8a8c5a0dc1f Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Thu, 19 Sep 2024 15:08:16 +0200 Subject: [PATCH 6/7] Add dpi for all plots. Add x grid for box plots --- simba/report.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/simba/report.py b/simba/report.py index 4f0b8a55..289d6841 100644 --- a/simba/report.py +++ b/simba/report.py @@ -15,6 +15,8 @@ from simba import util +DPI = 300 + def open_for_csv(file_path): """ Create a file handle to write to. @@ -182,11 +184,11 @@ def generate_plots(schedule, scenario, args): file_path_png = args.results_directory / "run_overview.png" if vars(args).get("scenario_name"): file_path_png = file_path_png.with_stem(file_path_png.stem + '_' + args.scenario_name) - plt.savefig(file_path_png) + plt.savefig(file_path_png, dpi=300) file_path_pdf = args.results_directory / "run_overview.pdf" if vars(args).get("scenario_name"): file_path_pdf = file_path_pdf.with_stem(file_path_pdf.stem + '_' + args.scenario_name) - plt.savefig(file_path_pdf) + plt.savefig(file_path_pdf, dpi=300) if args.show_plots: plt.show() @@ -428,7 +430,7 @@ def plot_distance_per_rotation_distribution(extended_plots_path, schedule): ax.yaxis.grid(True) ax.set_title('Distribution of bus types over rotation distance') ax.legend() - plt.savefig(extended_plots_path / "distribution_bustypes_route_rotations") + plt.savefig(extended_plots_path / "distribution_bustypes_route_rotations", dpi=300) plt.close() @@ -468,7 +470,7 @@ def plot_consumption_per_rotation_distribution(extended_plots_path, schedule): ax.yaxis.grid(True) ax.set_title('Distribution of bus types over rotation energy consumption') ax.legend() - plt.savefig(extended_plots_path / "distribution_bustypes_consumption_rotations") + plt.savefig(extended_plots_path / "distribution_bustypes_consumption_rotations", dpi=300) plt.close() @@ -525,7 +527,7 @@ def plot_charge_type_distribution(extended_plots_path, scenario, schedule): ax.yaxis.get_major_locator().set_params(integer=True) ax.legend(["successful rotations", "negative rotations"]) ax.set_title("Distribution of opportunity and depot charging") - plt.savefig(extended_plots_path / "charge_types") + plt.savefig(extended_plots_path / "charge_types", dpi=300) plt.close() @@ -606,7 +608,7 @@ def plot_gc_power_timeseries(extended_plots_path, scenario): ax.set_xlim(time_values[0], time_values[-1]) # ax.tick_params(axis='x', rotation=30) - plt.savefig(extended_plots_path / f"{sanitize(gc)}_power_time_overview.png") + plt.savefig(extended_plots_path / f"{sanitize(gc)}_power_time_overview.png", dpi=300) plt.close(fig) @@ -682,7 +684,7 @@ def VehicleIdRowGenerator(): fig.tight_layout() # PDF so Block names stay readable fig.savefig(output_path_folder / f"{sanitize(depot)}_vehicle_services.pdf") - fig.savefig(output_path_folder / f"{sanitize(depot)}_vehicle_services.png") + fig.savefig(output_path_folder / f"{sanitize(depot)}_vehicle_services.png", dpi=300) plt.close(fig) @@ -743,7 +745,7 @@ def DenseRowGenerator(): fig.tight_layout() # PDF so Block names stay readable fig.savefig(output_path_folder / f"{sanitize(depot)}_block_distribution.pdf") - fig.savefig(output_path_folder / f"{sanitize(depot)}_block_distribution.png") + fig.savefig(output_path_folder / f"{sanitize(depot)}_block_distribution.png", dpi=300) plt.close(fig) @@ -762,6 +764,7 @@ def create_plot_blocks(sorted_rotations, color_generator, row_generator): # Large heights create too much margin with default value of margins: Reduce value to 0.01 ax.axes.margins(y=0.01) + ax.grid(axis='x') ax.xaxis.set_major_locator(mdates.AutoDateLocator()) ax.xaxis.set_major_formatter(mdates.DateFormatter('%D %H:%M')) ax.set_xlim(min(r.departure_time for r in sorted_rotations) - datetime.timedelta(minutes=30), @@ -803,5 +806,5 @@ def plot_active_rotations(extended_plots_path, scenario, schedule): ax.yaxis.get_major_locator().set_params(integer=True) plt.grid(axis="y") plt.title("Active Rotations") - plt.savefig(extended_plots_path / "active_rotations") + plt.savefig(extended_plots_path / "active_rotations", dpi=300) plt.close() From c7b808ecb00ec990ea25c9d9d7edc828dd41b011 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Thu, 19 Sep 2024 16:06:20 +0200 Subject: [PATCH 7/7] replace 300 with variable KPI --- simba/report.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/simba/report.py b/simba/report.py index 058fcb89..ef5ddbd7 100644 --- a/simba/report.py +++ b/simba/report.py @@ -184,11 +184,11 @@ def generate_plots(schedule, scenario, args): file_path_png = args.results_directory / "run_overview.png" if vars(args).get("scenario_name"): file_path_png = file_path_png.with_stem(file_path_png.stem + '_' + args.scenario_name) - plt.savefig(file_path_png, dpi=300) + plt.savefig(file_path_png, dpi=DPI) file_path_pdf = args.results_directory / "run_overview.pdf" if vars(args).get("scenario_name"): file_path_pdf = file_path_pdf.with_stem(file_path_pdf.stem + '_' + args.scenario_name) - plt.savefig(file_path_pdf, dpi=300) + plt.savefig(file_path_pdf, dpi=DPI) if args.show_plots: plt.show() @@ -468,7 +468,7 @@ def plot_distance_per_rotation_distribution(extended_plots_path, schedule): ax.set_title('Distribution of rotation length per vehicle type') ax.legend() plt.tight_layout() - plt.savefig(extended_plots_path / "distribution_distance.png", dpi=300) + plt.savefig(extended_plots_path / "distribution_distance.png", dpi=DPI) plt.close() @@ -498,7 +498,7 @@ def plot_consumption_per_rotation_distribution(extended_plots_path, schedule): ax.set_title('Distribution of energy consumption of rotations per vehicle type') ax.legend() plt.tight_layout() - plt.savefig(extended_plots_path / "distribution_consumption", dpi=300) + plt.savefig(extended_plots_path / "distribution_consumption", dpi=DPI) plt.close() @@ -553,7 +553,7 @@ def plot_charge_type_distribution(extended_plots_path, scenario, schedule): ax.yaxis.get_major_locator().set_params(integer=True) ax.legend(["successful rotations", "negative rotations"]) ax.set_title("Feasibility of rotations per charging type") - plt.savefig(extended_plots_path / "charge_types", dpi=300) + plt.savefig(extended_plots_path / "charge_types", dpi=DPI) plt.close() @@ -634,7 +634,7 @@ def plot_gc_power_timeseries(extended_plots_path, scenario): ax.set_xlim(time_values[0], time_values[-1]) # ax.tick_params(axis='x', rotation=30) plt.tight_layout() - plt.savefig(extended_plots_path / f"{sanitize(gc)}_power_overview.png", dpi=300) + plt.savefig(extended_plots_path / f"{sanitize(gc)}_power_overview.png", dpi=DPI) plt.close(fig) @@ -710,7 +710,7 @@ def VehicleIdRowGenerator(): fig.tight_layout() # PDF so Block names stay readable fig.savefig(output_path_folder / f"{sanitize(depot)}_vehicle_services.pdf") - fig.savefig(output_path_folder / f"{sanitize(depot)}_vehicle_services.png", dpi=300) + fig.savefig(output_path_folder / f"{sanitize(depot)}_vehicle_services.png", dpi=DPI) plt.close(fig) @@ -771,7 +771,7 @@ def DenseRowGenerator(): fig.tight_layout() # PDF so Block names stay readable fig.savefig(output_path_folder / f"{sanitize(depot)}_block_distribution.pdf") - fig.savefig(output_path_folder / f"{sanitize(depot)}_block_distribution.png", dpi=300) + fig.savefig(output_path_folder / f"{sanitize(depot)}_block_distribution.png", dpi=DPI) plt.close(fig) @@ -835,5 +835,5 @@ def plot_active_rotations(extended_plots_path, scenario, schedule): plt.grid(axis="y") plt.title("Active Rotations") plt.tight_layout() - plt.savefig(extended_plots_path / "active_rotations", dpi=300) + plt.savefig(extended_plots_path / "active_rotations", dpi=DPI) plt.close()