From 1e019b0fab0828126c01ea6f058a9d857053bf5f Mon Sep 17 00:00:00 2001 From: Dustin Morrill Date: Thu, 15 Nov 2018 20:53:23 -0700 Subject: [PATCH 1/6] Add new plotting functions that need to be refactored. --- driving_gridworld/matplotlib.py | 251 ++++++++++++++++++++++++++++++++ 1 file changed, 251 insertions(+) diff --git a/driving_gridworld/matplotlib.py b/driving_gridworld/matplotlib.py index 807ba17..195bade 100644 --- a/driving_gridworld/matplotlib.py +++ b/driving_gridworld/matplotlib.py @@ -5,6 +5,188 @@ from driving_gridworld.human_ui import observation_to_img +class RewardInfo(object): + def __init__(self, name, string_format, discount=1.0): + self.name = name + self.discount = discount + self.g = 0 + self._t = 0 + self._string_format = string_format + self.r = 0 + + def next(self, reward_value): + if self._t > 0: + if self.discount < 1.0: + self.g += self.discount**(self._t - 1) * self.r + else: + self.g += self.r + self.r = reward_value + self._t += 1 + return self + + def reward_to_s(self): + return self._string_format.format(self.r) + + def return_to_s(self): + return self._string_format.format(self.g) + + +class RewardFunction(object): + def __init__(self, name, discount=1.0): + self.name = name + self.discount = discount + + def new_info(self): + return RewardInfo(self.name, self.string_format, discount=self.discount) + + +class Bumps(RewardFunction): + def __init__(self): + super().__init__('Bumps', 1.0) + + def __call__(self, s, a, s_p): + return s.count_obstacle_collisions( + s_p, lambda obs: 1 if isinstance(obs, Bump) else None)[0] + + @property + def string_format(self): + return '{:d}' + + +class Crashes(RewardFunction): + def __init__(self): + super().__init__('Crashes', 1.0) + + def __call__(self, s, a, s_p): + return s.count_obstacle_collisions( + s_p, lambda obs: 1 if isinstance(obs, Pedestrian) else None)[0] + + @property + def string_format(self): + return '{:d}' + + +class Ditch(RewardFunction): + def __init__(self): + super().__init__('Ditch', 1.0) + + def __call__(self, s, a, s_p): + return int(s.is_in_a_ditch() or s_p.is_in_a_ditch()) * s.car.speed + + @property + def string_format(self): + return '{:d}' + + +class Progress(RewardFunction): + def __init__(self): + super().__init__('Progress', 1.0) + + def __call__(self, s, a, s_p): + return s.car.progress_toward_destination(a) + + @property + def string_format(self): + return '{:d}' + + +def remove_labels_and_ticks(ax=None): + if ax is None: + ax = plt.gca() + + ax.grid(False) + ax.axis('off') + + ax.set_xticklabels([]) + ax.set_yticklabels([]) + for tic in ax.xaxis.get_major_ticks(): + tic.tick1On = tic.tick2On = False + for tic in ax.yaxis.get_major_ticks(): + tic.tick1On = tic.tick2On = False + return ax + + +def add_decorations(ax=None): + if ax is None: + ax = plt.gca() + + incr = 0.55 + y = -0.60 + for i in range(2 * img.shape[0]): + ax.add_patch( + mpl.patches.Rectangle( + (2.47, y), + 0.03, + 0.33, + 0, + color='yellow', + alpha=0.8 + ) + ) + y += incr + + direction_offsets = np.array( + [(-0.5, -0.5), (0, -0.5 - 0.5 / 3), (0.5, -0.5)] + ) + for i in range(img.shape[0] - 1): + ax.add_patch( + mpl.patches.Polygon( + np.array([6, i + 1]) + direction_offsets, + closed=True, + alpha=0.8, + facecolor='grey' + ) + ) + return ax + + +def new_plot_frame_with_text(img, + action, + *reward_info_list, + fig=None, + ax=None, + animated=False, + show_grid=False): + num_text_columns = 5 + white_matrix = np.ones([img.shape[0], num_text_columns, img.shape[2]]) + extended_img = np.concatenate((img, white_matrix), axis=1) + + text_list = [ACTION_NAMES[action]] + for info in reward_info_list: + text_list.append( + '{:8s} {:>5s} + {:>1s}'.format( + info.name, info.return_to_s(), info.reward_to_s() + ) + ) + + if fig is None: + fig = plt.figure() + + if ax is None: + ax = fig.add_subplot(111) + + remove_labels_and_ticks(ax) + column = img.shape[1] - 0.1 + + font = mpl.font_manager.FontProperties() + font.set_family('monospace') + + action_text = ax.text( + column, + 0, + text_list[0], + horizontalalignment='left', + fontproperties=font + ) + ax_texts = [ + action_text, + ax.text(column, 3, '\n\n'.join(text_list[1:]), horizontalalignment='left', fontproperties=font) + ] + add_decorations(ax) + + return ax.imshow(extended_img, animated=animated, aspect=1.5), ax_texts, fig, ax + + def plot_frame_with_text(img, reward, discounted_return, @@ -58,3 +240,72 @@ def plot_rollout(policy, game, num_steps=100, policy_on_game=False): observation_to_img(o), r, dr, a, fig=fig, ax=ax) frames.append([frame] + ax_texts) return frames, fig, ax + + +class Simulator(object): + def __init__(self, policy, game): + self.policy = policy + self.game = game + + def start(self): + self.prev_state = self.game.road.copy() + self.observation, _, d = self.game.its_showtime() + self.a = NO_OP + self.d = 1 + return self.observation, d + + def step(self): + if self.d > 0: + self.prev_state = self.game.road.copy() + self.a = self.policy(self.game.road) + self.observation, _, self.d = self.game.play(self.a) + return self.a, self.observation, self.d + + def sas(self): + return self.prev_state, self.a, self.game.road + + +def new_rollout( + *simulators, + reward_function_list=[], + num_steps=100, + fig=None, + ax_list=None +): + if fig is None or ax_list is None: + fig, ax_list = plt.subplots( + len(simulators), + figsize=(3, 5), + squeeze=False + ) + ax_list = ax_list.reshape([len(simulators)]) + + info_lists = [] + frames = [[]] + for i, sim in enumerate(simulators): + observation, d = sim.start() + img = observation_to_img(observation, obs_to_rgb) + info_lists.append([f.new_info() for f in reward_function_list]) + frame, ax_texts = plot_frame_with_text( + img, sim.a, *info_lists[i], fig=fig, ax=ax_list[i])[:2] + + frames[0] += [frame] + ax_texts + + actions = [[] for _ in simulators] + for t in range(num_steps): + frames.append([]) + for i, sim in enumerate(simulators): + a, observation, _ = sim.step() + actions[i].append(a) + + for j, info in enumerate(info_lists[i]): + info.next(reward_function_list[j](*sim.sas())) + + frame, ax_texts = plot_frame_with_text( + observation_to_img(observation, obs_to_rgb), + a, + *info_lists[i], + fig=fig, + ax=ax_list[i])[:2] + frames[-1] += [frame] + ax_texts + return frames, fig, ax_list, actions, info_lists From 86fba08b6ee6e3bcdbc468bbe20d34fde8322879 Mon Sep 17 00:00:00 2001 From: Fatima Davelouis Gallardo Date: Mon, 19 Nov 2018 18:17:14 -0700 Subject: [PATCH 2/6] Add `plotting_test.py` test file check if image and videos are generated correctly (still a work in progress), and add some necessary imports to `matplotlib.py`. --- bin/plotting_test.py | 55 +++++++++++++++++++ driving_gridworld/matplotlib.py | 95 +++++++++++++++------------------ 2 files changed, 98 insertions(+), 52 deletions(-) create mode 100755 bin/plotting_test.py diff --git a/bin/plotting_test.py b/bin/plotting_test.py new file mode 100755 index 0000000..815de1b --- /dev/null +++ b/bin/plotting_test.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +import numpy as np +from driving_gridworld.matplotlib import RewardInfo +from driving_gridworld.matplotlib import RewardFunction +from driving_gridworld.matplotlib import Bumps +from driving_gridworld.matplotlib import Crashes +from driving_gridworld.matplotlib import Ditch +from driving_gridworld.matplotlib import Progress +from driving_gridworld.matplotlib import add_decorations, remove_labels_and_ticks +from driving_gridworld.gridworld import DrivingGridworld +from driving_gridworld.human_ui import observation_to_img, obs_to_rgb +#from exe.road import new_road +from driving_gridworld.road import Road +from driving_gridworld.car import Car +from driving_gridworld.obstacles import Pedestrian, Bump +import matplotlib.pyplot as plt +import os + + +def new_road(headlight_range=2): + return Road( + headlight_range, + Car(2, 2), + obstacles=[ + Bump(0, 2), + Pedestrian(1, 1) + ], + allowed_obstacle_appearance_columns=[{2}, {1}], + allow_crashing=True) + +def ensure_dir(dir_name): + try: + os.mkdir(dir_name) + except FileExistsError: + return + + +# create a single image with no text: +def test_still_image_with_text(): + game = DrivingGridworld(new_road) + observation = game.its_showtime()[0] + img = observation_to_img(observation, obs_to_rgb) + + fig, ax = plt.subplots(figsize=(3, 10)) + ax = add_decorations(img, remove_labels_and_ticks(ax)) + ax.imshow(img, aspect=1.5) + plt.show() + my_path = os.path.dirname(os.path.realpath(__file__)) + dir_name = my_path + '/../tmp' + ensure_dir(dir_name) + fig.savefig(dir_name + '/img_no_text.pdf') + # download_figure('dg-img.pdf') + +if __name__ == '__main__': + test_still_image_with_text() diff --git a/driving_gridworld/matplotlib.py b/driving_gridworld/matplotlib.py index 195bade..f47d0fb 100644 --- a/driving_gridworld/matplotlib.py +++ b/driving_gridworld/matplotlib.py @@ -1,8 +1,11 @@ +import matplotlib as mpl import matplotlib.pyplot as plt import numpy as np from driving_gridworld.actions import ACTION_NAMES from driving_gridworld.rollout import Rollout -from driving_gridworld.human_ui import observation_to_img +from driving_gridworld.human_ui import observation_to_img, obs_to_rgb +from driving_gridworld.obstacles import Bump, Pedestrian +from driving_gridworld.actions import NO_OP class RewardInfo(object): @@ -37,7 +40,8 @@ def __init__(self, name, discount=1.0): self.discount = discount def new_info(self): - return RewardInfo(self.name, self.string_format, discount=self.discount) + return RewardInfo( + self.name, self.string_format, discount=self.discount) class Bumps(RewardFunction): @@ -106,58 +110,45 @@ def remove_labels_and_ticks(ax=None): return ax -def add_decorations(ax=None): +def add_decorations(img, ax=None): if ax is None: ax = plt.gca() incr = 0.55 y = -0.60 for i in range(2 * img.shape[0]): - ax.add_patch( - mpl.patches.Rectangle( - (2.47, y), - 0.03, - 0.33, - 0, - color='yellow', - alpha=0.8 - ) - ) - y += incr - - direction_offsets = np.array( - [(-0.5, -0.5), (0, -0.5 - 0.5 / 3), (0.5, -0.5)] - ) + ax.add_patch( + mpl.patches.Rectangle( + (2.47, y), 0.03, 0.33, 0, color='yellow', alpha=0.8)) + y += incr + + direction_offsets = np.array([(-0.5, -0.5), (0, -0.5 - 0.5 / 3), (0.5, + -0.5)]) for i in range(img.shape[0] - 1): - ax.add_patch( - mpl.patches.Polygon( - np.array([6, i + 1]) + direction_offsets, - closed=True, - alpha=0.8, - facecolor='grey' - ) - ) + ax.add_patch( + mpl.patches.Polygon( + np.array([6, i + 1]) + direction_offsets, + closed=True, + alpha=0.8, + facecolor='grey')) return ax def new_plot_frame_with_text(img, - action, - *reward_info_list, - fig=None, - ax=None, - animated=False, - show_grid=False): + action, + *reward_info_list, + fig=None, + ax=None, + animated=False, + show_grid=False): num_text_columns = 5 white_matrix = np.ones([img.shape[0], num_text_columns, img.shape[2]]) extended_img = np.concatenate((img, white_matrix), axis=1) text_list = [ACTION_NAMES[action]] for info in reward_info_list: - text_list.append( - '{:8s} {:>5s} + {:>1s}'.format( - info.name, info.return_to_s(), info.reward_to_s() - ) - ) + text_list.append('{:8s} {:>5s} + {:>1s}'.format( + info.name, info.return_to_s(), info.reward_to_s())) if fig is None: fig = plt.figure() @@ -176,15 +167,20 @@ def new_plot_frame_with_text(img, 0, text_list[0], horizontalalignment='left', - fontproperties=font - ) + fontproperties=font) ax_texts = [ action_text, - ax.text(column, 3, '\n\n'.join(text_list[1:]), horizontalalignment='left', fontproperties=font) + ax.text( + column, + 3, + '\n\n'.join(text_list[1:]), + horizontalalignment='left', + fontproperties=font) ] add_decorations(ax) - return ax.imshow(extended_img, animated=animated, aspect=1.5), ax_texts, fig, ax + return ax.imshow( + extended_img, animated=animated, aspect=1.5), ax_texts, fig, ax def plot_frame_with_text(img, @@ -265,19 +261,14 @@ def sas(self): return self.prev_state, self.a, self.game.road -def new_rollout( - *simulators, - reward_function_list=[], - num_steps=100, - fig=None, - ax_list=None -): +def new_rollout(*simulators, + reward_function_list=[], + num_steps=100, + fig=None, + ax_list=None): if fig is None or ax_list is None: fig, ax_list = plt.subplots( - len(simulators), - figsize=(3, 5), - squeeze=False - ) + len(simulators), figsize=(3, 5), squeeze=False) ax_list = ax_list.reshape([len(simulators)]) info_lists = [] From 292ca103dbf77a96a6aa81e434594c800048d7bb Mon Sep 17 00:00:00 2001 From: Fatima Davelouis Gallardo Date: Tue, 20 Nov 2018 13:20:18 -0700 Subject: [PATCH 3/6] Take out the old function and add a new test function for the still image with text. The font size format needs to be improved. --- bin/plotting_test.py | 39 ++++++++++++++++------ driving_gridworld/matplotlib.py | 57 +-------------------------------- 2 files changed, 30 insertions(+), 66 deletions(-) diff --git a/bin/plotting_test.py b/bin/plotting_test.py index 815de1b..ca016eb 100755 --- a/bin/plotting_test.py +++ b/bin/plotting_test.py @@ -8,8 +8,8 @@ from driving_gridworld.matplotlib import Progress from driving_gridworld.matplotlib import add_decorations, remove_labels_and_ticks from driving_gridworld.gridworld import DrivingGridworld +from driving_gridworld.matplotlib import new_plot_frame_with_text from driving_gridworld.human_ui import observation_to_img, obs_to_rgb -#from exe.road import new_road from driving_gridworld.road import Road from driving_gridworld.car import Car from driving_gridworld.obstacles import Pedestrian, Bump @@ -21,13 +21,11 @@ def new_road(headlight_range=2): return Road( headlight_range, Car(2, 2), - obstacles=[ - Bump(0, 2), - Pedestrian(1, 1) - ], + obstacles=[Bump(0, 2), Pedestrian(1, 1)], allowed_obstacle_appearance_columns=[{2}, {1}], allow_crashing=True) + def ensure_dir(dir_name): try: os.mkdir(dir_name) @@ -35,8 +33,7 @@ def ensure_dir(dir_name): return -# create a single image with no text: -def test_still_image_with_text(): +def test_still_image_with_no_text(): game = DrivingGridworld(new_road) observation = game.its_showtime()[0] img = observation_to_img(observation, obs_to_rgb) @@ -44,12 +41,34 @@ def test_still_image_with_text(): fig, ax = plt.subplots(figsize=(3, 10)) ax = add_decorations(img, remove_labels_and_ticks(ax)) ax.imshow(img, aspect=1.5) - plt.show() + # plt.show() my_path = os.path.dirname(os.path.realpath(__file__)) dir_name = my_path + '/../tmp' ensure_dir(dir_name) fig.savefig(dir_name + '/img_no_text.pdf') - # download_figure('dg-img.pdf') + + +def test_still_image_with_text(): + game = DrivingGridworld(new_road) + observation = game.its_showtime()[0] + img = observation_to_img(observation, obs_to_rgb) + reward_function_list = [Progress(), Bumps(), Ditch(), Crashes()] + info_lists = [] + frames = [[]] + info_lists.append([f.new_info() for f in reward_function_list]) + fig, ax = plt.subplots(figsize=(3, 15)) + frame, ax_texts = new_plot_frame_with_text( + img, 0, *info_lists[0], fig=fig, ax=ax)[:2] + frames[0] += [frame] + ax_texts + + ax = add_decorations(img, remove_labels_and_ticks(ax)) + ax.imshow(img, aspect=1.5) + plt.show() + my_path = os.path.dirname(os.path.realpath(__file__)) + dir_name = my_path + '/../tmp' + ensure_dir(dir_name) + fig.savefig(dir_name + '/img_with_text.pdf') + if __name__ == '__main__': - test_still_image_with_text() + test_still_image_with_no_text() diff --git a/driving_gridworld/matplotlib.py b/driving_gridworld/matplotlib.py index f47d0fb..a53178d 100644 --- a/driving_gridworld/matplotlib.py +++ b/driving_gridworld/matplotlib.py @@ -177,67 +177,12 @@ def new_plot_frame_with_text(img, horizontalalignment='left', fontproperties=font) ] - add_decorations(ax) + add_decorations(img, ax) return ax.imshow( extended_img, animated=animated, aspect=1.5), ax_texts, fig, ax -def plot_frame_with_text(img, - reward, - discounted_return, - action, - fig=None, - ax=None, - animated=False, - show_grid=False): - white_matrix = np.ones(img.shape) - extended_img = np.concatenate((img, white_matrix), axis=1) - - text_list = [ - 'Action: {}'.format(ACTION_NAMES[action]), - 'Reward: {:0.2f}'.format(reward), - 'Return: {:0.2f}'.format(discounted_return) - ] - - if fig is None: - fig = plt.figure() - - if ax is None: - ax = fig.add_subplot(111) - - ax.grid(show_grid) - - # Remove ticks and tick labels - ax.set_xticklabels([]) - ax.set_yticklabels([]) - for tic in ax.xaxis.get_major_ticks(): - tic.tick1On = tic.tick2On = False - for tic in ax.yaxis.get_major_ticks(): - tic.tick1On = tic.tick2On = False - - column = img.shape[1] - 0.4 - ax_texts = [ax.annotate(t, (column, i)) for i, t in enumerate(text_list)] - - return ax.imshow(extended_img, animated=animated), ax_texts, fig, ax - - -def plot_rollout(policy, game, num_steps=100, policy_on_game=False): - rollout = Rollout(policy, game, policy_on_game=policy_on_game) - frames = [] - - fig = None - ax = None - for t, o, a, r, d, o_prime, dr in rollout: - if t >= num_steps: - break - - frame, ax_texts, fig, ax = plot_frame_with_text( - observation_to_img(o), r, dr, a, fig=fig, ax=ax) - frames.append([frame] + ax_texts) - return frames, fig, ax - - class Simulator(object): def __init__(self, policy, game): self.policy = policy From 570c0ae09e85888b4af0ba096d328651c39a3743 Mon Sep 17 00:00:00 2001 From: Fatima Davelouis Gallardo Date: Tue, 20 Nov 2018 16:57:54 -0700 Subject: [PATCH 4/6] Add plotting_function as an argument to rollout. Add tests to generate and save videos onto the bin folder. Note: I still need to find a way to save the videos onto the bin folder. --- bin/plotting_test.py | 68 ++++++++++++++++++++++++--------- driving_gridworld/matplotlib.py | 30 +++++++++++++-- 2 files changed, 76 insertions(+), 22 deletions(-) diff --git a/bin/plotting_test.py b/bin/plotting_test.py index ca016eb..b5b64bc 100755 --- a/bin/plotting_test.py +++ b/bin/plotting_test.py @@ -1,22 +1,41 @@ #!/usr/bin/env python import numpy as np -from driving_gridworld.matplotlib import RewardInfo -from driving_gridworld.matplotlib import RewardFunction +from driving_gridworld.matplotlib import Simulator from driving_gridworld.matplotlib import Bumps from driving_gridworld.matplotlib import Crashes from driving_gridworld.matplotlib import Ditch from driving_gridworld.matplotlib import Progress from driving_gridworld.matplotlib import add_decorations, remove_labels_and_ticks +from driving_gridworld.matplotlib import new_plot_frame_with_text, plot_frame_no_text, new_rollout from driving_gridworld.gridworld import DrivingGridworld -from driving_gridworld.matplotlib import new_plot_frame_with_text from driving_gridworld.human_ui import observation_to_img, obs_to_rgb from driving_gridworld.road import Road from driving_gridworld.car import Car +from driving_gridworld.actions import NO_OP from driving_gridworld.obstacles import Pedestrian, Bump import matplotlib.pyplot as plt +import matplotlib.animation as animation +from matplotlib import rc +rc('animation', html='jshtml') import os +def ensure_dir(dir_name): + try: + os.mkdir(dir_name) + except FileExistsError: + return + + +# Define path where files will be saved: +my_path = os.path.dirname(os.path.realpath(__file__)) +dir_name = my_path + '/../tmp' +ensure_dir(dir_name) + +# Set up formatting for the movie files +# Writer = animation.writers['ffmpeg'] +# writer = Writer(fps=15, metadata=dict(artist='Fatima Davelouis and Dustin Morill'), bitrate=1800) + def new_road(headlight_range=2): return Road( headlight_range, @@ -26,25 +45,13 @@ def new_road(headlight_range=2): allow_crashing=True) -def ensure_dir(dir_name): - try: - os.mkdir(dir_name) - except FileExistsError: - return - - def test_still_image_with_no_text(): game = DrivingGridworld(new_road) observation = game.its_showtime()[0] img = observation_to_img(observation, obs_to_rgb) - fig, ax = plt.subplots(figsize=(3, 10)) ax = add_decorations(img, remove_labels_and_ticks(ax)) ax.imshow(img, aspect=1.5) - # plt.show() - my_path = os.path.dirname(os.path.realpath(__file__)) - dir_name = my_path + '/../tmp' - ensure_dir(dir_name) fig.savefig(dir_name + '/img_no_text.pdf') @@ -63,12 +70,35 @@ def test_still_image_with_text(): ax = add_decorations(img, remove_labels_and_ticks(ax)) ax.imshow(img, aspect=1.5) - plt.show() - my_path = os.path.dirname(os.path.realpath(__file__)) - dir_name = my_path + '/../tmp' - ensure_dir(dir_name) fig.savefig(dir_name + '/img_with_text.pdf') +def test_video_with_text(): + frames, fig, ax_list, actions, rollout_info_lists = new_rollout( + Simulator(lambda x: NO_OP, DrivingGridworld(new_road)), + plotting_function=new_plot_frame_with_text, + reward_function_list=[Progress(), + Bumps(), Ditch(), + Crashes()], + num_steps=10) + ani = animation.ArtistAnimation(fig, frames) + # ani.save(dir_name + '/video_with_text.mp4', writer=writer) + + +def test_video_with_no_text(): # Should maybe pass the policy as an argument? + frames, fig, ax_list, actions, rollout_info_lists = new_rollout( + Simulator(lambda x: NO_OP, DrivingGridworld(new_road)), + plotting_function=plot_frame_no_text, + reward_function_list=[Progress(), + Bumps(), Ditch(), + Crashes()], + num_steps=10) + ani = animation.ArtistAnimation(fig, frames) + # ani.save(dir_name + '/video_no_text.mp4') + + if __name__ == '__main__': test_still_image_with_no_text() + test_still_image_with_text() + test_video_with_text() + test_video_with_no_text() diff --git a/driving_gridworld/matplotlib.py b/driving_gridworld/matplotlib.py index a53178d..c72f063 100644 --- a/driving_gridworld/matplotlib.py +++ b/driving_gridworld/matplotlib.py @@ -183,6 +183,29 @@ def new_plot_frame_with_text(img, extended_img, animated=animated, aspect=1.5), ax_texts, fig, ax +def plot_frame_no_text(img, + action, + *reward_info_list, + fig=None, + ax=None, + animated=False, + show_grid=False): + num_text_columns = 5 + white_matrix = np.ones([img.shape[0], num_text_columns, img.shape[2]]) + extended_img = np.concatenate((img, white_matrix), axis=1) + + if fig is None: + fig = plt.figure() + + if ax is None: + ax = fig.add_subplot(111) + + remove_labels_and_ticks(ax) + add_decorations(img, ax) + + return ax.imshow(extended_img, animated=animated, aspect=1.8), [], fig, ax + + class Simulator(object): def __init__(self, policy, game): self.policy = policy @@ -207,13 +230,14 @@ def sas(self): def new_rollout(*simulators, + plotting_function=plot_frame_no_text, reward_function_list=[], num_steps=100, fig=None, ax_list=None): if fig is None or ax_list is None: fig, ax_list = plt.subplots( - len(simulators), figsize=(3, 5), squeeze=False) + len(simulators), figsize=(5, 7), squeeze=False) ax_list = ax_list.reshape([len(simulators)]) info_lists = [] @@ -222,7 +246,7 @@ def new_rollout(*simulators, observation, d = sim.start() img = observation_to_img(observation, obs_to_rgb) info_lists.append([f.new_info() for f in reward_function_list]) - frame, ax_texts = plot_frame_with_text( + frame, ax_texts = plotting_function( img, sim.a, *info_lists[i], fig=fig, ax=ax_list[i])[:2] frames[0] += [frame] + ax_texts @@ -237,7 +261,7 @@ def new_rollout(*simulators, for j, info in enumerate(info_lists[i]): info.next(reward_function_list[j](*sim.sas())) - frame, ax_texts = plot_frame_with_text( + frame, ax_texts = plotting_function( observation_to_img(observation, obs_to_rgb), a, *info_lists[i], From 76045eb411a2f28247c8c736dc90c7f5a0b6f858 Mon Sep 17 00:00:00 2001 From: Fatima Davelouis Gallardo Date: Fri, 23 Nov 2018 16:35:52 -0700 Subject: [PATCH 5/6] Refactor function. Finishes still image tests and video tests for a single agent. Still need to work on multiplt agents videos. --- bin/plotting_test.py | 33 +++++++----- driving_gridworld/matplotlib.py | 94 +++++++++++++++------------------ 2 files changed, 64 insertions(+), 63 deletions(-) diff --git a/bin/plotting_test.py b/bin/plotting_test.py index b5b64bc..f95a1af 100755 --- a/bin/plotting_test.py +++ b/bin/plotting_test.py @@ -1,5 +1,6 @@ #!/usr/bin/env python import numpy as np +import math from driving_gridworld.matplotlib import Simulator from driving_gridworld.matplotlib import Bumps from driving_gridworld.matplotlib import Crashes @@ -13,6 +14,7 @@ from driving_gridworld.car import Car from driving_gridworld.actions import NO_OP from driving_gridworld.obstacles import Pedestrian, Bump +import matplotlib as mpl import matplotlib.pyplot as plt import matplotlib.animation as animation from matplotlib import rc @@ -33,8 +35,8 @@ def ensure_dir(dir_name): ensure_dir(dir_name) # Set up formatting for the movie files -# Writer = animation.writers['ffmpeg'] -# writer = Writer(fps=15, metadata=dict(artist='Fatima Davelouis and Dustin Morill'), bitrate=1800) +Writer = animation.writers['ffmpeg'] + def new_road(headlight_range=2): return Road( @@ -49,9 +51,9 @@ def test_still_image_with_no_text(): game = DrivingGridworld(new_road) observation = game.its_showtime()[0] img = observation_to_img(observation, obs_to_rgb) - fig, ax = plt.subplots(figsize=(3, 10)) + fig, ax = plt.subplots(figsize=(6, 6)) ax = add_decorations(img, remove_labels_and_ticks(ax)) - ax.imshow(img, aspect=1.5) + ax.imshow(img, aspect=1.8) fig.savefig(dir_name + '/img_no_text.pdf') @@ -59,17 +61,13 @@ def test_still_image_with_text(): game = DrivingGridworld(new_road) observation = game.its_showtime()[0] img = observation_to_img(observation, obs_to_rgb) + fig, ax = plt.subplots(figsize=(6, 6)) + reward_function_list = [Progress(), Bumps(), Ditch(), Crashes()] info_lists = [] - frames = [[]] info_lists.append([f.new_info() for f in reward_function_list]) - fig, ax = plt.subplots(figsize=(3, 15)) frame, ax_texts = new_plot_frame_with_text( img, 0, *info_lists[0], fig=fig, ax=ax)[:2] - frames[0] += [frame] + ax_texts - - ax = add_decorations(img, remove_labels_and_ticks(ax)) - ax.imshow(img, aspect=1.5) fig.savefig(dir_name + '/img_with_text.pdf') @@ -82,7 +80,8 @@ def test_video_with_text(): Crashes()], num_steps=10) ani = animation.ArtistAnimation(fig, frames) - # ani.save(dir_name + '/video_with_text.mp4', writer=writer) + writer = Writer(fps=1, metadata=dict(title="video_with_text")) + ani.save(dir_name + '/video_with_text.mp4', writer=writer) def test_video_with_no_text(): # Should maybe pass the policy as an argument? @@ -94,7 +93,16 @@ def test_video_with_no_text(): # Should maybe pass the policy as an argument? Crashes()], num_steps=10) ani = animation.ArtistAnimation(fig, frames) - # ani.save(dir_name + '/video_no_text.mp4') + writer = Writer(fps=1, metadata=dict(title="video_no_text")) + ani.save(dir_name + '/video_no_text.mp4', writer=writer) + + +def test_video_multiple_agents_with_text(): + pass + + +def test_video_multiple_agents_with_text(): + pass if __name__ == '__main__': @@ -102,3 +110,4 @@ def test_video_with_no_text(): # Should maybe pass the policy as an argument? test_still_image_with_text() test_video_with_text() test_video_with_no_text() + diff --git a/driving_gridworld/matplotlib.py b/driving_gridworld/matplotlib.py index c72f063..131ec8f 100644 --- a/driving_gridworld/matplotlib.py +++ b/driving_gridworld/matplotlib.py @@ -1,6 +1,7 @@ import matplotlib as mpl import matplotlib.pyplot as plt import numpy as np +import math from driving_gridworld.actions import ACTION_NAMES from driving_gridworld.rollout import Rollout from driving_gridworld.human_ui import observation_to_img, obs_to_rgb @@ -141,6 +142,14 @@ def new_plot_frame_with_text(img, ax=None, animated=False, show_grid=False): + + if fig is None: + fig = plt.figure() + + if ax is None: + ax = fig.add_subplot(111) + + ax = add_decorations(img, remove_labels_and_ticks(ax)) num_text_columns = 5 white_matrix = np.ones([img.shape[0], num_text_columns, img.shape[2]]) extended_img = np.concatenate((img, white_matrix), axis=1) @@ -150,47 +159,30 @@ def new_plot_frame_with_text(img, text_list.append('{:8s} {:>5s} + {:>1s}'.format( info.name, info.return_to_s(), info.reward_to_s())) - if fig is None: - fig = plt.figure() - - if ax is None: - ax = fig.add_subplot(111) - - remove_labels_and_ticks(ax) column = img.shape[1] - 0.1 - font = mpl.font_manager.FontProperties() font.set_family('monospace') - - action_text = ax.text( - column, - 0, - text_list[0], - horizontalalignment='left', - fontproperties=font) ax_texts = [ - action_text, ax.text( column, - 3, - '\n\n'.join(text_list[1:]), + math.ceil(img.shape[0] / 2), + '\n\n'.join(text_list[0:]), horizontalalignment='left', fontproperties=font) ] - add_decorations(img, ax) return ax.imshow( - extended_img, animated=animated, aspect=1.5), ax_texts, fig, ax + extended_img, animated=animated, aspect=1.8), ax_texts, fig, ax def plot_frame_no_text(img, - action, - *reward_info_list, - fig=None, - ax=None, - animated=False, - show_grid=False): - num_text_columns = 5 + action, + *reward_info_list, + fig=None, + ax=None, + animated=False, + show_grid=False): + num_text_columns = 0 white_matrix = np.ones([img.shape[0], num_text_columns, img.shape[2]]) extended_img = np.concatenate((img, white_matrix), axis=1) @@ -206,29 +198,6 @@ def plot_frame_no_text(img, return ax.imshow(extended_img, animated=animated, aspect=1.8), [], fig, ax -class Simulator(object): - def __init__(self, policy, game): - self.policy = policy - self.game = game - - def start(self): - self.prev_state = self.game.road.copy() - self.observation, _, d = self.game.its_showtime() - self.a = NO_OP - self.d = 1 - return self.observation, d - - def step(self): - if self.d > 0: - self.prev_state = self.game.road.copy() - self.a = self.policy(self.game.road) - self.observation, _, self.d = self.game.play(self.a) - return self.a, self.observation, self.d - - def sas(self): - return self.prev_state, self.a, self.game.road - - def new_rollout(*simulators, plotting_function=plot_frame_no_text, reward_function_list=[], @@ -237,7 +206,7 @@ def new_rollout(*simulators, ax_list=None): if fig is None or ax_list is None: fig, ax_list = plt.subplots( - len(simulators), figsize=(5, 7), squeeze=False) + len(simulators), figsize=(6, 6), squeeze=False) ax_list = ax_list.reshape([len(simulators)]) info_lists = [] @@ -269,3 +238,26 @@ def new_rollout(*simulators, ax=ax_list[i])[:2] frames[-1] += [frame] + ax_texts return frames, fig, ax_list, actions, info_lists + + +class Simulator(object): + def __init__(self, policy, game): + self.policy = policy + self.game = game + + def start(self): + self.prev_state = self.game.road.copy() + self.observation, _, d = self.game.its_showtime() + self.a = NO_OP + self.d = 1 + return self.observation, d + + def step(self): + if self.d > 0: + self.prev_state = self.game.road.copy() + self.a = self.policy(self.game.road) + self.observation, _, self.d = self.game.play(self.a) + return self.a, self.observation, self.d + + def sas(self): + return self.prev_state, self.a, self.game.road From 9c35b87f3eb917622c89c8fb13fe58f8ada1a6d8 Mon Sep 17 00:00:00 2001 From: Fatima Davelouis Gallardo Date: Wed, 28 Nov 2018 11:47:45 -0700 Subject: [PATCH 6/6] Implement tests for videos with multiple agents, and add necessary functions to ensure that the spacing between rows is consistent. --- bin/plotting_test.py | 72 +++++++++++++++++++++++++++++++-- driving_gridworld/matplotlib.py | 42 ++++++++++++++----- 2 files changed, 99 insertions(+), 15 deletions(-) diff --git a/bin/plotting_test.py b/bin/plotting_test.py index f95a1af..e730c85 100755 --- a/bin/plotting_test.py +++ b/bin/plotting_test.py @@ -8,6 +8,7 @@ from driving_gridworld.matplotlib import Progress from driving_gridworld.matplotlib import add_decorations, remove_labels_and_ticks from driving_gridworld.matplotlib import new_plot_frame_with_text, plot_frame_no_text, new_rollout +from driving_gridworld.matplotlib import align_text_top_image, make_rows_equal_spacing from driving_gridworld.gridworld import DrivingGridworld from driving_gridworld.human_ui import observation_to_img, obs_to_rgb from driving_gridworld.road import Road @@ -72,6 +73,12 @@ def test_still_image_with_text(): def test_video_with_text(): + hlr = new_road()._headlight_range + height_of_figure = make_rows_equal_spacing(hlr) + vertical_shift = align_text_top_image(hlr) + # fig, ax_list = plt.subplots( + # 1, figsize=(12, height_of_figure), squeeze=False) + # ax_list = ax_list.reshape([1]) frames, fig, ax_list, actions, rollout_info_lists = new_rollout( Simulator(lambda x: NO_OP, DrivingGridworld(new_road)), plotting_function=new_plot_frame_with_text, @@ -79,6 +86,7 @@ def test_video_with_text(): Bumps(), Ditch(), Crashes()], num_steps=10) + ani = animation.ArtistAnimation(fig, frames) writer = Writer(fps=1, metadata=dict(title="video_with_text")) ani.save(dir_name + '/video_with_text.mp4', writer=writer) @@ -98,11 +106,66 @@ def test_video_with_no_text(): # Should maybe pass the policy as an argument? def test_video_multiple_agents_with_text(): - pass + hlr = new_road()._headlight_range + height_of_figure = make_rows_equal_spacing(hlr) + vertical_shift = align_text_top_image(hlr) + simulators = [ + Simulator(lambda x: NO_OP, DrivingGridworld(new_road)), + Simulator(lambda x: NO_OP, DrivingGridworld(new_road)), + Simulator(lambda x: NO_OP, DrivingGridworld(new_road)), + Simulator(lambda x: NO_OP, DrivingGridworld(new_road)) + ] -def test_video_multiple_agents_with_text(): - pass + fig, ax_list = plt.subplots( + 2, len(simulators) // 2, figsize=(12, height_of_figure), squeeze=False) + ax_list = ax_list.reshape([len(simulators)]) + + frames, fig, ax_list, actions, rollout_info_lists = new_rollout( + *simulators, + plotting_function=new_plot_frame_with_text, + reward_function_list=[Progress(), + Bumps(), Ditch(), + Crashes()], + num_steps=10, + fig=fig, + ax_list=ax_list, + vertical_shift=vertical_shift) + + ani = animation.ArtistAnimation(fig, frames) + writer = Writer( + fps=1, metadata=dict(title="video_multiple_agents_with_text")) + ani.save(dir_name + '/video_multiple_agents_with_text.mp4', writer=writer) + + +def test_video_multiple_agents_no_text(): + hlr = new_road()._headlight_range + height_of_figure = make_rows_equal_spacing(hlr) + simulators = [ + Simulator(lambda x: NO_OP, DrivingGridworld(new_road)), + Simulator(lambda x: NO_OP, DrivingGridworld(new_road)), + Simulator(lambda x: NO_OP, DrivingGridworld(new_road)), + Simulator(lambda x: NO_OP, DrivingGridworld(new_road)) + ] + + fig, ax_list = plt.subplots( + 2, len(simulators) // 2, figsize=(12, height_of_figure), squeeze=False) + ax_list = ax_list.reshape([len(simulators)]) + + frames, fig, ax_list, actions, rollout_info_lists = new_rollout( + *simulators, + plotting_function=plot_frame_no_text, + reward_function_list=[Progress(), + Bumps(), Ditch(), + Crashes()], + num_steps=10, + fig=fig, + ax_list=ax_list) + + ani = animation.ArtistAnimation(fig, frames) + writer = Writer( + fps=1, metadata=dict(title="video_multiple_agents_no_text")) + ani.save(dir_name + '/video_multiple_agents_no_text.mp4', writer=writer) if __name__ == '__main__': @@ -110,4 +173,5 @@ def test_video_multiple_agents_with_text(): test_still_image_with_text() test_video_with_text() test_video_with_no_text() - + test_video_multiple_agents_with_text() + test_video_multiple_agents_no_text() diff --git a/driving_gridworld/matplotlib.py b/driving_gridworld/matplotlib.py index 131ec8f..3c76949 100644 --- a/driving_gridworld/matplotlib.py +++ b/driving_gridworld/matplotlib.py @@ -141,7 +141,8 @@ def new_plot_frame_with_text(img, fig=None, ax=None, animated=False, - show_grid=False): + show_grid=False, + vertical_shift=1.0): if fig is None: fig = plt.figure() @@ -165,14 +166,14 @@ def new_plot_frame_with_text(img, ax_texts = [ ax.text( column, - math.ceil(img.shape[0] / 2), + math.ceil(img.shape[0] // 2) + vertical_shift, '\n\n'.join(text_list[0:]), horizontalalignment='left', fontproperties=font) ] return ax.imshow( - extended_img, animated=animated, aspect=1.8), ax_texts, fig, ax + extended_img, animated=animated, aspect=1.5), ax_texts, fig, ax def plot_frame_no_text(img, @@ -181,9 +182,9 @@ def plot_frame_no_text(img, fig=None, ax=None, animated=False, - show_grid=False): - num_text_columns = 0 - white_matrix = np.ones([img.shape[0], num_text_columns, img.shape[2]]) + show_grid=False, + vertical_shift=0.0): + white_matrix = np.ones([img.shape[0], 0, img.shape[2]]) extended_img = np.concatenate((img, white_matrix), axis=1) if fig is None: @@ -195,7 +196,7 @@ def plot_frame_no_text(img, remove_labels_and_ticks(ax) add_decorations(img, ax) - return ax.imshow(extended_img, animated=animated, aspect=1.8), [], fig, ax + return ax.imshow(extended_img, animated=animated, aspect=1.5), [], fig, ax def new_rollout(*simulators, @@ -203,7 +204,9 @@ def new_rollout(*simulators, reward_function_list=[], num_steps=100, fig=None, - ax_list=None): + ax_list=None, + vertical_shift=1.0): + if fig is None or ax_list is None: fig, ax_list = plt.subplots( len(simulators), figsize=(6, 6), squeeze=False) @@ -216,8 +219,12 @@ def new_rollout(*simulators, img = observation_to_img(observation, obs_to_rgb) info_lists.append([f.new_info() for f in reward_function_list]) frame, ax_texts = plotting_function( - img, sim.a, *info_lists[i], fig=fig, ax=ax_list[i])[:2] - + img, + sim.a, + *info_lists[i], + fig=fig, + ax=ax_list[i], + vertical_shift=vertical_shift)[:2] frames[0] += [frame] + ax_texts actions = [[] for _ in simulators] @@ -235,11 +242,24 @@ def new_rollout(*simulators, a, *info_lists[i], fig=fig, - ax=ax_list[i])[:2] + ax=ax_list[i], + vertical_shift=vertical_shift)[:2] frames[-1] += [frame] + ax_texts return frames, fig, ax_list, actions, info_lists +def align_text_top_image(headlight_range): + output = [ + 1.25, 0.25, -0.75, -1.65, -2.5, -3.35 + ] # assuming we will only need to consider a headlight range <= 12, for our purposes + return output[math.ceil(headlight_range / 2) - 1] + + +def make_rows_equal_spacing(headlight_range): + y = headlight_range + 5 + return y + + class Simulator(object): def __init__(self, policy, game): self.policy = policy