Пример #1
0
class LeafletMap:
    def __init__(self, bounds: tuple):
        self.layer = None
        self._leaflet_map = Map(layers=(basemap_to_tiles(
            basemaps.OpenStreetMap.BlackAndWhite), ),
                                name="Leaflet Map",
                                center=center(bounds),
                                zoom=12,
                                scroll_wheel_zoom=True)
        self._leaflet_map.add_control(FullScreenControl())

    @property
    def map(self):
        return self._leaflet_map

    def update(self, layer: Layer):
        self.layer = layer
        self._remove_layers()
        self._update_layers()

    def _remove_layers(self):
        for layer in self._leaflet_map.layers:
            if isinstance(layer, TileLayer):
                continue
            self._leaflet_map.remove_layer(layer)

    def _update_layers(self):
        if self.layer.empty:
            return
        self._leaflet_map.add_layer(self.layer.layer)
Пример #2
0
class MapRegion:
    def __init__(self, center=(41.8204600, 1.8676800), zoom=9):
        self.map = Map(center=center,
                       zoom=zoom,
                       basemap=basemaps.OpenStreetMap.HOT)

        polygon = Polygon(locations=[[]], color="green", fill_color="green")

        def handle_click(**kwargs):
            if kwargs.get('type') == 'click':
                pol = next(layer for layer in self.map.layers
                           if isinstance(layer, Polygon))
                coords = kwargs.get('coordinates')
                if (len(polygon.locations) == 0):
                    pol.locations[0].extend([coords, coords])
                else:
                    pol.locations[0].insert(1, coords)

                self.map.remove_layer(pol)
                other = Polygon(locations=pol.locations,
                                color="green",
                                fill_color="green")
                self.map.add_layer(other)

            if kwargs.get('type') == 'contextmenu':
                pol = next(layer for layer in self.map.layers
                           if isinstance(layer, Polygon))
                self.map.remove_layer(pol)
                other = Polygon(locations=[[]],
                                color="green",
                                fill_color="green")
                self.map.add_layer(other)

        self.map.on_interaction(handle_click)
        self.map.add_layer(polygon)
        display(self.map)

    def get_region(self):
        locations = [[]]

        for layer in self.map.layers:
            if isinstance(layer, Polygon):
                locations[0] = [[loc[1], loc[0]] for loc in layer.locations[0]]

        if (len(locations[0]) > 0):
            locations[0].append(locations[0][0])

        return locations[0]
Пример #3
0
def clearLayers(worldMap: lf.Map,
                layerType: type,
                dispose: bool = True) -> int:
    ''' Remove all layers based on the given layerType 
      @worldMap: Map object
      @layerType: type of layer to be removed
      @dispose: if True, delete the removed layer
      Returns: number of removed layers
  '''
    layers = list(
        filter(lambda layer: isinstance(layer, layerType), worldMap.layers))
    map(lambda layer: worldMap.remove_layer(layer), layers)

    if (dispose):
        for layer in layers:
            del layer

    return len(list(layers))
Пример #4
0
def removeLayerByType(worldMap: lf.Map,
                      layerName: str,
                      layerType: type,
                      dispose: bool = True) -> bool:
    ''' Remove a heatmap layer by its name 
      @worldMap: Map object
      @layerName: name of the layer
      @layerType: type of the layer
      @dispose: if True, delete the removed layer
      Returns: True if removed, False if not
  '''
    layers = list(
        filter(
            lambda layer: isinstance(layer, layerType) and layer.name ==
            layerName, worldMap.layers))
    map(lambda layer: worldMap.remove_layer(layer), layers)

    if (dispose):
        for layer in layers:
            del layer

    return len(layers) > 0
Пример #5
0
class DatasetAnnotatorDetection:
    
    def __init__(self, classes, images, output_path, output_name, images_classes=None):
        # task classes
        self.__classes = classes
        self.__current_image_annotations = []
        self.__current_class_for_ann = []
        self.__output_path = output_path
        self.__output_name = output_name
        self.__file_path = os.path.join(self.__output_path, self.__output_name + ".json")
        self.__images = images
        # classes for each img
        self.__images_classes = images_classes
        self.__current_img = -1

        self.__image_id = -1
        self.__annotation_id = -1
        self.__selected_ann = None

        if os.path.exists(self.__file_path):
            self.__load_coco_file()
        else:
            self.__create_coco_format()

        self.__id_for_class = {cl['name']: cl['id'] for cl in self.__CATEGORIES}

        self.__create_btns()

        self.__progress = widgets.IntProgress(min=0, max=len(images), value=1, description='{}/{}'.format(1, len(images)))
        self.__progress.bar_style = 'info'
        self.__title_lbl = widgets.Label(value="title")
        self.__create_map()
        self.__create_classes_btns()
        self.__validation_show = widgets.HTML(value="")
        self.__map_classes = widgets.HBox(children=[self.__map, widgets.VBox(children=self.__classes_btns)])
        self.__all_widgets = widgets.VBox(children=[self.__progress, self.__buttons, self.__validation_show, self.__title_lbl, self.__map_classes])
 
    
    # create coco file format
    def __create_coco_format(self):
        self.__INFO = {
            "description": "Dataset",
            "url": "www.polimi.it",
            "version": "0.1.0",
            "year": 2020,
            "contributor": "Polimi",
            "date_created": datetime.today().strftime('%Y-%m-%d-%H:%M:%S')
        }
        self.__LICENSES = [
            {
                "id": 0,
                "name": "Attribution-NonCommercial-ShareAlike License",
                "url": "http://creativecommons.org/licenses/by-nc-sa/2.0/"
            }
        ]

        self.__create_categories()
        self.__IMAGES = []
        self.__ANNOTATIONS = []
    
    # load already creted coco file
    def __load_coco_file(self):
        with open(self.__file_path, 'r') as f:
            dictionary_with_data = json.load(f)

        self.__INFO = dictionary_with_data['info']
        self.__LICENSES = dictionary_with_data['licenses']
        self.__CATEGORIES = dictionary_with_data['categories']
        self.__IMAGES = dictionary_with_data['images']
        self.__ANNOTATIONS = dictionary_with_data['annotations']


        assert set(self.__classes) == set(
            [c['name'] for c in self.__CATEGORIES]), "Classes in annotator and json must be equal"
    
    # get not used ids for annotations (deleted ann creates usable id)
    def __get_missing_ids(self, lst):
        ids = [el['id'] for el in lst]
        if len(ids) > 0:
            return sorted(set(range(min(ids), max(ids)+1)) - set(ids))
        return []
    
    # save current data to coco format
    def __save_coco_file(self):

        file_name = self.__get_image_name(self.__images[self.__current_img])
       
        # remove annotations and image from list (will be added again later)
        self.__ANNOTATIONS = list(filter(lambda x: x['image_id'] != self.__image_id, self.__ANNOTATIONS))
        self.__IMAGES = list(filter(lambda x: x['id'] != self.__image_id, self.__IMAGES))

        h, w, hh, ww, off_h, off_w = self.__img_coords[:]

        free_ann_ids = self.__get_missing_ids(self.__ANNOTATIONS)
        
        #print('Missing ids', free_ann_ids)

        for idx, ann in enumerate(self.__current_image_annotations):
            ann_cl = self.__current_class_for_ann[idx]
            coordinates = ann.bounds
            # rectangle opposite coordinates wrt geojson
            hs = [c[0] for c in coordinates]
            ws = [c[1] for c in coordinates]
            min_h, max_h = max(hs), min(hs)
            min_w, max_w = min(ws), max(ws)

            h_ratio = h / hh
            w_ratio = w / ww
            # map coords to img coords
            min_h = (min_h - off_h) * h_ratio
            max_h = (max_h - off_h) * h_ratio
            min_w = (min_w - off_w) * w_ratio
            max_w = (max_w - off_w) * w_ratio
            
            min_h = h - min_h
            max_h = h - max_h

            if len(free_ann_ids) > 0:
                ann_id = free_ann_ids.pop(0)
            else:
                ann_id = len(self.__ANNOTATIONS)

            annotation_info = {
                "id": ann_id,
                "image_id": self.__image_id,
                "category_id": ann_cl,
                "iscrowd": False,
                # "area": area.tolist(),
                "bbox": [min_w, min_h, max_w - min_w, max_h - min_h],
                # "segmentation": segmentation
            }
            self.__annotation_id = ann_id
            self.__ANNOTATIONS.append(annotation_info)
            #print('Saved id', ann_id)
        image_info = {
            "id": self.__image_id,
            "file_name": file_name,
            "width": w,
            "height": h,
            "date_captured": datetime.today().strftime('%Y-%m-%d-%H:%M:%S'),
            "license": 0,
            # "coco_url": coco_url,
            # "flickr_url": flickr_url
        }
        self.__IMAGES.append(image_info)

        dictionary_with_data = {'info': self.__INFO, 'licenses': self.__LICENSES, 'categories': self.__CATEGORIES,
                                'images': self.__IMAGES, 'annotations': self.__ANNOTATIONS}
        with open(self.__file_path, 'w') as f:
            json.dump(dictionary_with_data, f, indent=4)
    
    # get image name
    def __get_image_name(self, img_path):
        return os.path.basename(img_path)
    
    def __get_image_name_no_ext(self, img_path):
        return os.path.splitext(self.__get_image_name(img_path))[0]
    
    # get image id
    def __get_current_image_id(self):
        img_name = self.__get_image_name(self.__images[self.__current_img])
        
        for img in self.__IMAGES:
            if img['file_name'] == img_name:
                return img['id']
        if len(self.__IMAGES) > 0:
            return max(self.__IMAGES, key=lambda x: x['id'])['id'] + 1
        return 0
    
    # load existing annotations
    def __load_annotations(self):
        img_id = self.__get_current_image_id()
        # resize coords to fit in map
        h_i, w_i, hh, ww, offset_h, offset_w = self.__img_coords[:]
        h_ratio = hh / h_i
        w_ratio = ww / w_i

        for ann in self.__ANNOTATIONS:
            if ann['image_id'] == img_id:
                # create rectangle layer
                min_w, min_h, w, h = ann['bbox'][:]
                max_w = min_w + w
                max_h = min_h + h
                
                min_h = h_i - min_h
                max_h = h_i - max_h
                # coords to map coords
                min_h = min_h * h_ratio + offset_h
                max_h = max_h * h_ratio + offset_h
                min_w = min_w * w_ratio + offset_w
                max_w = max_w * w_ratio + offset_w

                rectangle = self.__create_rectangle(((min_h, min_w), (max_h, max_w)), default_class=ann['category_id'])
                rectangle.color = "green"
                rectangle.fill_color = "green"

                self.__map.add_layer(rectangle)
                self.__current_image_annotations.append(rectangle)
                self.__current_class_for_ann.append(ann['category_id'])
        #print('Current annotations', self.__current_class_for_ann)
    
    # create coco categories
    def __create_categories(self):
        self.__CATEGORIES = []
        for idx, cl in enumerate(self.__classes):
            proto = {
                'id': idx,
                'name': cl,
                'supercategory': ''
            }
            self.__CATEGORIES.append(proto)
    
    # create buttons for navigation
    def __create_btns(self):
        

        self.__next_button = widgets.Button(description=labels_str.str_btn_next)
        self.__reset_button = widgets.Button(description=labels_str.str_btn_reset)
        self.__previous_button = widgets.Button(description=labels_str.str_btn_prev)
        self.__delete_button = widgets.Button(description=labels_str.str_btn_delete_bbox, disabled=True)

        self.__next_button.on_click(self.__on_next_button_clicked)
        self.__reset_button.on_click(self.__on_reset_button_clicked)
        self.__previous_button.on_click(self.__on_previous_button_clicked)
        self.__delete_button.on_click(self.__on_delete)

        self.__buttons = widgets.HBox(children=[self.__previous_button, self.__next_button, 
                                                self.__delete_button, self.__reset_button])

    
    # create radio buttons with classes
    def __create_classes_btns(self):
        # TODO: CHANGE TO RADIO BUTTON
        self.__classes_btns = []
        for c in self.__classes:   
            layout = widgets.Layout(width='200px',height='25px')
            box = widgets.Checkbox(value=False,
                                   description=c,
                                   disabled=True,
                                   layout=layout,
                                   indent=False,
                                  )
            box.observe(self.__on_class_selected)
            self.__classes_btns.append(box)
        self.__classes_btns_interaction_disabled = False
    
    # reset all classes btns/checkbox/radio
    def __reset_classes_btns(self):
        # do not handle change value during reset
        self.__classes_btns_interaction_disabled = True
        for b in self.__classes_btns:
            b.value = False if self.__selected_class is None else b.description == self.__selected_class
            b.disabled = self.__selected_ann is None
        # enable handle change value for user interaction
        self.__classes_btns_interaction_disabled = False
    
    # interaction with classes btns/checkbox/radio
    def __on_class_selected(self, b):
        self.__clear_validation()
        if self.__classes_btns_interaction_disabled:
            return
        if self.__selected_ann is None:
            return
        if b['name'] == 'value':
            old_v = b['old']
            new_v = b['new']
            if new_v:
                self.__selected_class = b['owner'].description
                self.__current_class_for_ann[self.__selected_ann] = self.__classes.index(self.__selected_class)
            else:
                self.__selected_class = None
                self.__current_class_for_ann[self.__selected_ann] = None
            
            #print(old_v, new_v, self.__selected_class, self.__current_class_for_ann[self.__selected_ann])
                
            self.__reset_classes_btns()
        
    # click on rectangle layer
    def __handle_click(self, **kwargs):
        
        if kwargs.get('type') == 'click':
            self.__clear_validation()
            click_coords = kwargs.get('coordinates')
            clicked_ann = None
            # find clicked annotations (can be more than 1 if overlapping)
            clicked_size = None
            for idx, ann in enumerate(self.__current_image_annotations):
                coordinates = ann.bounds
                # rectangle opposite coordinates wrt geojson
                hs = [c[0] for c in coordinates]
                ws = [c[1] for c in coordinates]
                min_h, max_h = min(hs), max(hs)
                min_w, max_w = min(ws), max(ws)
                # don't break so if two rectangles are overlapping I take only the last drawed
                if min_h <= click_coords[0] <= max_h and min_w <= click_coords[1] <= max_w:  
                    curr_size = (max_h - min_h) * (max_w - min_w)
                    if clicked_size is None or curr_size < clicked_size:
                        clicked_size = curr_size
                        clicked_ann = idx
                        
            if clicked_ann is not None:

                # change color to green
                # +2 because layer 0 is map, layer 1 is overlay
                self.__selected_ann = clicked_ann
                self.__delete_button.disabled = False
                self.__reset_colors_bboxes()
                
                current_class = self.__current_class_for_ann[self.__selected_ann]
                self.__selected_class = None if current_class is None else self.__classes[current_class]
                self.__reset_classes_btns()

            # it should not enter here because click is handled only by annotations
            else:
                self.__selected_ann = None
                self.__selected_class = None
                self.__reset_colors_bboxes()
                self.__reset_classes_btns()
                self.__delete_button.disabled = True
                
    
    # reset bboxes to green or red colors
    def __reset_colors_bboxes(self):
        for i in range(len(self.__current_image_annotations)):
            # blue selected annotation
            if self.__selected_ann is not None and i == self.__selected_ann:
                self.__map.layers[i + 2].color = "blue"
                self.__map.layers[i + 2].fill_color = "blue"
            # red annotation without class
            elif self.__current_class_for_ann[i] is None:
                self.__map.layers[i + 2].color = "red"
                self.__map.layers[i + 2].fill_color = "red"
            # green annotation with class
            else:
                self.__map.layers[i + 2].color = "green"
                self.__map.layers[i + 2].fill_color = "green"
    
    # delete selected layer, class and geojson
    def __on_delete(self, b):
        if not self.__selected_ann is None:
            # +2 because layer 0 is map, layer 1 is overlay and rectangles start from index 2
            self.__map.remove_layer(self.__map.layers[self.__selected_ann + 2])
            self.__current_image_annotations.pop(self.__selected_ann)
            self.__current_class_for_ann.pop(self.__selected_ann)
            # print('deleted')
            self.__selected_ann = None
            self.__selected_class = None
            self.__reset_colors_bboxes()
            self.__reset_classes_btns()
            self.__delete_button.disabled = True

        

    # create annotation rectangle
    def __create_rectangle(self, bounds, default_class=None):
        rectangle = Rectangle(bounds=bounds, color="red", fill_color="red")
        rectangle.on_click(self.__handle_click)
        mid_h = bounds[0][0] + (bounds[1][0] - bounds[0][0]) / 2
        mid_w = bounds[0][1] + (bounds[1][1] - bounds[0][1]) / 2
        #rectangle.popup = self.__create_popup((mid_h, mid_w), default_class)
        return rectangle
    
    # create and handle draw control
    def __create_draw_control(self):
        dc = DrawControl(rectangle={'shapeOptions': {'color': '#0000FF'}}, circle={}, circlemarker={}, polyline={},
                         marker={}, polygon={})
        dc.edit = False
        dc.remove = False

        # handle drawing and deletion of annotations and corresponding classes
        def handle_draw(target, action, geo_json):
            # print(target)
            # print(action)
            # print(geo_json)
            if action == 'created' and geo_json['geometry']['type'] == 'Polygon':
                coordinates = geo_json['geometry']['coordinates'][0]
                #print(coordinates)
                #print(self.__map)
                #print(coordinates)
                hs = [c[1] for c in coordinates]
                ws = [c[0] for c in coordinates]
                min_h, max_h = min(hs), max(hs)
                min_w, max_w = min(ws), max(ws)
                
                # coordinates only inside image
                hh, ww, offset_h, offset_w = self.__img_coords[2:]
                max_h = max(0, min(hh + offset_h, max_h))
                max_w = max(0, min(ww + offset_w, max_w))
                min_h = max(offset_h, min(hh + offset_h, min_h))
                min_w = max(offset_w, min(ww + offset_w, min_w))
                
                
                # remove draw
                dc.clear()

                if max_h - min_h < 1 or max_w - min_w < 1:
                    print(labels_str.warn_skip_wrong )
                    return

                # print(min_h, max_h, min_w, max_w)
                # create rectangle layer and remove drawn geojson
                rectangle = self.__create_rectangle(((min_h, min_w), (max_h, max_w)))
                self.__current_image_annotations.append(rectangle)
                self.__current_class_for_ann.append(None)
                self.__map.add_layer(rectangle)
                # automatically select last annotation
                self.__selected_ann = len(self.__current_image_annotations)-1
                self.__reset_colors_bboxes()
                self.__selected_class = None
                self.__reset_classes_btns()
                self.__delete_button.disabled = False
                # print('Adding ann at index:',len(self.current_image_annotations)-1,
                # ' with class', self.current_class_for_ann[-1])

        dc.on_draw(handle_draw)
        self.__map.add_control(dc)
    
    # load image and get map overlay
    def __get_img_overlay(self, img_path):
        # We need to create an ImageOverlay for each image to show,
        # and set the appropriate bounds based  on the image size
              
        if not os.path.exists(img_path):
            print(labels_str.warn_img_path_not_exits +  img_path)
            

        im = cv2.imread(img_path)
        h, w, _ = im.shape

        max_v = 100
        
        offset_h = -25
        offset_w = -25
        hh = max_v - offset_h*2
        ww = max_v - offset_w*2
        
        if h > w:
            ww = int(w * hh / h)
            offset_w = (max_v - ww) / 2
        elif w > h:
            hh = int(h * ww / w)
            offset_h = (max_v - hh) / 2

        img_ov = ImageOverlay(url=img_path, bounds=((offset_h, offset_w), (hh + offset_h, ww+offset_w)))
        return img_ov, h, w, hh, ww, offset_h, offset_w
    
    
    # create and set map
    def __create_map(self):
        # Create the "map" that will be used to display the image
        # the crs simple, indicates that we will use pixels to locate objects inside the map
        self.__map = Map(center=(50, 50), zoom=2, crs=projections.Simple, dragging=False, 
                         zoom_control=False, double_click_zoom=False,
                         layers=[LocalTileLayer(path='white.png')], layout=dict(width='600px', height='600px'))

        self.__create_draw_control()
    
    # remove all annotations from map
    def __clear_map(self, keep_img_overlay=False):
        starting_layer = 2 if keep_img_overlay else 1
        for l in self.__map.layers[starting_layer:]:
            self.__map.remove_layer(l)
        self.__current_image_annotations = []
        self.__current_class_for_ann = []
        self.__selected_class = None
        self.__selected_ann = None
        self.__delete_button.disabled = True
    
    # disable or enable buttons
    def __toggle_interaction_buttons(self, disabled):
        self.__next_button.disabled = disabled
        self.__previous_button.disabled = disabled
        self.__reset_button.disabled = disabled
    
    # enable or disable buttons for first and last images
    def __change_buttons_status(self):
        self.__next_button.disabled = self.__current_img >= len(self.__images) - 1
        self.__previous_button.disabled = self.__current_img <= 0
        
    def __clear_workspace(self):
        self.__toggle_interaction_buttons(disabled=True)
        self.__save_coco_file()
        self.__clear_map()
        self.__reset_classes_btns()
        self.__clear_validation()
    
    def __clear_validation(self):
        self.__validation_show.value = ""
        
    # next button clicked
    def __on_next_button_clicked(self, b):
        if None in self.__current_class_for_ann:
            self.__validation_show.value = labels_str.warn_select_class
            return
        
        self.__clear_workspace()
        self.__show_image(1)
        
    
    # previous button clicked
    def __on_previous_button_clicked(self, b):
        if None in self.__current_class_for_ann:
            return
        
        self.__clear_workspace()
        self.__show_image(-1)
        
   # reset button clicked
    def __on_reset_button_clicked(self, b):
        self.__clear_map(keep_img_overlay=True)
        self.__reset_classes_btns()
    
    # show current image
    def __show_image(self, delta):
        # update progress bar
        self.__current_img += delta
        self.__progress.value = self.__current_img + 1
        self.__progress.description = '{}/{}'.format(self.__current_img + 1, len(self.__images))
        self.__toggle_interaction_buttons(disabled=False)
        # change buttons
        self.__change_buttons_status()
        # update map
        img_ov, h, w, hh, ww, off_h, off_w = self.__get_img_overlay(self.__images[self.__current_img])
        self.__img_coords = (h, w, hh, ww, off_h, off_w)
        self.__map.add_layer(img_ov)
        self.__image_id = self.__get_current_image_id()
        # update title
        file_name = self.__get_image_name_no_ext(self.__images[self.__current_img])
        self.__title_lbl.value = file_name
        if self.__images_classes is not None:
            pass
            # do something with additional infos
        # load current annotations
        self.__load_annotations()

    def start_annotation(self):
        display(self.__all_widgets)
        self.__show_image(1)
Пример #6
0
class DomainPicker:
    def __init__(self, n_days_old_satimg=1):
        t = datetime.datetime.now() - datetime.timedelta(days=n_days_old_satimg)
        t_str = t.strftime("%Y-%m-%d")

        self.m = Map(
            layers=[
                basemap_to_tiles(basemaps.NASAGIBS.ModisTerraTrueColorCR, t_str),
            ],
            center=(52.204793, 360.121558),
            zoom=2,
        )

        self.domain_coords = []
        self.polygon = None
        self.marker_locs = {}

        self.m.on_interaction(self._handle_map_click)

        button_reset = Button(description="reset")
        button_reset.on_click(self._clear_domain)
        button_save = Button(description="save domain")
        button_save.on_click(self._save_domain)
        self.name_textfield = Text(value="domain_name", width=10)

        self.m.add_control(WidgetControl(widget=button_save, position="bottomright"))
        self.m.add_control(WidgetControl(widget=button_reset, position="bottomright"))
        self.m.add_control(
            WidgetControl(widget=self.name_textfield, position="bottomright")
        )

    def _update_domain_render(self):
        if self.polygon is not None:
            self.m.remove_layer(self.polygon)

        if len(self.domain_coords) > 1:
            self.polygon = Polygon(
                locations=self.domain_coords, color="green", fill_color="green"
            )
            self.m.add_layer(self.polygon)
        else:
            self.polygon = None

    def _handle_marker_move(self, marker, location, **kwargs):
        old_loc = marker.location
        new_loc = location
        idx = self.domain_coords.index(old_loc)
        self.domain_coords[idx] = new_loc
        self._update_domain_render()

    def _handle_map_click(self, **kwargs):
        if kwargs.get("type") == "click":
            loc = kwargs.get("coordinates")
            marker = Marker(location=loc)
            marker.on_move(partial(self._handle_marker_move, marker=marker))
            self.domain_coords.append(loc)
            self.marker_locs[marker] = loc
            self.m.add_layer(marker)
            self._update_domain_render()

    def _clear_domain(self, *args, **kwargs):
        self.domain_coords = []
        for marker in self.marker_locs.keys():
            self.m.remove_layer(marker)
        self.marker_locs = {}
        self._update_domain_render()

    def _save_domain(self, *args, **kwargs):
        fn = "{}.domain.yaml".format(self.name_textfield.value)
        with open(fn, "w") as fh:
            yaml.dump(self.domain_coords, fh, default_flow_style=False)
        print("Domain points written to `{}`".format(fn))
Пример #7
0
class BBoxSelector:
    def __init__(self, bbox, zoom=8, resolution=10):
        center = (bbox.min_y + bbox.max_y) / 2, (bbox.min_x + bbox.max_x) / 2
        self.map = Map(center=center, zoom=zoom, scroll_wheel_zoom=True)

        self.resolution = resolution

        control = DrawControl()

        control.rectangle = {
            "shapeOptions": {
                "fillColor": "#fabd14",
                "color": "#fa6814",
                "fillOpacity": 0.2
            }
        }

        #Disable the rest of draw options
        control.polyline = {}
        control.circle = {}
        control.circlemarker = {}
        control.polygon = {}
        control.edit = False
        control.remove = False

        control.on_draw(self._handle_draw)

        self.map.add_control(control)

        self.bbox = None
        self.size = None
        self.rectangle = None
        self.add_rectangle(bbox.min_x, bbox.min_y, bbox.max_x, bbox.max_y)

        # self.out = w.Output(layout=w.Layout(width='100%', height='50px', overflow_y='scroll'))
        # self.vbox = w.VBox([self.map, self.out])

    def add_rectangle(self, min_x, min_y, max_x, max_y):
        if self.rectangle:
            self.map.remove_layer(self.rectangle)

        self.rectangle = Rectangle(
            bounds=((min_y, min_x), (max_y, max_x)),
            color="#fa6814",
            fill=True,
            fill_color="#fabd14",
            fill_opacity=0.2,
            weight=1
        )

        self.map.add_layer(self.rectangle)

        self.bbox = BBox(((min_x, min_y), (max_x, max_y)), CRS.WGS84).transform(CRS.POP_WEB)

        # self.out.append_display_data((min_x, min_y, max_x, max_y))

        size_x = abs(int((self.bbox.max_x - self.bbox.min_x) / self.resolution))
        size_y = abs(int((self.bbox.max_y - self.bbox.min_y) / self.resolution))

        self.size = size_x, size_y

    def _handle_draw(self, control, action, geo_json):
        control.clear_rectangles()

        bbox_geom = geo_json['geometry']['coordinates'][0]

        min_x, min_y = bbox_geom[0]
        max_x, max_y = bbox_geom[2]

        self.add_rectangle(min_x, min_y, max_x, max_y)

    def show(self):
        return self.map