Exemple #1
0
 def calculate_hydrology_map(self, map, edaphic_map, soil_ids_map,
                             image_insolation_map, biom):
     """
     Calculates the available water at every point on the terrain. It uses the average rainfall and groundwater from
     the biom. The water absorption and depth of the soil is also considered and the evaporation by the sun is calculated.
     :param map: Object of the map class.
     :param edaphic_map: Object of the Edaphology class. Used to get the soil depth.
     :param soil_ids_map: Map of the soil ids. Used to get the water absorption of the soil.
     :param image_insolation_map: Result of the insolation calculation. Used for the calculation of the evaporation.
     :param biom: Object of the biom class. Used to get the groundwater and rainfall values.
     :return: hydrology_map: Result of water calculations.
     """
     hydrology_map = Image(size=edaphic_map.size, dtype=np.float)
     for y in range(edaphic_map.size):
         print("Calculating hydrology: Row: " + str(y))
         for x in range(edaphic_map.size):
             depth = edaphic_map.image[y][x]
             soil_id = soil_ids_map.image[y][x]
             soil = self.controller.search_soil(soil_id)
             if depth >= 100:
                 depth_coefficient = 1.0
             else:
                 depth_coefficient = depth / 100
             water_supply = (biom.groundwater + biom.avg_rainfall_per_day
                             ) * depth_coefficient * soil.water_absorption
             evaporated_water = (
                 image_insolation_map.image[y][x] *
                 K_CALORIES_NEEDED_TO_EVAPORATE_1_G_WATER) / 1000
             if evaporated_water > water_supply:
                 evaporated_water = water_supply
             water_supply -= evaporated_water
             hydrology_map.image[y][
                 x] = water_supply  # * (map.pixel_size ** 2)
     return hydrology_map
    def draw_height_and_soil_map(self, maps):
        self.controller.load_height_and_soil_map(maps)
        self.subplot_height_map.imshow(self.controller.image_height_map.image,
                                       cmap='gray')
        if self.height_map_colorbar:
            self.height_map_colorbar.remove()
        plot = self.subplot_height_map.pcolor(
            self.controller.image_height_map.image, cmap='gray')
        self.height_map_colorbar = self.figure_height_map.colorbar(plot)

        self.subplot_texture_map.imshow(self.controller.soil_ids_map.image)
        self.canvas_height_map.draw()
        self.canvas_texture_map.draw()
        map_name = self.maps.get()
        map = self.controller.maps[map_name]
        insolation_map_file = Path("resources/results/" + map_name + "/" +
                                   map_name + "_" +
                                   self.daylight_hours.get("1.0", 'end-1c') +
                                   "daylight_hours_insolation_image.png")

        self.controller.image_insolation_map = Image(size=3, fill_color=0xFF)
        if insolation_map_file.is_file():
            self.controller.image_insolation_map.load_image(
                insolation_map_file)
        self.draw_insolation_image(self.controller.image_insolation_map)

        orographic_file = Path("resources/results/" + map_name + "/" +
                               map_name + "_orographic_normals")
        self.controller.image_orographic_map = [[[0.0, 0.0, 0.0],
                                                 [0.0, 0.0, 0.0]],
                                                [[0.0, 0.0, 0.0],
                                                 [0.0, 0.0, 0.0]]]
        if orographic_file.is_file():
            self.controller.image_orographic_map = self.controller.load_3d_list(
                orographic_file)
        self.draw_orographic_image(self.controller.image_orographic_map)

        edaphic_map_file = Path("resources/results/" + map_name + "/" +
                                map_name + "_edaphic_image.png")
        self.controller.image_edaphic_map = Image(size=3, fill_color=0xFF)
        if edaphic_map_file.is_file():
            self.controller.image_edaphic_map.load_image(edaphic_map_file)
        self.draw_edaphic_image(self.controller.image_edaphic_map)

        water_map_file = Path("resources/results/" + map_name + "/" +
                              map_name + "_water_image.png")
        self.controller.image_water_map = Image(dtype=np.float,
                                                size=3,
                                                fill_color=0xFF)
        if water_map_file.is_file():
            self.controller.image_water_map.load_image(water_map_file)
        self.draw_hydrology_image(self.controller.image_water_map)

        self.controller.image_probabilities = Image(dtype=np.float,
                                                    size=3,
                                                    fill_color=0xFF)
        self.draw_probability_image(self.controller.image_probabilities)
 def load_texture_map(self):
     rep = askopenfilenames(parent=self, initialdir='/', initialfile='tmp',
                            filetypes=[("Pictures", "*.png")])
     if len(rep) > 0:
         self.texture_map_path = rep[0]
         soil_ids_map = Image()
         soil_ids_map.load_image(self.texture_map_path)
         self.subplot_texture_map.imshow(soil_ids_map.image)
         self.canvas_texture_map.draw()
 def load_height_map(self):
     rep = askopenfilenames(parent=self, initialdir='/', initialfile='tmp',
                            filetypes=[("Pictures", "*.png")])
     if len(rep) > 0:
         self.height_map_path = rep[0]
         image_height_map = Image()
         image_height_map.load_image(self.height_map_path)
         self.subplot_height_map.imshow(image_height_map.image, cmap='gray')
         self.canvas_height_map.draw()
Exemple #5
0
 def load_height_and_soil_map(self, map_name):
     """
     It creates two images and loads the height- and soil- map into it.
     :param map_name: String of the map name. It is used to find the images on disk.
     """
     map = self.maps[map_name]
     self.image_height_map = Image()
     self.image_height_map.load_image(map.height_map_path)
     self.soil_ids_map = Image()
     self.soil_ids_map.load_image(map.texture_map_path)
Exemple #6
0
    def test_CalculateInsolationDarkImage(self):
        # given
        image_size = 4
        input_image = Image(size=image_size, fill_color=100)
        insolation = Insolation(input_image)
        expected_image = Image(size=image_size,
                               fill_color=0)  # completely dark
        sun_position = [2, 2, 10]

        # when
        insolation.calculate_insolation_cpu(sun_position)

        # then
        self.assertEqual(expected_image, insolation.insolation_image)
Exemple #7
0
    def test_CalculateInsolationWhiteImage(self):
        # given
        image_size = 4
        input_image = Image(size=image_size, fill_color=100)
        insolation = Insolation(input_image)
        expected_image = Image(
            size=image_size,
            fill_color=CAL_PER_HOUR_PER_PIXEL)  # every pixel receives calories
        sun_position = [2, 2, 200]

        # when
        insolation.calculate_insolation_cpu(sun_position)

        # then
        self.assertEqual(expected_image, insolation.insolation_image)
Exemple #8
0
    def test_CalculateInsolationForDaylightHours(self):
        # given
        image_size = 10
        input_image = Image(size=image_size, fill_color=0)
        insolation = Insolation(input_image)
        daylight_hours = 7
        # every pixel receives calories per hour
        expected_image = Image(size=image_size,
                               fill_color=CAL_PER_HOUR_PER_PIXEL *
                               daylight_hours)

        # when
        insolation.calculate_insolation_for_daylight_hours(daylight_hours)

        # then
        self.assertEqual(expected_image, insolation.insolation_image)
 def calculate_soil_depth(map, size, angles):
     """
     It calculates the soil depth at every point of the terrain. It uses the previously calculated angles (steepness).
     :param map: Object of Map class. Used to get the max soil depth.
     :param size: Integer. Size of the terrain. Used to initialize the image.
     :param angles: 3D-List of all normal vectors.
     :return: angles: List all angles on the terrain.
     """
     soil_depths = Image(size=size)
     x = 0
     y = 0
     for rows in angles:
         print("Calculating edaphology: Row: " + str(y))
         for angle in rows:
             depth = (1 - angle / 90) * map.max_soil_depth
             soil_depths.image[y][x] = depth
             x += 1
         y += 1
         x = 0
     return soil_depths
Exemple #10
0
    def test_ConstructorShouldInitializeCorrectly(self):
        # given
        fill_color = 10

        # when
        image = Image(size=2, fill_color=fill_color)

        # then
        self.assertEqual(fill_color, image.image[0][0])
        self.assertEqual(fill_color, image.image[0][1])
        self.assertEqual(fill_color, image.image[1][0])
        self.assertEqual(fill_color, image.image[1][1])
Exemple #11
0
 def prepare_insolation_calculation(self, map_name, daylight_hours, sun_start_elevation, sun_start_azimuth,
                                    sun_max_elevation, reflection_coefficient):
     """
     It finds the correct map obect and creates an image and an object of insolation class. Then the heightmap
     gets loaded and the calculation of the insolation gets started. The results will be shown in the UI and saved.
     :param map_name: String of the current map name
     :param daylight_hours: Integer of the number of daylight hours
     :param sun_start_elevation: Float of the start elevation of the sun
     :param sun_start_azimuth: Float of the start azimuth of the sun
     :param sun_max_elevation: Float of the maximal sun elevation (noon)
     :param reflection_coefficient: Float of the reflection coeficient. It states how much light of the neighbour
             pixel will be reflected.
     """
     map = self.maps[map_name]
     self.image_insolation_map = Image(size=self.image_height_map.size)
     insolation = Insolation(self)
     self.image_height_map.load_image(map.height_map_path)
     self.image_insolation_map = insolation.calculate_actual_insolation(map, daylight_hours, sun_start_elevation,
                                                                        sun_start_azimuth, sun_max_elevation,
                                                                        reflection_coefficient)
     self.main_window.frames['ProbabilityCloudWindow'].draw_insolation_image(self.image_insolation_map)
     save_path = "resources/results/" + map_name + "/" + map_name + "_" + str(daylight_hours) + "daylight_hours_insolation_image.png"
     self.image_insolation_map.save_image(save_path)
Exemple #12
0
 def calculate_probabilities(self):
     """
     Calculates the final probability by selecting the lowest probability at every pixel.
     :return: final_probabilities: List of final probabilities at each pixel.
     """
     all_probabilities = [
         self.calculate_insolation_probabilities(),
         self.calculate_soil_demand_probabilities(),
         self.calculate_soil_depth_probabilities(),
         self.calculate_water_demand_probabilities()
     ]
     final_probabilities = Image(size=self.controller.image_height_map.size,
                                 dtype=np.float)
     reasons_for_not_growing = [0, 0, 0, 0]
     for y in range(self.controller.image_height_map.size):
         for x in range(self.controller.image_height_map.size):
             probability = 1.0
             for i in range(len(all_probabilities)):
                 if all_probabilities[i][y][x] < probability:
                     probability = all_probabilities[i][y][x]
                     if probability == 0.0:
                         reasons_for_not_growing[i] += 1
             final_probabilities.image[y][x] = probability
     location_factor_with_max_reasons_for_not_growing = 0
     for j in range(len(reasons_for_not_growing)):
         if j >= 2:  # soil demand should be skipped because it is a obvious reason
             if reasons_for_not_growing[j] > reasons_for_not_growing[
                     location_factor_with_max_reasons_for_not_growing]:
                 location_factor_with_max_reasons_for_not_growing = j
     location_factors = [
         "insolation", "soil demand", "soil depth", "water demand"
     ]
     print(
         "Main reason for not growing (except soil demand): " +
         location_factors[location_factor_with_max_reasons_for_not_growing])
     return final_probabilities
Exemple #13
0
class Controller:
    """
    The Controller class controls the flow of the application. It starts the UI, loads all data and controlls
    the calculation of the maps (insolation, orography, edaphology and hydrology) by starting the other logic
    classes. It also starts the calculation of the probability map. All results will be saved and can be loaded
    later on.
    """

    def __init__(self):
        self.image_height_map = None
        self.soil_ids_map = None
        self.image_insolation_map = None
        self.image_orographic_map = None
        self.image_edaphic_map = None
        self.image_water_map = None
        self.image_probabilities = None
        self.bioms = {}
        self.load_bioms()
        self.soils = {}
        self.load_soils()
        self.vegetations = {}
        self.load_vegetations()
        self.maps = {}
        self.load_maps()
        self.main_window = MainWindow(self)

    def load_height_and_soil_map(self, map_name):
        """
        It creates two images and loads the height- and soil- map into it.
        :param map_name: String of the map name. It is used to find the images on disk.
        """
        map = self.maps[map_name]
        self.image_height_map = Image()
        self.image_height_map.load_image(map.height_map_path)
        self.soil_ids_map = Image()
        self.soil_ids_map.load_image(map.texture_map_path)
        # self.transform_and_save_soil_id_map(map.texture_map_path)
        # self.save_image_as_csv(self.image_height_map.image)

    def transform_and_save_soil_id_map(self, path):
        """
        This function is used to transform all occuring IDs in a soil map to wanted IDs (usually the IDs of the
        created soils). To transform the IDs you have to change the transformation list. This function is used
        as a workaround if you can't find a valid soil-map.
        :param path: String of the path to the map that shall be transformed.
        """
        self.soil_ids_map.filter_unique_numbers_from_2d_array()
        transformation_list = {0: 40, 9362: 80, 18724: 120, 28086: 160, 37449: 200, 46811: 240}
        self.soil_ids_map.transform_image_to_valid_soils(transformation_list)
        self.soil_ids_map.filter_unique_numbers_from_2d_array()  # check if the transformation was successfull
        self.soil_ids_map.save_image(path)

    def prepare_insolation_calculation(self, map_name, daylight_hours, sun_start_elevation, sun_start_azimuth,
                                       sun_max_elevation, reflection_coefficient):
        """
        It finds the correct map obect and creates an image and an object of insolation class. Then the heightmap
        gets loaded and the calculation of the insolation gets started. The results will be shown in the UI and saved.
        :param map_name: String of the current map name
        :param daylight_hours: Integer of the number of daylight hours
        :param sun_start_elevation: Float of the start elevation of the sun
        :param sun_start_azimuth: Float of the start azimuth of the sun
        :param sun_max_elevation: Float of the maximal sun elevation (noon)
        :param reflection_coefficient: Float of the reflection coeficient. It states how much light of the neighbour
                pixel will be reflected.
        """
        map = self.maps[map_name]
        self.image_insolation_map = Image(size=self.image_height_map.size)
        insolation = Insolation(self)
        self.image_height_map.load_image(map.height_map_path)
        self.image_insolation_map = insolation.calculate_actual_insolation(map, daylight_hours, sun_start_elevation,
                                                                           sun_start_azimuth, sun_max_elevation,
                                                                           reflection_coefficient)
        self.main_window.frames['ProbabilityCloudWindow'].draw_insolation_image(self.image_insolation_map)
        save_path = "resources/results/" + map_name + "/" + map_name + "_" + str(daylight_hours) + "daylight_hours_insolation_image.png"
        self.image_insolation_map.save_image(save_path)

    def prepare_orographic_calculation(self, map_name):
        """
        It loads the correct map object, starts the orograhic calculation, displays the result in the UI and
        saves it as an image.
        :param map_name: name of the current map
        """
        map = self.maps[map_name]
        self.image_orographic_map = Orography.calculate_normal_map(map, self.image_height_map)
        self.main_window.frames['ProbabilityCloudWindow'].draw_orographic_image(self.image_orographic_map)
        self.save_3d_list(self.image_orographic_map, "resources/results/" + map_name + "/" + map_name + "_orographic_normals")

    def prepare_edaphic_calculation(self, map_name):
        """
        It loads the correct map object, calculates all angles on the map (between the normal vector and the z-vector),
        starts the edaphic calculation, displays the result in the UI and saves it as an image.
        :param map_name: name of the current map
        """
        map = self.maps[map_name]
        angles = Edaphology.calculate_angles(self.image_orographic_map)
        self.image_edaphic_map = Edaphology.calculate_soil_depth(map, self.image_height_map.size, angles)
        self.main_window.frames['ProbabilityCloudWindow'].draw_edaphic_image(self.image_edaphic_map)
        self.image_edaphic_map.save_image("resources/results/" + map_name + "/" + map_name + "_edaphic_image.png")

    def prepare_water_calculation(self, map_name):
        """
        It loads the correct map and biom object, starts the hydrologic calculation, displays the result in the UI and
        saves it as an image.
        :param map_name: name of the current map
        """
        map = self.maps[map_name]
        biom = map.biom
        hydrology = Hydrology(self)
        self.image_water_map = hydrology.calculate_hydrology_map(map, self.image_edaphic_map, self.soil_ids_map,
                                                                 self.image_insolation_map, biom)
        self.main_window.frames['ProbabilityCloudWindow'].draw_hydrology_image(self.image_water_map)
        self.image_water_map.save_image("resources/results/" + map_name + "/" + map_name + "_water_image.png")

    def calculate_all(self, map_name, daylight_hours, sun_start_elevation, sun_start_azimuth, sun_max_elevation,
                      reflection_coefficient):
        """
        Starts all calculation. This function is used for very large maps. So the user does not have to check the
        state of the application all the time. You can start all calculations and come back a few hours later.
        :param map_name: String of the current map name.
        :param daylight_hours: Integer of the number of daylight hours.
        :param sun_start_elevation: Float of the start elevation of the sun.
        :param sun_start_azimuth: Float of the start azimuth of the sun.
        :param sun_max_elevation: Float of the maximal sun elevation (noon).
        :param reflection_coefficient: Float of the reflection coeficient. It states how much light of the neighbour
                pixel will be reflected.
        """
        self.prepare_insolation_calculation(map_name, daylight_hours, sun_start_elevation, sun_start_azimuth,
                                            sun_max_elevation, reflection_coefficient)
        self.prepare_orographic_calculation(map_name)
        self.prepare_edaphic_calculation(map_name)
        self.prepare_water_calculation(map_name)

    def prepare_probabilites_calculation(self, vegetation_name, map_name):
        """
        It creates a probability object, starts the calculation of the probabilites and displays the result in the UI.
        :param vegetation_name: String. Name of the vegetation for which the probabilites will be calculated.
        :param map_name: String. Name of the current map.
        """
        probability_calculator = Probabilities(self, vegetation_name, map_name)
        self.image_probabilities = probability_calculator.calculate_probabilities()
        self.main_window.frames['ProbabilityCloudWindow'].draw_probability_image(self.image_probabilities)

    def search_soil(self, soil_id):
        """
        Searches for the soil object in the soil list with the help of the soil ID.
        :param soil_id: ID of the soil for which the object from the list shall be found.
        :return: soil_value: Soil object from the soil list.
        """
        for soil_name, soil_value in self.soils.items():
            if soil_value.id == soil_id:
                return soil_value
        print('Soil id (' + str(soil_id) + ') could not be found!')
        return self.soils['NotFound']  # raise Exception('Soil id could not be found!')

    def load_bioms(self):
        """
        Loads all bioms from the bioms.yml into a list.
        """
        bioms = {}
        bioms_file = Path("resources/data/bioms.yml")
        if bioms_file.is_file():
            with open(bioms_file, 'r') as stream:
                try:
                    bioms_dict = yaml.safe_load(stream)
                    if bioms_dict is not None:
                        for biom_name, biom_values in bioms_dict.items():
                            bioms[biom_name] = Biom(biom_name,
                                                    float(biom_values['atmospheric_diffusion']),
                                                    float(biom_values['atmospheric_absorption']),
                                                    float(biom_values['cloud_reflection']),
                                                    float(biom_values['avg_rainfall_per_day']),
                                                    float(biom_values['groundwater']))
                except yaml.YAMLError as exc:
                    print(exc)
        self.bioms = bioms

    def load_soils(self):
        """
        Loads all soils from the soils.yml into a list.
        """
        soils = {}
        soils_file = Path("resources/data/soil_types.yml")
        if soils_file.is_file():
            with open(soils_file, 'r') as stream:
                try:
                    soils_dict = yaml.safe_load(stream)
                    if soils_dict is not None:
                        for soil_name, soil_values in soils_dict.items():
                            soils[soil_name] = Soil(int(soil_values['id']), soil_name, float(soil_values['albedo']),
                                                    float(soil_values['water_absorption']))
                except yaml.YAMLError as exc:
                    print(exc)
        self.soils = soils

    def load_vegetations(self):
        """
        Loads all vegetations from the vegetation_types.yml into a list.
        """
        vegetations = {}
        vegetations_file = Path("resources/data/vegetation_types.yml")
        if vegetations_file.is_file():
            with open(vegetations_file, 'r') as stream:
                try:
                    vegetations_dict = yaml.safe_load(stream)
                    if vegetations_dict is not None:
                        for vegetation_name, vegetation_values in vegetations_dict.items():
                            vegetations[vegetation_name] = Vegetation(vegetation_name,
                                                                      float(vegetation_values['energy_demand']),
                                                                      float(vegetation_values['water_demand']),
                                                                      self.soils[vegetation_values['soil_demand']],
                                                                      float(vegetation_values['soil_depth_demand']))
                except yaml.YAMLError as exc:
                    print(exc)
        self.vegetations = vegetations

    def load_maps(self):
        """
        Loads all maps from the maps.yml into a list.
        """
        maps = {}
        maps_file = Path("resources/data/maps.yml")
        if maps_file.is_file():
            with open(maps_file, 'r') as stream:
                try:
                    maps_dict = yaml.safe_load(stream)
                    if maps_dict is not None:
                        for map_name, map_values in maps_dict.items():
                            maps[map_name] = Map(map_name, self.bioms[map_values['biom']],
                                                 map_values['height_map_path'],
                                                 map_values['texture_map_path'],
                                                 map_values['height_conversion'],
                                                 map_values['max_soil_depth'],
                                                 map_values['pixel_size'])
                except yaml.YAMLError as exc:
                    print(exc)
        self.maps = maps

    @staticmethod
    def save_3d_list(list, path):
        """
        It saves the result of the orographic class (normal map) as a file.
        :param list: List of the normal vectors of the current map.
        :param path: String of the path where the file should be saved.
        """
        if not os.path.exists(os.path.dirname(path)):
            os.makedirs(os.path.dirname(path))
        output = open(path, 'wb')
        pickle.dump(list, output)
        output.close()

    @staticmethod
    def load_3d_list(path):
        """
        Loads the normal vectors from a file.
        :param path: String of the path of the file that will be loaded.
        :return: list: List of the loaded normal vectors (normal map).
        """
        pkl_file = open(path, 'rb')
        list = pickle.load(pkl_file)
        pkl_file.close()
        return list

    @staticmethod
    def save_image_as_csv(image):
        np.savetxt("resources/height_map.csv", image, delimiter=',', fmt='%s')
Exemple #14
0
    def __init__(self, parent, main_window, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        row = 0
        column = 0

        self.canvas = tk.Canvas(self, width=main_window.window_width-20, height=main_window.window_height)
        self.canvas.grid(row=0, column=0, sticky="nsew")

        scrollbar = tk.Scrollbar(self, command=self.canvas.yview)
        scrollbar.grid(row=0, column=1, sticky='ns')

        self.canvas.configure(yscrollcommand=scrollbar.set)

        # update scrollregion after starting 'mainloop'
        # when all widgets are in canvas
        self.canvas.bind('<Configure>', self.on_configure)

        self.frame = tk.Frame(self.canvas)
        self.canvas.create_window((0, 0), window=self.frame, anchor='nw')

        tk.Button(self.frame, text="< Back to menu",
                           command=lambda: main_window.show_frame("MenuWindow")).grid(row=row, column=column, pady=10)
        row += 1
        tk.Label(self.frame, text="Maps:", font='Helvetica 18 bold').grid(row=row, column=column, pady=10)
        row += 1
        tk.Button(self.frame, text="Create new map >",
                  command=lambda: main_window.show_frame("NewMapWindow")).grid(row=row, column=column, pady=10, padx=10)
        column += 1
        for map in controller.maps.values():
            row += 1
            tk.Label(self.frame, text=map.name, font='Helvetica 16').grid(row=row, column=column, pady=(50, 0), columnspan=4, sticky='S')
            row += 1
            tk.Label(self.frame, text="Biom:").grid(row=row, column=column + 1, pady=5, sticky='E')
            tk.Label(self.frame, text=map.biom.name).grid(row=row, column=column + 2, pady=5, sticky='W')
            row += 1
            tk.Label(self.frame, text="Height conversion:").grid(row=row, column=column + 1, pady=5, sticky='E')
            tk.Label(self.frame, text=str(map.height_conversion) + " meter/unit").grid(row=row, column=column + 2, pady=5, sticky='W')
            row += 1
            tk.Label(self.frame, text="Maximum soil depth:").grid(row=row, column=column + 1, pady=5, sticky='E')
            tk.Label(self.frame, text=str(map.max_soil_depth) + " cm").grid(row=row, column=column + 2, pady=5, sticky='W')
            row += 1
            tk.Label(self.frame, text="Pixel size:").grid(row=row, column=column + 1, pady=5, sticky='E')
            tk.Label(self.frame, text=str(map.pixel_size) + " m").grid(row=row, column=column + 2, pady=5, sticky='W')
            row += 1
            figure_height_map = Figure(figsize=(3, 3))
            subplot_height_map = figure_height_map.add_subplot()
            subplot_height_map.title.set_text('Height map')
            canvas_height_map = FigureCanvasTkAgg(figure_height_map, master=self.frame)
            canvas_height_map.get_tk_widget().grid(row=row, column=column + 1)
            height_map = Image()
            height_map.load_image(map.height_map_path)
            subplot_height_map.imshow(height_map.image, cmap='gray')

            figure_texture_map = Figure(figsize=(3, 3))
            subplot_texture_map = figure_texture_map.add_subplot()
            subplot_texture_map.title.set_text('Soil-IDs map')
            canvas_texture_map = FigureCanvasTkAgg(figure_texture_map, master=self.frame)
            canvas_texture_map.get_tk_widget().grid(row=row, column=column + 2)
            texture_map = Image()
            texture_map.load_image(map.texture_map_path)
            subplot_texture_map.imshow(texture_map.image)