Unverified Commit bb5c0cd5 authored by Jacob Kaufman's avatar Jacob Kaufman Committed by GitHub
Browse files

Merge pull request #67 from kaitlyndlee/overlays

Adds overlays including WFS feature names to the python map
parents 6d5a1caf 1eb2e790
Loading
Loading
Loading
Loading
+86 −153

File changed.

Preview size limit exceeded, changes collapsed.

+213 −146
Original line number Diff line number Diff line
@@ -5,12 +5,15 @@ import json
import geojson
import shapely.geometry as geo
import shapely.wkt
import os
import urllib.request


class planetary_maps:

    def __init__(self, targetName):
        self.target_name = targetName
        self.json_file = 'geoServerLayers.json'
        self.base_layers = []
        self.layers = []
        self.planet_map = None
        self.map_layers = {
            'base': [],
@@ -25,9 +28,22 @@ class planetary_maps:
        self.gui = planetary_gui()
        self.dmajor_radius = 0
        self.dminor_radius = 0

        # Variables to keep track of how many times handle_feature_click is called.
        # There is a bug where it is called twice, the first time passing in feature
        # and the second time passing in the coordinates. We need both of those variables
        self.handle_feature_click_counter = 0
        self.handle_feature_click_feature = None

        self.json_dict = None
        dir_path = os.path.dirname(os.path.realpath(__file__))
        with open(dir_path + "/geoServerLayers.json", 'r') as fp:
            self.json_dict = json.load(fp)

        self.find_radius()
        self.create_layers()
        self.create_map()

        self.feature_collection = {
            'type': 'FeatureCollection',
            'features': []
@@ -35,22 +51,19 @@ class planetary_maps:

    def find_radius(self):

        with open(self.json_file, 'r') as fp:
            json_dict = json.load(fp)

        targets = json_dict['targets']
        targets = self.json_dict['targets']
        for i, target in enumerate(targets):
            current_target = targets[i]
            if current_target['name'].lower() == self.target_name:
                self.dmajor_radius = float(current_target['aaxisradius']) * 1000.0
                self.dminor_radius = float(current_target['caxisradius']) * 1000.0
                break;
                self.dmajor_radius = float(
                    current_target['aaxisradius']) * 1000.0
                self.dminor_radius = float(
                    current_target['caxisradius']) * 1000.0
                break

    def create_layers(self):
        with open(self.json_file, 'r') as fp:
            json_dict = json.load(fp)

        targets = json_dict['targets']
        targets = self.json_dict['targets']
        for i, target in enumerate(targets):
            current_target = targets[i]
            if current_target['name'].lower() == self.target_name:
@@ -61,19 +74,36 @@ class planetary_maps:
                        if current_layer['transparent'] == 'false':
                            self.map_layers['base'].append(current_layer)
                        else:
                            if current_layer['displayname'] == "Show Feature Names":
                                continue
                            self.map_layers['overlays'].append(current_layer)

        
        for layer in self.map_layers['base']:
            if layer['projection'] == 'cylindrical':
                wms_layer = WMSLayer(
                    url='https://planetarymaps.usgs.gov/cgi-bin/mapserv?map=' + layer['map'],
                    url=layer["url"] + "?map=" + layer["map"],
                    layers=layer['layer'],
                    name=layer['displayname'],
                    crs='EPSG4326',
                    base=True,
                    show_loading=False,
                )
                self.layers.append(wms_layer)

        for layer in self.map_layers['overlays']:
            if layer['projection'] == 'cylindrical':
                wms_layer = WMSLayer(
                    url=layer["url"] + "?map=" + layer["map"],
                    layers=layer['layer'],
                    name=layer['displayname'],
                    crs='EPSG4326',
                    base=True
                    base=False,
                    transparent=True,
                    format="image/png",
                    show_loading=False,
                    visible=False,
                )
                self.base_layers.append(wms_layer)
                self.layers.append(wms_layer)

    def handle_interaction(self, **kwargs):
        if kwargs.get('type') == 'mousemove':
@@ -94,26 +124,27 @@ class planetary_maps:
                    lng = -180 + (abs(lng) % 180)

            if self.gui.get_longitude_range().value == "0 to 360":
                lng += 180;
            
                lng += 180

            if self.gui.get_lat_domain().value == "Planetographic":
                converted_latitude = Math.radians(lat)
                converted_latitude = Math.atan(((self.dmajor_radius / self.dminor_radius)**2) * (Math.tan(converted_latitude)))
                converted_latitude = Math.atan(
                    ((self.dmajor_radius / self.dminor_radius)**2) * (Math.tan(converted_latitude)))
                converted_latitude = Math.degrees(converted_latitude)
                lat = converted_latitude

                
            if self.gui.get_longitude_direction().value == "Positive West":
                if(self.gui.get_longitude_range().value == "-180 to 180"):
                    lng *= -1
                else:
                    lng = Math.fabs(lng - 360)

            self.gui.get_lat_lon_label().value = "Lat, Lon: "+ str(round(lat, 2)) + ", " + str(round(lng, 2))
            self.gui.get_lat_lon_label().value = "Lat, Lon: " + \
                str(round(lat, 2)) + ", " + str(round(lng, 2))

    def create_map(self):
        self.planet_map = Map(layers=tuple(self.base_layers), center=(0, 0), zoom=1, crs='EPSG4326')
        self.planet_map = Map(layers=tuple(self.layers),
                              center=(0, 0), zoom=1, crs='EPSG4326')

        draw_control = DrawControl()
        draw_control.polyline = {
@@ -156,10 +187,14 @@ class planetary_maps:
        draw_control.on_draw(self.handle_draw)
        self.gui.get_wkt_button().on_click(self.handle_WKT_button)

        self.range_control = WidgetControl(widget=self.gui.get_longitude_range(), position='topright')
        self.lat_control = WidgetControl(widget=self.gui.get_lat_domain(), position='topright')
        self.direction_control = WidgetControl(widget=self.gui.get_longitude_direction(), position='topright')
        self.label_control = WidgetControl(widget=self.gui.get_lat_lon_label(), position='bottomright')
        self.range_control = WidgetControl(
            widget=self.gui.get_longitude_range(), position='topright')
        self.lat_control = WidgetControl(
            widget=self.gui.get_lat_domain(), position='topright')
        self.direction_control = WidgetControl(
            widget=self.gui.get_longitude_direction(), position='topright')
        self.label_control = WidgetControl(
            widget=self.gui.get_lat_lon_label(), position='bottomright')

        self.planet_map.add_control(draw_control)
        self.planet_map.add_control(LayersControl(position='topright'))
@@ -168,8 +203,6 @@ class planetary_maps:
        self.planet_map.add_control(fullscreen_control)
        self.planet_map.on_interaction(self.handle_fullscreen)



    def display_map(self):
        display(self.gui.get_longitude_range())
        display(self.gui.get_lat_domain())
@@ -180,17 +213,19 @@ class planetary_maps:
        display(self.gui.get_wkt_text_box())
        display(self.gui.get_wkt_button())

        # Display map first, then add features
        self.add_wfs_features()

    def add_wkt(self, wktString):
        try:
            g1 = shapely.wkt.loads(wktString)
            g2 = geojson.Feature(geometry=g1, properties={})
            geo_json = GeoJSON(data=g2, style = {'color': 'yellow', 'opacity':1, 'weight':1.9, 'fillOpacity':0.5})
            geo_json = GeoJSON(data=g2, style={
                               'color': 'yellow', 'opacity': 1, 'weight': 1.9, 'fillOpacity': 0.5})
            self.planet_map.add_layer(geo_json)
        except:
            self.gui.get_wkt_text_box().value = "Invalid WKT String"

        

    def handle_draw(self, *args, **kwargs):
        """Do something with the GeoJSON when it's drawn on the map"""
        geo_json = kwargs.get('geo_json')
@@ -220,6 +255,51 @@ class planetary_maps:
    def handle_WKT_button(self, *args, **kwargs):
        self.add_wkt(self.gui.get_wkt_text_box().value)

    def add_wfs_features(self):
        geoJsonUrl = ("https://astrocloud.wr.usgs.gov/dataset/data/nomenclature/{}/WFS?"
                      "service=WFS&version=1.1.0&request=GetFeature&outputFormat=application%2Fjson"
                      "&srsName=EPSG%3A4326".format(self.target_name.upper()))

        break_out = False
        while not break_out:
            try:    # Try until no 404 error is thrown by server
                with urllib.request.urlopen(geoJsonUrl, timeout=240) as url:
                    jsonp = json.loads(url.read())

                    # Sort features by diameter
                    jsonp['features'] = sorted(
                        jsonp['features'], key=lambda feature: feature["properties"]["diameter"])
                    geo_json = GeoJSON(data=jsonp, name="Show Feature Names")
                    geo_json.point_style = {
                        'fillOpacity': 1,
                        'radius': 3
                    }

                    geo_json.on_click(self.handle_feature_click)
                    self.planet_map.add_layer(geo_json)
                    break_out = True

            except:
                continue

    def handle_feature_click(self, feature=None, coordinates=None, **kwargs):
        self.handle_feature_click_counter += 1
        if self.handle_feature_click_counter == 1:
            self.handle_feature_click_feature = feature

        elif self.handle_feature_click_counter == 2:
            popup = Popup(
                location=coordinates,
                child=widgets.HTML(self.handle_feature_click_feature['name']),
                close_button=True,
                auto_close=True,
                close_on_escape_key=False
            )
            self.planet_map.add_layer(popup)
            self.handle_feature_click_counter = 0
            return


class planetary_gui:
    def __init__(self):
        self.longitude_range = None
@@ -294,16 +374,3 @@ class planetary_gui:

    def get_longitude_range(self):
        return self.longitude_range