def test_map_of_island_is_dict(self, example_geogr, example_ini_pop): """ Asserts that the create_map_dict method created a dictionary. """ island_map = IslandMap(example_geogr, example_ini_pop) island_map.create_map_dict() assert type(island_map.map) is dict
def test_animal_moves_not_if_it_has_already_moved_this_year( self, example_geogr, example_ini_pop ): """ Tests move_single_animal. Asserts that animal does not move if it has already moved this year. """ island_map = IslandMap(example_geogr, example_ini_pop) island_map.create_map_dict() herbivore = island_map.map[(1, 2)].pop_herb[0] herbivore.has_moved_this_year = True assert island_map.move_single_animal((1, 2), herbivore) is None
def test_finds_two_correct_neighbours_when_two_habitable_cells_around( self, example_geogr, example_ini_pop ): """ Asserts that the neighbours_of_current_cell method return the correct neighbours for a cell with only two neighbours. """ island_map = IslandMap(example_geogr, example_ini_pop) island_map.create_map_dict() dict_with_neighbours = island_map.neighbours_of_current_cell((1, 1)) neighbours = [(1, 2), (2, 1)] for neighbour in dict_with_neighbours.keys(): assert neighbour in neighbours
def test_single_animal_moves_not_if_rand_num_higher_than_prob( self, mocker, example_geogr, example_ini_pop ): """ Tests move_single_animal. Asserts that animal does not move if it has not moved this year, but the random number is higher than the probability of moving. """ mocker.patch('numpy.random.random', return_value=1) island_map = IslandMap(example_geogr, example_ini_pop) island_map.create_map_dict() herbivore = island_map.map[(1, 2)].pop_herb[0] assert island_map.move_single_animal((1, 2), herbivore) is None
def test_finds_no_neighbours_when_no_habitable_cells_around( self, example_ini_pop ): """ Asserts that the neighbours_of_current_cell method handles a cell with no habitable neighbours. """ geogr_one_cell = """\ OOO OJO OOO """ island_map = IslandMap(geogr_one_cell, example_ini_pop) island_map.create_map_dict() dict_with_neighbours = island_map.neighbours_of_current_cell((1, 1)) assert dict_with_neighbours == {}
def test_all_animals_die_after_dying_season( self, mocker, example_ini_pop, example_geogr ): """ Test for dying_season. Asserts that all animals on island die, when the random number that decides is larger than their probability to live. """ mocker.patch("numpy.random.random", return_value=1) island_map = IslandMap(example_geogr, example_ini_pop) island_map.dying_season() sum_animals = 0 for cell in island_map.map.values(): sum_animals += len(cell.pop_herb) sum_animals += len(cell.pop_carn) assert sum_animals == 0
def test_map_can_include_all_landscape_types(self, example_ini_pop): """ Asserts that create_map_dict can create map from a geography string where all landscape types are included. """ all_types = """\ OOOO ODMO OSJO OOOO """ island_map = IslandMap(all_types, example_ini_pop) island_map.create_map_dict() assert type(island_map.map[(0, 0)]).__name__ is "Ocean" assert type(island_map.map[(1, 1)]).__name__ is "Desert" assert type(island_map.map[(1, 2)]).__name__ is "Mountain" assert type(island_map.map[(2, 1)]).__name__ is "Savannah" assert type(island_map.map[(2, 2)]).__name__ is "Jungle"
def test_finds_four_correct_neighbours_when_four_habitable_cells_around( self, example_ini_pop ): """ Asserts that the neighbours_of_current_cell method return the correct neighbours for a cell with four neighbours. """ test_geogr = """\ OOOOO OJJJO OJJJO OJJJO OOOOO """ island_map = IslandMap(test_geogr, example_ini_pop) island_map.create_map_dict() dict_with_neighbours = island_map.neighbours_of_current_cell((2, 2)) neighbours = [(1, 2), (2, 1), (2, 3), (3, 2)] for neighbour in dict_with_neighbours.keys(): assert neighbour in neighbours
def test_all_animals_gave_birth_when_prob_birth_is_one( self, mocker, example_ini_pop, example_geogr ): """ Tests procreation_season method. Asserts that all animals on island give birth when their probability of giving birth is one. """ mocker.patch("numpy.random.random", return_value=0.01) island_map = IslandMap(example_geogr, example_ini_pop) ini_sum_animals = 0 for cell in island_map.map.values(): ini_sum_animals += len(cell.pop_herb) ini_sum_animals += len(cell.pop_carn) island_map.procreation_season() sum_animals = 0 for cell in island_map.map.values(): sum_animals += len(cell.pop_herb) sum_animals += len(cell.pop_carn) assert sum_animals == 2 * ini_sum_animals
def test_all_animals_move_if_rand_num_less_than_prob( self, mocker, example_geogr ): """ Tests move_single_animal on several animals. Asserts that all animal move if they have not moved this year and random number is less than their probability to move. """ move_ini_pop = [ { "loc": (1, 2), "pop": [ {"species": "Herbivore", "age": 5, "weight": 20} for _ in range(3) ] }, { "loc": (2, 2), "pop": [ {"species": "Carnivore", "age": 5, "weight": 20} for _ in range(3) ] } ] mocker.patch('numpy.random.random', return_value=0.01) island_map = IslandMap(example_geogr, move_ini_pop) island_map.create_map_dict() for loc, cell in island_map.map.items(): for herbivore in cell.pop_herb: assert island_map.move_single_animal(loc, herbivore) is True for carnivore in cell.pop_carn: assert island_map.move_single_animal(loc, carnivore) is True
def test_geography_is_converted_correctly_to_dict( self, example_ini_pop ): """ Asserts that the create_geography method creates a dictionary, and that the dictionary has correct keys and values. """ geogr_convert = """\ OOOO OJSO ODMO OOOO """ island_map = IslandMap(geogr_convert, example_ini_pop) island_map.create_geography_dict() assert type(island_map.geography) is dict assert island_map.geography == { (0, 0): 'O', (0, 1): 'O', (0, 2): 'O', (0, 3): 'O', (1, 0): 'O', (1, 1): 'J', (1, 2): 'S', (1, 3): 'O', (2, 0): 'O', (2, 1): 'D', (2, 2): 'M', (2, 3): 'O', (3, 0): 'O', (3, 1): 'O', (3, 2): 'O', (3, 3): 'O', }
def test_population_is_converted_correctly_to_dict( self, example_geogr, example_ini_pop ): """ Asserts that the create_population method created a dictionary and that the keys and values of the dictionary have been converted correctly. """ island_map = IslandMap(example_geogr, example_ini_pop) island_map.create_population_dict() assert type(island_map.population) is dict assert island_map.population == { (1, 2): [ {'species': 'Herbivore', 'age': 5, 'weight': 20}, {'species': 'Herbivore', 'age': 5, 'weight': 20}, {'species': 'Herbivore', 'age': 5, 'weight': 20} ], (2, 2): [ {'species': 'Herbivore', 'age': 5, 'weight': 20}, {'species': 'Herbivore', 'age': 5, 'weight': 20}, {'species': 'Herbivore', 'age': 5, 'weight': 20} ] }
def test_add_animals_to_existing_population( self, example_ini_pop, example_geogr ): """ Tests add_population method. Asserts that additional animals can be added to an existing population. """ island_map = IslandMap(example_geogr, initial_population=[]) island_map.create_map_dict() island_map.add_population(example_ini_pop)
def test_all_animals_lost_weight_during_weight_loss_season( self, example_ini_pop, example_geogr ): """ Asserts that all animals on the island on the island has lost weight after weight_loss_season. """ island_map = IslandMap(example_geogr, example_ini_pop) island_map.create_map_dict() island_map.weight_loss_season() initial_weight_animal = example_ini_pop[0]["pop"][0]["weight"] for cell in island_map.map.values(): for animal in cell.pop_herb+cell.pop_carn: assert animal.weight < initial_weight_animal
def test_all_animals_age_during_aging_season( self, example_ini_pop, example_geogr ): """ Test for aging_season method. Asserts that all animals on the island have aged. """ island_map = IslandMap(example_geogr, example_ini_pop) island_map.create_map_dict() island_map.aging_season() initial_age_animal = example_ini_pop[0]["pop"][0]["age"] for cell in island_map.map.values(): for animal in cell.pop_herb+cell.pop_carn: assert animal.age > initial_age_animal
def test_all_animals_migrate_during_migration_season( self, mocker, example_ini_pop, example_geogr ): """ Test for migration_season method. Asserts that all animals have moved after the migration season, by checking their has_moved_this_year attribute. """ mocker.patch('numpy.random.random', return_value=0.0001) island_map = IslandMap(example_geogr, [example_ini_pop[0]]) island_map.create_map_dict() island_map.migration_season() for loc, cell in island_map.map.items(): for animal in cell.pop_herb+cell.pop_carn: assert animal.has_moved_this_year is True
def test_one_animal_in_each_cell_has_been_fed( self, example_geogr, example_ini_pop ): """ Tests feeding_season method. Asserts that one animal in each cell of the test island have been fed. """ island_map = IslandMap(example_geogr, example_ini_pop) island_map.create_map_dict() island_map.feeding_season() assert island_map.map[(1, 2)].pop_herb[0].weight > \ example_ini_pop[0]["pop"][0]["weight"] assert island_map.map[(2, 2)].pop_herb[0].weight > \ example_ini_pop[1]["pop"][0]["weight"]
def test_all_animals_move_when_rand_num_less_than_prob( self, mocker, example_ini_pop, example_geogr ): """ Tests move_all_animals_in_cell. Asserts that all animals move out of a cell when the random number is less than the probability for each to move. """ mocker.patch('numpy.random.random', return_value=0.0001) island_map = IslandMap(example_geogr, [example_ini_pop[0]]) island_map.create_map_dict() island_map.move_all_animals_in_cell((1, 2), island_map.map[(1, 2)]) final_num_animals = len(island_map.map[(1, 2)].pop_herb) + \ len(island_map.map[(1, 2)].pop_carn) assert final_num_animals == 0
def test_no_animals_move_when_rand_num_higher_than_prob_of_moving( self, mocker, example_ini_pop, example_geogr ): """ Tests move_all_animals_in_cell. Asserts that no animals move out of a cell when the random number is higher than the animal's probability to move. """ mocker.patch('numpy.random.random', return_value=1) island_map = IslandMap(example_geogr, [example_ini_pop[0]]) island_map.create_map_dict() initial_num_animals = len(island_map.map[(1, 2)].pop_herb) + \ len(island_map.map[(1, 2)].pop_carn) island_map.move_all_animals_in_cell((1, 2), island_map.map[(1, 2)]) final_num_animals = len(island_map.map[(1, 2)].pop_herb) + \ len(island_map.map[(1, 2)].pop_carn) assert final_num_animals == initial_num_animals
def __init__( self, island_geography, initial_population, seed, ymax_animals=None, cmax_animals=None, img_base=None, img_fmt="png", ): """ :param island_geography: Multi-line string specifying island geography :param initial_population: List of dictionaries specifying initial population :param seed: Integer used as random number seed :param ymax_animals: Number specifying y-axis limit for graph showing animal numbers :param cmax_animals: Dict specifying color-code limits for animal densities :param img_base: String with beginning of file name for figures, including path :param img_fmt: String with file type for figures, e.g. 'png' If ymax_animals is None, the y-axis limit should be adjusted automatically. If cmax_animals is None, sensible, fixed default values should be used. cmax_animals is a dict mapping species names to numbers, e.g., {'Herbivore': 50, 'Carnivore': 20} If img_base is None, no figures are written to file. Filenames are formed as '{}_{:05d}.{}'.format(img_base, img_no, img_fmt) where img_no are consecutive image numbers starting from 0. img_base should contain a path and beginning of a file name. """ numpy.random.seed(seed) self.img_base = img_base self.img_fmt = img_fmt self.img_no = 0 self.ymax = ymax_animals if cmax_animals is None: self.cmax = {'Herbivore': 300, 'Carnivore': 100} else: self.cmax = cmax_animals self.island_map = IslandMap(island_geography, initial_population) self.island_map.create_map_dict() self.num_years_simulated = 0 self.final_year = None # The following will be initialized by setup_graphics self._fig = None self._line_graph_ax = None self._line_graph_line_herb = None self._line_graph_line_carn = None self._map_ax = None self._img_axis = None self._heat_map_herb_ax = None self._img_herb_axis = None self._heat_map_carn_ax = None self._img_carn_axis = None
class BioSim: """ Class for simulating the model of an ecosystem. """ def __init__( self, island_geography, initial_population, seed, ymax_animals=None, cmax_animals=None, img_base=None, img_fmt="png", ): """ :param island_geography: Multi-line string specifying island geography :param initial_population: List of dictionaries specifying initial population :param seed: Integer used as random number seed :param ymax_animals: Number specifying y-axis limit for graph showing animal numbers :param cmax_animals: Dict specifying color-code limits for animal densities :param img_base: String with beginning of file name for figures, including path :param img_fmt: String with file type for figures, e.g. 'png' If ymax_animals is None, the y-axis limit should be adjusted automatically. If cmax_animals is None, sensible, fixed default values should be used. cmax_animals is a dict mapping species names to numbers, e.g., {'Herbivore': 50, 'Carnivore': 20} If img_base is None, no figures are written to file. Filenames are formed as '{}_{:05d}.{}'.format(img_base, img_no, img_fmt) where img_no are consecutive image numbers starting from 0. img_base should contain a path and beginning of a file name. """ numpy.random.seed(seed) self.img_base = img_base self.img_fmt = img_fmt self.img_no = 0 self.ymax = ymax_animals if cmax_animals is None: self.cmax = {'Herbivore': 300, 'Carnivore': 100} else: self.cmax = cmax_animals self.island_map = IslandMap(island_geography, initial_population) self.island_map.create_map_dict() self.num_years_simulated = 0 self.final_year = None # The following will be initialized by setup_graphics self._fig = None self._line_graph_ax = None self._line_graph_line_herb = None self._line_graph_line_carn = None self._map_ax = None self._img_axis = None self._heat_map_herb_ax = None self._img_herb_axis = None self._heat_map_carn_ax = None self._img_carn_axis = None @staticmethod def reset_params(): """ Resets parameters of all landscape and animal classes. """ for class_name in [ Landscape, Jungle, Savannah, Desert, Mountain, Ocean, Animal, Herbivore, Carnivore ]: class_name.reset_params() @staticmethod def set_animal_parameters(species, params): """ Set parameters for animal species. All animal parameters shall be positive. However, DeltaPhiMax and F shall be strictly positive and eta shall lie between zero and one. :param species: String, name of animal species :param params: Dict with valid parameter specification for species :raise ValueError: if parameter has invalid value or name """ class_names = {"Herbivore": Herbivore, "Carnivore": Carnivore} for param_name in params.keys(): if param_name in class_names[species].params: if params[param_name] >= 0 and param_name is not "DeltaPhiMax"\ and param_name is not "eta" and param_name is not "F": class_names[species].params[param_name] = params[ param_name] # checks special criteria for eta elif param_name is "eta" and 0 <= params[param_name] <= 1: class_names[species].params[param_name] = params[ param_name] # checks special criteria for F elif param_name is "F" and 0 < params[param_name]: class_names[species].params[param_name] = params[ param_name] # checks special criteria for DeltaPhiMax elif param_name is "DeltaPhiMax" and params[param_name] > 0: class_names[species].params[param_name] = params[ param_name] else: raise ValueError(f'{params[param_name]} is an invalid ' f'parameter value for parameter ' f'{param_name}!') else: raise ValueError(f'{param_name} is an invalid parameter name!') @staticmethod def set_landscape_parameters(landscape, params): """ Set parameters for landscape type. f_max must be positive. :param landscape: String, code letter for landscape :param params: Dict with valid parameter specification for landscape :raise ValueError: if parameter name or value is invalid """ class_names = { 'J': Jungle, 'S': Savannah, 'D': Desert, 'M': Mountain, 'O': Ocean } for param_name in params.keys(): if param_name in class_names[landscape].params.keys(): if param_name is "f_max" and params[param_name] >= 0: class_names[landscape].params[param_name] = params[ param_name] elif param_name is "alpha": class_names[landscape].params[param_name] = params[ param_name] else: raise ValueError(f'{params[param_name]} is an invalid ' f'parameter value!') else: raise ValueError(f'{param_name} is an invalid parameter name!') def add_population(self, population): """ Add a population to the island during simulation. :param population: List of dictionaries specifying population """ self.island_map.add_population(population) @property def year(self): """ Last year simulated. """ return self.num_years_simulated @property def num_animals(self): """ Total number of animals on island. """ num_animals = 0 for cell in self.island_map.map.values(): num_animals += len(cell.pop_herb) num_animals += len(cell.pop_carn) return num_animals @property def num_animals_per_species(self): """ Number of animals per species in island, as dictionary. """ num_animals_per_species = {"Herbivore": 0, "Carnivore": 0} for cell in self.island_map.map.values(): num_animals_per_species["Herbivore"] += len(cell.pop_herb) num_animals_per_species["Carnivore"] += len(cell.pop_carn) return num_animals_per_species @property def animal_distribution(self): """ Pandas DataFrame with animal count per species for each cell on island. """ data_all_cells = [] i = 0 for coord, cell in self.island_map.map.items(): row = coord[0] col = coord[1] herb = len(cell.pop_herb) carn = len(cell.pop_carn) data_all_cells.append([row, col, herb, carn]) i += 1 return pandas.DataFrame( data=data_all_cells, columns=['Row', 'Col', 'Herbivore', 'Carnivore']) def simulate(self, num_years, vis_years=1, img_years=None): """ Run simulation while visualizing the result. :param num_years: number of years to simulate :param vis_years: years between visualization updates :param img_years: years between visualizations saved to files (default: vis_years) Image files will be numbered consecutively. """ if img_years is None: img_years = vis_years self.final_year = self.year + num_years self.setup_graphics() while self.year < self.final_year: if self.year % vis_years == 0: self.update_graphics() if self.year % img_years == 0: self.save_graphics() self.island_map.run_all_seasons() self.num_years_simulated += 1 def setup_graphics(self): """ Creates four subplots for visualization of geography, number of animals per species and distribution of each species. """ # Create new figure window if self._fig is None: self._fig = plt.figure(figsize=(13, 8)) self._fig.subplots_adjust(hspace=0.2, wspace=0.2) # Add upper left subplot with features for map of island if self._map_ax is None: self._map_ax = self._fig.add_subplot(2, 2, 1) self._map_ax.set_position(pos=[0, 0.55, 0.4, 0.3]) self.create_map_graphics() self._map_ax.title.set_text('Island') # Add upper right subplot for line graph of herbivore and carnivore # populations. if self._line_graph_ax is None: self._line_graph_ax = self._fig.add_subplot(2, 2, 2) self._line_graph_ax.set_position(pos=[0.5, 0.55, 0.35, 0.35]) # Needs updating on subsequent calls to simulate() self._line_graph_ax.set_xlim(0, self.final_year + 1) # Line graph for herbivores if self._line_graph_line_herb is None: line_graph_plot_herb = self._line_graph_ax.plot( numpy.arange(0, self.final_year), numpy.full(self.final_year, numpy.nan)) self._line_graph_line_herb = line_graph_plot_herb[0] else: xdata, ydata = self._line_graph_line_herb.get_data() xnew = numpy.arange(xdata[-1] + 1, self.final_year) if len(xnew) > 0: ynew = numpy.full(xnew.shape, numpy.nan) self._line_graph_line_herb.set_data( numpy.hstack((xdata, xnew)), numpy.hstack((ydata, ynew))) # Line graph for carnivores if self._line_graph_line_carn is None: line_graph_plot_carn = self._line_graph_ax.plot( numpy.arange(0, self.final_year), numpy.full(self.final_year, numpy.nan)) self._line_graph_line_carn = line_graph_plot_carn[0] else: xdata, ydata = self._line_graph_line_carn.get_data() xnew = numpy.arange(xdata[-1] + 1, self.final_year) if len(xnew) > 0: ynew = numpy.full(xnew.shape, numpy.nan) self._line_graph_line_carn.set_data( numpy.hstack((xdata, xnew)), numpy.hstack((ydata, ynew))) # Features for line graph self._line_graph_ax.yaxis.tick_right() self._line_graph_ax.yaxis.set_label_position('right') self._line_graph_ax.legend(["Herbivore", "Carnivore"], loc='best') self._line_graph_ax.title.set_text('Population dynamics') self._line_graph_ax.set_ylabel('Number of animals') self._line_graph_ax.set_xlabel('Year') # Add lower left heat map for herbivores if self._heat_map_herb_ax is None: self._heat_map_herb_ax = self._fig.add_subplot(2, 2, 3) self._heat_map_herb_ax.set_position(pos=[0, 0, 0.4, 0.4]) self._img_herb_axis = None # Features for herbivore heat map self._heat_map_herb_ax.title.set_text('Herbivore distribution') self._heat_map_herb_ax.set_ylabel('y coordinate') self._heat_map_herb_ax.set_xlabel('x coordinate') # Add lower right heat map for carnivores if self._heat_map_carn_ax is None: self._heat_map_carn_ax = self._fig.add_subplot(2, 2, 4) self._heat_map_carn_ax.set_position(pos=[0.5, 0, 0.4, 0.4]) self._img_carn_axis = None # Features for carnivore heat map self._heat_map_carn_ax.title.set_text('Carnivore distribution') self._heat_map_carn_ax.set_ylabel('y coordinate') self._heat_map_carn_ax.set_xlabel('x coordinate') def create_map_graphics(self): """ Creates graphic of the map of the island's island_geography. The island map is static and the different landscape types are represented by different colours. """ # R G B rgb_value = { 'O': (0.0, 0.0, 1.0), # blue 'M': (0.5, 0.5, 0.5), # grey 'J': (0.0, 0.6, 0.0), # dark green 'S': (0.5, 1.0, 0.5), # light green 'D': (1.0, 1.0, 0.5) } # light yellow geogr_rgb = [[rgb_value[column] for column in row] for row in self.island_map.geogr.splitlines()] axim = self._map_ax axim.imshow(geogr_rgb) axim.set_xticks(range(len(geogr_rgb[0]))) axim.set_xticklabels(range(1, 1 + len(geogr_rgb[0]))) axim.set_yticks(range(len(geogr_rgb))) axim.set_yticklabels(range(1, 1 + len(geogr_rgb))) axim.set_ylabel('y coordinate') axim.set_xlabel('x coordinate') axlg = self._fig.add_axes([0.4, 0.55, 0.1, 0.3]) axlg.axis('off') for ix, name in enumerate( ('Ocean', 'Mountain', 'Jungle', 'Savannah', 'Desert')): axlg.add_patch( plt.Rectangle((0., ix * 0.2), 0.3, 0.1, edgecolor='none', facecolor=rgb_value[name[0]])) axlg.text(0.35, ix * 0.21, name, transform=axlg.transAxes, fontsize=8) def update_line_graph(self): """ Updates line graph for both species. """ # for herbivores ydata_herb = self._line_graph_line_herb.get_ydata() ydata_herb[self.num_years_simulated] = self.num_animals_per_species[ "Herbivore"] self._line_graph_line_herb.set_ydata(ydata_herb) # for carnivores ydata_carn = self._line_graph_line_carn.get_ydata() ydata_carn[self.num_years_simulated] = self.num_animals_per_species[ "Carnivore"] self._line_graph_line_carn.set_ydata(ydata_carn) # rescales y axis if self.ymax: self._line_graph_ax.set_ylim(0, self.ymax) else: self._line_graph_ax.set_ylim(0, self.num_animals * 1.3) def create_array_herbs(self): """ Creates array used to create heat map of herbivore population. Each cell in the array represents a cell on the island map and contains number of herbivores at that location. """ df = self.animal_distribution num_rows = df["Row"].iloc[-1] + 1 num_cols = df["Col"].iloc[-1] + 1 index = 0 array_herbs = numpy.zeros(shape=(num_rows, num_cols)) for row in range(num_rows): for col in range(num_cols): array_herbs[row, col] = df["Herbivore"].iloc[index] index += 1 return array_herbs def update_heat_map_herbs(self): """ Updates visualization of heat map for herbivores. """ if self._img_herb_axis is not None: self._img_herb_axis.set_data(self.create_array_herbs()) else: self._img_herb_axis = self._heat_map_herb_ax.imshow( self.create_array_herbs(), interpolation='nearest', vmin=0, vmax=self.cmax["Herbivore"]) plt.colorbar(self._img_herb_axis, ax=self._heat_map_herb_ax, orientation='vertical') def create_array_carns(self): """ Creates array used to create heat map of carnivore population. Each cell in the array represents a cell on the island map and contains number of carnivores at that location. """ df = self.animal_distribution num_rows = df["Row"].iloc[-1] + 1 num_cols = df["Col"].iloc[-1] + 1 index = 0 array_carns = numpy.zeros(shape=(num_rows, num_cols)) for row in range(num_rows): for col in range(num_cols): array_carns[row, col] = df["Carnivore"].iloc[index] index += 1 return array_carns def update_heat_map_carns(self): """ Updates visualization of heat map for carnivores. """ if self._img_carn_axis is not None: self._img_carn_axis.set_data(self.create_array_carns()) else: self._img_carn_axis = self._heat_map_carn_ax.imshow( self.create_array_carns(), interpolation='nearest', vmin=0, vmax=self.cmax["Carnivore"]) plt.colorbar(self._img_carn_axis, ax=self._heat_map_carn_ax, orientation='vertical') def update_graphics(self): """ Updates all graphics with current data and title. """ self.update_line_graph() self.update_heat_map_herbs() self.update_heat_map_carns() plt.suptitle(f"Simulation of year {self.year}", fontsize=26) plt.pause(1e-6) def save_graphics(self): """ Saves graphics to file, if file name is given. The image is stored as img_base + img_no + img_fmt """ if self.img_base is None: return plt.savefig(f"{self.img_base}_{self.img_no:05d}.{self.img_fmt}") self.img_no += 1 def make_movie(self, movie_fmt=_DEFAULT_MOVIE_FORMAT): """ Creates MPEG4 movie from visualization images saved. :param movie_fmt: str format for movie (default='mp4') :note: Requires ffmpeg to work. Update ffmpeg binary at top of this file. The movie is stored as img_base + movie_fmt. :raise RuntimeError: if img_base not defined or ffmpeg fails :raise ValueError: if movie format is unknown """ if self.img_base is None: raise RuntimeError("No filename defined.") if movie_fmt == 'mp4': try: subprocess.check_call([ FFMPEG_BINARY, '-i', '{}_%05d.png'.format(self.img_base), '-y', '-profile:v', 'baseline', '-level', '3.0', '-pix_fmt', 'yuv420p', '{}.{}'.format(self.img_base, movie_fmt) ]) except subprocess.CalledProcessError as err: raise RuntimeError('ERROR: ffmpeg failed with: {}'.format(err)) else: raise ValueError('Unknown movie format: ' + movie_fmt)
def test_constructor(self, example_geogr, example_ini_pop): """ Asserts that an instance of the IslandMap class can be constructed. """ island_map = IslandMap(example_geogr, example_ini_pop) assert isinstance(island_map, IslandMap)