def save_map(date): valencia = [39.4561165311493, -0.3545661635] mapa = Map(location=valencia, tiles='OpenStreetMap', zoom_start=10) GeoJson(open('voronoi.json'), name='Diagrama de Voronoi').add_to(mapa) GeoJson(open('estaciones_de_recarga_' + date + '.json'), name='Estaciones de Recarga').add_to(mapa) LayerControl().add_to(mapa) mapa.save('valencia_' + date + '.html')
def html_map(contiguity_fname, html_out_fname, json_out_fname): """ Create HTML and GeoJSON files showing the valid geometry for the input contiguity image. :param contiguity_fname: A full file pathname to the image representing the data contiguity. :param html_out_fname: A full file pathname that will contain the html bounday map. :param json_out_fname: A full file pathname that will contain the json bounday map. :return: None; Outputs will be saved directly to disk. """ # remove any previous creations try: os.remove(html_out_fname) except OSError: pass try: os.remove(json_out_fname) except OSError: pass logging.info("Create valid bounds " + json_out_fname) geom, crs = valid_region(contiguity_fname) gpdsr = gpd.GeoSeries([geom]) gpdsr.crs = crs gpdsr = gpdsr.to_crs({'init': 'epsg:4326'}) gpdsr.to_file(json_out_fname, driver='GeoJSON') m = folium.Map() def style_function(*args): return {'fillColor': None, 'color': '#0000ff'} with open(json_out_fname, 'r') as src: # Manual handling of json load for multi-version support of folium _geojson = json.load(src) GeoJson(_geojson, name='bounds.geojson', style_function=style_function).add_to(m) # TODO - add MGRS tile reference to map with layer active = False m.fit_bounds(GeoJson(gpdsr).get_bounds()) folium.LatLngPopup().add_to(m) folium.LayerControl().add_to(m) m.save(html_out_fname)
def draw_jam_lines(jam_data, folium_map) -> None: for i, row in jam_data.iterrows(): geojson = GeoJson( row['path.street_coord'].replace('\'', '\"'), style_function=lambda f: { 'fillColor': '#FF0000', 'color': '#FF0000', 'weight': 4, 'fillOpacity': 0.1, } ) geojson.add_to(folium_map)
def draw_CDBG_map(self): self.CDBG_map = Map(location=[42.795390191429625, -71.07516023514027], zoom_start=12) data = self.preprocess.get_CDBG_geometry_data() geo_json = GeoJson( data, style_function=lambda feature: { 'fillColor': '#ffff00', 'color': 'black', 'weight': 1, }, control=False ) geo_json.add_to(self.CDBG_map)
def draw_refuse_routes_map(self, refuse_routes_file_path: string = 'resource/data/Hav_Refuse_Routes_WGS84' '/Hav_Refuse_Routes_WGS84.json'): geo_map = Map(location=[42.795390191429625, -71.07516023514027], zoom_start=12) data = self.preprocess.get_refuse_routes_data(refuse_routes_file_path) keys_pool = [ 'MONDAY - Red Week', 'TUESDAY - Red Week', 'WEDNESDAY - Red Week', 'THURSDAY - Red Week', 'FRIDAY - Red Week', 'MONDAY - Blue Week', 'TUESDAY - Blue Week', 'WEDNESDAY - Blue Week', 'THURSDAY - Blue Week', 'FRIDAY - Blue Week', 'MERCANTILE - Every Friday' ] for key in keys_pool: feature_group = FeatureGroup(name=key, show=True) if key.endswith('Red Week'): color = 'red' elif key.endswith('Blue Week'): color = 'blue' else: color = 'black' for each in data[key]: geo_json = GeoJson( data=each, style_function=lambda feature, color=color: { 'fillColor': '#A9A9A9', 'color': color, 'weight': 3, }, highlight_function=lambda feature, color=color: { 'fillColor': '#FFBFFF', 'color': color, 'weight': 4, }, tooltip=key, overlay=True ) geo_json.add_to(feature_group) feature_group.add_to(geo_map) LayerControl().add_to(geo_map) cur_time = time.strftime('%m_%d_%Y_%H_%M_%S', time.localtime()) file_name = 'refuse_routes_{}.html'.format(cur_time) geo_map.save(os.path.join(self.refuse_routes_directory_path, file_name))
def add_contour(self, contour: Union[Polygon, MultiPolygon, str]) -> SpatialPlot: """ :param contour: either a polygon object or a string (state acronym) if it's a string, this method will pull the contour with get_state_contour() function and plot it. """ if isinstance(contour, str): contour_polygon = get_state_contours(contour) elif isinstance(contour, MultiPolygon) or isinstance(contour, Polygon): contour_polygon = contour else: raise TypeError( 'this method only supports state name or polygon object from shapely' ) min_x, min_y, max_x, max_y = contour_polygon.bounds make_df = DataFrame({'LAT': [min_y, max_y], 'LON': [min_x, max_x]}) self.update_locations(new_data=make_df, lat_col='LAT', lon_col='LON') [centroid_] = list(contour_polygon.centroid.coords) longitude, latitude = centroid_ self.initialize_canvass(center=[ latitude, longitude ]) # no need to infer the center this time just use centroid GeoJson(contour_polygon).add_to(self.canvass) return self
def plot_basemap_region_fill(df_boundaries_zones, initial_map=None): """On a folium map, add the boundaries of the geometries in geojson formatted column of df_boundaries zones""" if initial_map is None: initial_map = base_empty_map() feature_group = folium.FeatureGroup(name='Boundaries') for i, row in df_boundaries_zones.iterrows(): feature_sel = Feature(geometry=row["geom_geojson"], id=str(i)) feat_collection_sel = FeatureCollection([feature_sel]) geojson_subzone = json.dumps(feat_collection_sel) GeoJson( geojson_subzone, style_function=lambda feature: { 'fillColor': None, 'color': 'blue', 'opacity': 0.5, 'weight': 3, 'fillOpacity': 0 } ).add_to(feature_group) feature_group.add_to(initial_map) return initial_map
def add_park(park, popup, feature_group, icon): geom_raw = parks[park] gc_raw = GeometryCollection([shape(geom_raw)]) gc_simple = GeometryCollection.simplify( gc_raw, 0.01 ) # I *think* the tolerance units are in degrees latitude/longitude geojson_simple = GeoJson(mapping(gc_simple)) geojson_simple.add_to(feature_group) centroid = gc_raw.centroid Marker( location=(centroid.y, centroid.x), popup=popup, icon=icon, ).add_to(feature_group)
def add_layers(dictobject): for geodataframe in dictobject: local = dictobject[geodataframe] fg = folium.FeatureGroup(name=geodataframe) fg.layer_name = geodataframe try: data = local['data'] for x, y, charge, time, date in zip(data['x_coord'], data['y_coord'], data['charge'], data['time'], data['date']): folium.Marker( [y, x], popup= f"Category: {geodataframe}<br>Charge: {charge}<br>Date: {pd.to_datetime(date).strftime('''%b %d, %Y''')}" + '<br>' + 'Time: ' + time, icon=folium.Icon(color=local['color'])).add_to(fg) # Handling non-point objects(our census tract polygon layers), and adding them to the feature group (fg). except KeyError: GeoJson( local, overlay=True, highlight_function=lambda feature: { 'weight': 3, 'fillOpacity': 0.8, 'fillColor': color_dict[str(feature['properties']['NUMPOINTS'])], 'color': "#5D0C0E", 'borderOpacity': 0.0, }, style_function=lambda feature: { 'weight': 2, 'fillOpacity': 0.6, 'fillColor': color_dict[str(feature['properties']['NUMPOINTS'])], 'color': "#423e41", 'borderOpacity': 0.0, }, smooth_factor=2.0, ).add_to(fg) # adding a popup to show the details of each tract. for geo, pts in zip(local.geometry, local['NUMPOINTS']): # Adding a marker with the details for each polygon. folium.Marker( [geo.centroid.y, geo.centroid.x], popup= f"{pts} {'fatalities' if pts != 1 else 'fatality'} in this tract during {geodataframe[:4]}", icon=folium.Icon(icon='bookmark', color='darkblue')).add_to(fg) map.add_child(fg, name=geodataframe)
def draw_score_markers(data, folium_map, congestions_toggle): cmap = plt.get_cmap('RdYlBu_r') # Sort by score to get higher score markers on top of the map data = sorted(data, key=lambda k: k['score'], reverse=congestions_toggle) norm = colors.Normalize(vmin=-1, vmax=1) placed_markers = set() try: for row in data: color = convert_to_hex(cmap(norm(row['score']))) tooltip = 'Location: {}<br />Attribute: {}<br />Time: {}<br />Score: {}'.format( row['location'].replace('{', '').replace('`', '').replace('}', ''), row['attribute_name'], row['time_point'], row['score']) # Only place a marker per location # TODO: change to max/min per location if row['location'] in placed_markers: continue if row['dataset'] == 'espiras': pmarker = CircleMarker(location=json.loads(row['location_coor']), radius=8, line_color=color, color=color, fill_color=color, tooltip=tooltip) pmarker.add_to(folium_map) else: if isinstance(row['location_coor'], dict): row['location_coor'] = str(row['location_coor']) geojson = GeoJson( row['location_coor'].replace("\'", "\""), style_function=lambda f, color=color: { 'fillColor': color, 'color': color, 'weight': 4, 'fillOpacity': 0.7 }, tooltip=tooltip ) geojson.add_to(folium_map) placed_markers.add(row['location']) except Exception as e: print(e)
def get_population_feature_group() -> FeatureGroup: population_feature_group = FeatureGroup('Population') population_feature_group.add_child( GeoJson( data=open('world.json', mode='r', encoding='utf-8-sig').read(), style_function=lambda x: { 'fillColor': 'green' if x['properties']['POP2005'] < 10000000 else 'orange' if 10000000 <= x['properties']['POP2005'] < 20000000 else 'red' })) return population_feature_group
def choropleth_map(df_aggreg, hex_id_field, geometry_field, value_field, layer_name, initial_map=None, kind="filled_nulls", border_color='#ffffff', fill_opacity=0.4, border_opacity=0.3, with_legend=False): """Plots a Choropleth Map with folium""" if initial_map is None: initial_map = base_empty_map() # the custom colormap depends on the map kind if kind == "linear": min_value = df_aggreg[value_field].min() max_value = df_aggreg[value_field].max() custom_cm = cm.LinearColormap(['green', 'yellow', 'red'], vmin=min_value, vmax=max_value) elif kind == "outlier": # for outliers, values would be -1,0,1 custom_cm = cm.LinearColormap(['blue', 'white', 'red'], vmin=-1, vmax=1) elif kind == "filled_nulls": min_value = df_aggreg[df_aggreg[value_field] > 0][value_field].min() max_value = df_aggreg[df_aggreg[value_field] > 0][value_field].max() # m = round((min_value + max_value) / 2, 0) m = (min_value + max_value) / 2.0 custom_cm = cm.LinearColormap(['silver', 'green', 'yellow', 'red'], index=[0, min_value, m, max_value], vmin=min_value, vmax=max_value) else: custom_cm = None # create geojson data from dataframe geojson_data = hexagons_dataframe_to_geojson(df_aggreg, hex_id_field, geometry_field, value_field) # plot on map GeoJson( geojson_data, style_function=lambda feature: { 'fillColor': custom_cm(feature['properties']['value']), 'color': border_color, 'opacity': border_opacity, 'weight': 0.2, 'fillOpacity': fill_opacity }, name=layer_name ).add_to(initial_map) # add legend (not recommended if multiple layers) if with_legend is True: custom_cm.add_to(initial_map) return initial_map
def population(path): """ str -> None This function add population child to the html map """ fg_pp.add_child( GeoJson( data=open(path, 'r', encoding='utf-8-sig').read(), style_function=lambda x: { 'fillColor': 'green' if x['properties']['POP2005'] < 10000000 else 'orange' if 10000000 <= x['properties']['POP2005'] < 20000000 else 'red' }))
def choropleth_map(df_agg, value_col, name, border_color='black', fill_opacity=0.7, initial_map=None, with_legend=False, kind='linear'): min_value = df_agg[value_col].min() max_value = df_agg[value_col].max() m = round((min_value + max_value) / 2, 0) res = h3.h3_get_resolution(df_agg.loc[0, 'hex_id']) if initial_map is None: initial_map = Map( location=[39.970208, -83.000645], zoom_start=13, tiles='cartodbpositron', attr=( '© <a href="http://www.openstreetmap.org/copyright">' + 'OpenStreetMap</a> contributors © <a href="http://cartodb.' + 'com/attributions#basemaps">CartoDB</a>' ) ) if kind == 'linear': custom_cm = cm.LinearColormap( ['green', 'yellow', 'red'], vmin=min_value, vmax=max_value) elif kind == 'outlier': custom_cm = cm.LinearColormap( ['blue', 'white', 'red'], vmin=min_value, vmax=max_value) geojson_data = hexagons_dataframe_to_geojson( df_hex=df_agg, value_col=value_col) GeoJson( geojson_data, style_function=lambda feature: { 'fillColor': custom_cm(feature['properties']['value']), 'color': border_color, 'weight': 1, 'fillOpacity': fill_opacity }, name=name ).add_to(initial_map) if with_legend is True: custom_cm.add_to(initial_map) return initial_map
def draw_precincts_wards_map(self): self.precincts_wards_map = Map(location=[42.795390191429625, -71.07516023514027], zoom_start=12) data = self.preprocess.get_precincts_wards_geometry_data() for i in range(len(data)): ward_info = data[i] precincts = ward_info['data'] for j in range(len(precincts)): precinct = precincts[j] geo_json = GeoJson( data=precinct, style_function=lambda feature: { 'fillColor': '#A9A9A9', 'color': 'black', 'weight': 1, }, highlight_function=lambda feature: { 'fillColor': '#FFBFFF', 'color': 'yellow', 'weight': 2, }, tooltip=GeoJsonTooltip(fields=['Precinct']), control=False ) geo_json.add_to(self.precincts_wards_map)
def map_seattle(date_idx): date_idx = int(date_idx) linear = cm.linear.RdYlGn_06 seattle_neighborhoods = folium.Map(location=[47.61, -122.3321], zoom_start=11,tiles='cartodbpositron') GeoJson(mcpp_neighoborhoods, style_function=lambda feature: { 'fillColor': linear(my_color_function(feature, date_idx)), 'fillOpacity': 0.45, 'color': 'gray', 'dashArray': '2, 5'}).add_to(seattle_neighborhoods) mapdata = BytesIO() seattle_neighborhoods.save(mapdata, close_file=False) html = mapdata.getvalue() return html
def test_geojson_find_identifier(): def _create(*properties): return {"type": "FeatureCollection", "features": [ {"type": "Feature", "properties": item} for item in properties]} def _assert_id_got_added(data): _geojson = GeoJson(data) assert _geojson.find_identifier() == 'feature.id' assert _geojson.data['features'][0]['id'] == '0' data_with_id = _create(None, None) data_with_id['features'][0]['id'] = 'this-is-an-id' data_with_id['features'][1]['id'] = 'this-is-another-id' geojson = GeoJson(data_with_id) assert geojson.find_identifier() == 'feature.id' assert geojson.data['features'][0]['id'] == 'this-is-an-id' data_with_unique_properties = _create( {'property-key': 'some-value'}, {'property-key': 'another-value'}, ) geojson = GeoJson(data_with_unique_properties) assert geojson.find_identifier() == 'feature.properties.property-key' data_with_unique_properties = _create( {'property-key': 42}, {'property-key': 43}, {'property-key': 'or a string'}, ) geojson = GeoJson(data_with_unique_properties) assert geojson.find_identifier() == 'feature.properties.property-key' # The test cases below have no id field or unique property, # so an id will be added to the data. data_with_identical_ids = _create(None, None) data_with_identical_ids['features'][0]['id'] = 'identical-ids' data_with_identical_ids['features'][1]['id'] = 'identical-ids' _assert_id_got_added(data_with_identical_ids) data_with_some_missing_ids = _create(None, None) data_with_some_missing_ids['features'][0]['id'] = 'this-is-an-id' # the second feature doesn't have an id _assert_id_got_added(data_with_some_missing_ids) data_with_identical_properties = _create( {'property-key': 'identical-value'}, {'property-key': 'identical-value'}, ) _assert_id_got_added(data_with_identical_properties) data_bare = _create(None) _assert_id_got_added(data_bare) data_empty_dict = _create({}) _assert_id_got_added(data_empty_dict) data_without_properties = _create(None) del data_without_properties['features'][0]['properties'] _assert_id_got_added(data_without_properties) data_some_without_properties = _create({'key': 'value'}, 'will be deleted') # the first feature has properties, but the second doesn't del data_some_without_properties['features'][1]['properties'] _assert_id_got_added(data_some_without_properties) data_with_nested_properties = _create({ "summary": {"distance": 343.2}, "way_points": [3, 5], }) _assert_id_got_added(data_with_nested_properties) data_with_incompatible_properties = _create({ "summary": {"distances": [0, 6], "durations": None}, "way_points": [3, 5], }) _assert_id_got_added(data_with_incompatible_properties) data_loose_geometry = {"type": "LineString", "coordinates": [ [3.961389, 43.583333], [3.968056, 43.580833], [3.974722, 43.578333], [3.986389, 43.575278], [3.998333, 43.5725], [4.163333, 43.530556], ]} geojson = GeoJson(data_loose_geometry) geojson.convert_to_feature_collection() assert geojson.find_identifier() == 'feature.id' assert geojson.data['features'][0]['id'] == '0'
#!/Users/simurgh/anaconda/bin/python import os import json import folium from folium import GeoJson from scipy.spatial import Voronoi, voronoi_plot_2d import matplotlib.pyplot as plt ixp_location = os.path.join('buildings.geojson') with open(ixp_location) as f: ixp = json.load(f) coor_list = [] for feature in ixp['features']: coor_list.append(feature['geometry']['coordinates']) kw = {'location': [48, -102], 'zoom_start': 3} m = folium.Map(**kw) GeoJson(ixp).add_to(m) vor = Voronoi(coor_list) vor_plot = voronoi_plot_2d(vor) #vor_plot.add_to(m) m.save(os.path.join('ixp-map.html'))
#!/Users/simurgh/anaconda/bin/python import os import json import folium from folium import GeoJson from scipy.spatial import Voronoi, voronoi_plot_2d import matplotlib.pyplot as plt probe_location = os.path.join('probes.geojson') with open(probe_location) as f: probe = json.load(f) coor_list = [] for feature in probe['features']: coor_list.append(feature['geometry']['coordinates']) kw = {'location': [48, -102], 'zoom_start': 3} m = folium.Map(**kw) GeoJson(probe).add_to(m) vor = Voronoi(coor_list) vor_plot = voronoi_plot_2d(vor) #vor_plot.add_to(m) m.save(os.path.join('probe-map.html'))
def choropleth_map(df_aggreg, border_color='black', fill_opacity=0.7, initial_map=None, with_legend=False, kind="linear", coords=[], zoom_start=13): #colormap min_value = df_aggreg["value"].min() max_value = df_aggreg["value"].max() m = round((min_value + max_value) / 2, 0) #take resolution from the first row res = h3.h3_get_resolution(df_aggreg.loc[0, 'hex_id']) if initial_map is None: initial_map = Map( location=coords, zoom_start=zoom_start, tiles="cartodbpositron", attr= '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="http://cartodb.com/attributions#basemaps">CartoDB</a>' ) #the colormap #color names accepted https://github.com/python-visualization/branca/blob/master/branca/_cnames.json if kind == "linear": custom_bcm = bcm.LinearColormap(['green', 'yellow', 'red'], vmin=min_value, vmax=max_value) elif kind == "outlier": #for outliers, values would be -11,0,1 custom_bcm = bcm.LinearColormap(['blue', 'white', 'red'], vmin=min_value, vmax=max_value) elif kind == "filled_nulls": custom_bcm = bcm.LinearColormap(['sienna', 'green', 'yellow', 'red'], index=[0, min_value, m, max_value], vmin=min_value, vmax=max_value) #create geojson data from dataframe geojson_data = hexagons_dataframe_to_geojson(df_hex=df_aggreg) #plot on map name_layer = "Choropleth " + str(res) if kind != "linear": name_layer = name_layer + kind GeoJson(geojson_data, style_function=lambda feature: { 'fillColor': custom_bcm(feature['properties']['value']), 'color': border_color, 'weight': 1, 'fillOpacity': fill_opacity }, name=name_layer).add_to(initial_map) #add legend (not recommended if multiple layers) if with_legend == True: custom_bcm.add_to(initial_map) return initial_map
def h3_choropleth_map(df_aggreg: pd.DataFrame, value_to_map: str, kind: str, hour: int, border_color='black', fill_opacity=0.7, initial_map=None, map_center=[34.0522, -118.2437], with_legend=True): """ Builds a folium choropleth map from an df containing H3 hex cells and some cell value such as 'count'. parameters ---------- df_aggreg:pd.DataFrame - df with H3 hex cells in col ['hex_id'] and at least one col ['value_to_map'] for cell color. value_to_map:str - column name in df to scale and color cells by returns ---------- initial_map:folium.Map """ # take resolution from the first row res = h3.h3_get_resolution(df_aggreg.loc[0, 'hex_id']) if hour is not None: df_aggreg = df_aggreg[df_aggreg.hour == hour] else: df_aggreg = df_aggreg.groupby(['hex_id']).agg({value_to_map: 'sum', 'geometry': 'first', 'hex_id': 'first'}) # create geojson data from dataframe geojson_data = hexagons_dataframe_to_geojson(df_hex=df_aggreg) if initial_map is None: initial_map = Map(location=[34.0522, -118.2437], zoom_start=11, tiles="cartodbpositron", attr='© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="http://cartodb.com/attributions#basemaps">CartoDB</a>' ) if value_to_map: # colormap min_value = df_aggreg[value_to_map].min() max_value = df_aggreg[value_to_map].max() m = round((min_value + max_value) / 2, 0) # color names accepted https://github.com/python-visualization/branca/blob/master/branca/_cnames.json if kind == "linear": custom_cm = cm.LinearColormap(['green', 'yellow', 'red'], vmin=min_value, vmax=max_value) elif kind == "outlier": # for outliers, values would be -11,0,1 custom_cm = cm.LinearColormap(['blue', 'white', 'red'], vmin=min_value, vmax=max_value) elif kind == "filled_nulls": custom_cm = cm.LinearColormap(['sienna', 'green', 'yellow', 'red'], index=[0, min_value, m, max_value], vmin=min_value, vmax=max_value) # plot on map name_layer = "Choropleth " + str(res) if kind != "linear": name_layer = name_layer + kind GeoJson( geojson_data, style_function=lambda feature: { 'fillColor': custom_cm(feature['properties'][value_to_map]), 'color': border_color, 'weight': 1, 'fillOpacity': fill_opacity }, name=name_layer ).add_to(initial_map) # add legend (not recommended if multiple layers) if with_legend == True: custom_cm.add_to(initial_map) else: # plot on map name_layer = "Choropleth " + str(res) if kind != "linear": name_layer = name_layer + kind GeoJson( geojson_data, style_function=lambda feature: { 'fillColor': 'blue', 'color': 'border_color', 'weight': 1, 'fillOpacity': fill_opacity }, name=name_layer ).add_to(initial_map) return initial_map
def path_plot(self, channel=None, map_type='dynamic', devices='all', start_date=None, end_date=None, options=dict()): ''' Creates a folium map showing a path Parameters ------- channel: String None If None, shows path, otherwise, colored path with channel mapping map_type: String 'dynamic' 'dynamic' or 'static'. Whether is a dinamic map or not devices: list or 'all' List of devices to include, or 'all' from self.devices channel: String The channel to make the map from start_date, end_date: String Date convertible string options: dict() Possible keys are (default otherwise) location: list [41.400818, 2.1825157] Center map location tiles: (String) 'Stamen Toner' Tiles for the folium.Map zoom: (float) 2.5 Zoom to start with in folium.Map period: 'String' '1W' Period for 'dynamic' map radius: float 10 Circle radius for icon fillOpacity: float 1 (<1) Fill opacity for the icon stroke: 'String' 'false' 'true' or 'false'. For icon's stroke icon: 'String' 'circle' A valid folium.Map icon style Returns ------- Folium.Map object ''' # Set defaults options = dict_fmerge(config._map_def_opt, options) # Make features features = [] if devices == 'all': mdev = self.devices else: mdev = list() for device in devices: if device in self.devices: mdev.append(device) else: std_out(f'Device {device} not found, ignoring', 'WARNING') if len(mdev) == 0: std_out('Requested devices not in test', 'ERROR') return None for device in mdev: chs = ['GPS_LAT', 'GPS_LONG'] if channel is not None: if channel not in self.devices[str(device)].readings.columns: std_out( f'Channel {channel} not in columns: {self.devices[str(device)].readings.columns}', 'ERROR') return None # Get bins minmax = False if not options['minmax']: if all([key not in channel for key in config._channel_bins]): std_out( f'Requested channel {channel} not in config mapped bins {config._channel_bins.keys()}.Using min/max mapping', 'WARNING') minmax = True else: minmax = True if minmax: bins = linspace( self.devices[str(device)].readings[channel].min(), self.devices[str(device)].readings[channel].max(), config._channel_bin_n) else: for bname in config._channel_bins.keys(): if bname in channel: bins = config._channel_bins[bname] break chs.append(channel) # Create copy dfc = self.devices[str(device)].readings[chs].copy() # Resample and cleanup # TODO THIS CAN INPUT SOME MADE UP READINGS dfc = clean(dfc.resample(options['period']).mean(), 'fill') # Make color column legend_labels = None if channel is not None: dfc['COLOR'] = cut(dfc[channel], bins, labels =\ config._map_colors_palette) # Make legend labels legend_labels = {} for ibin in range(len(bins) - 1): legend_labels[f'{round(bins[ibin],2)} : {round(bins[ibin+1],2)}'] =\ config._map_colors_palette[ibin] else: dfc['COLOR'] = config._map_colors_palette[0] if start_date is not None: dfc = dfc[dfc.index > start_date] if end_date is not None: dfc = dfc[dfc.index < end_date] # Add point for each date for date in dfc.index: if date == dfc.index[-1]: break times = [] color = str(dfc.loc[date, 'COLOR']) if color == 'nan' or isnan(dfc.loc[date, 'GPS_LONG'])\ or isnan(dfc.loc[date, 'GPS_LAT']): std_out(f'Skipping point {date}', 'WARNING') continue geometry = { 'type': 'LineString', 'coordinates': [[dfc.loc[date, 'GPS_LONG'], dfc.loc[date, 'GPS_LAT']], [ dfc.loc[date + dfc.index.freq, 'GPS_LONG'], dfc.loc[date + dfc.index.freq, 'GPS_LAT'] ]], } properties = { 'icon': options['icon'], 'iconstyle': { 'fillColor': color, 'fillOpacity': options['fillOpacity'], 'stroke': options['stroke'], 'radius': options['radius'] }, 'device': device, 'timestamp': date.strftime('%Y-%m-%dT%H:%M:%S'), "coordinates": [ dfc.loc[date + dfc.index.freq, 'GPS_LAT'], dfc.loc[date + dfc.index.freq, 'GPS_LONG'] ], 'style': { 'color': color, 'stroke-width': options['stroke-width'], 'fillOpacity': options['fillOpacity'] } } # Add reading to tooltip if channel is not None: properties['channel'] = channel properties['value'] = dfc.loc[date, channel] if map_type == 'dynamic': properties['times'] = [ date.strftime('%Y-%m-%dT%H:%M:%S'), (date + dfc.index.freq).strftime('%Y-%m-%dT%H:%M:%S') ] features.append({ 'type': 'Feature', 'geometry': geometry, 'properties': properties }) featurecol = {'type': 'FeatureCollection', 'features': features} # Make map if options['location'] == 'average': avg_long = dfc['GPS_LONG'].mean() avg_lat = dfc['GPS_LAT'].mean() loc = [avg_lat, avg_long] else: loc = options['location'] m = Map( location=loc, tiles=options['tiles'], zoom_start=options['zoom'], ) if map_type == 'static': # TODO WORKAROUND UNTIL GEOJSON ACCEPTS MARKERS if options['markers']: for feature in features: Circle(location=[ feature['geometry']['coordinates'][0][1], feature['geometry']['coordinates'][0][0] ], fill='true', radius=feature['properties']['iconstyle']['radius'], color=feature['properties']['iconstyle']['fillColor'], fill_opacity=feature['properties']['iconstyle'] ['fillOpacity']).add_to(m) if channel is not None: fields = ["device", "channel", "timestamp", "coordinates", "value"] aliases = [ "Device:", "Sensor:", "Timestamp:", "Coordinates:", "Reading:" ] else: fields = ["device", "timestamp", "coordinates"] aliases = ["Device:", "Timestamp:", "Coordinates:"] popup = GeoJsonPopup( fields=fields, aliases=aliases, localize=True, labels=True, max_width=800, ) tooltip = GeoJsonTooltip( fields=fields, aliases=aliases, localize=True, sticky=True, labels=True, style=""" background-color: #F0EFEF; border: 1px solid gray; border-radius: 1px; box-shadow: 2px; """, max_width=800, ) GeoJson( featurecol, tooltip=tooltip, popup=popup, style_function=lambda x: { 'color': x['properties']['style']['color'], 'weight': x['properties']['style']['stroke-width'], 'fillOpacity': x['properties']['style']['fillOpacity'] }, ).add_to(m) elif map_type == 'dynamic': TimestampedGeoJson(featurecol, period='PT' + convert_rollup(options['period']), add_last_point=True, auto_play=False, loop=False, max_speed=options['max_speed'], loop_button=True, time_slider_drag_update=True).add_to(m) else: std_out(f'Not supported map type {map_type}', 'ERROR') return None if options['minimap']: minimap = MiniMap(toggle_display=True, tile_layer=options['tiles']) minimap.add_to(m) if options['legend'] and not legend_labels is None: templateLoader = FileSystemLoader(searchpath=join(dirname(__file__),\ 'templates')) templateEnv = Environment(loader=templateLoader) template = templateEnv.get_template("map_legend.html") filled_map_legend = template.render(legend_labels=legend_labels) map_legend_html = '{% macro html(this, kwargs) %}'+\ filled_map_legend+\ '{% endmacro %}' legend = element.MacroElement() legend._template = element.Template(map_legend_html) m.get_root().add_child(legend) return m
def create_map(data, file_name="index.html"): map = Map( location=[data[col].mean() for col in ["latitude", "longitude"]], tiles="Stamen Toner", zoom_start=2, ) fg_nodes_locations = FeatureGroup(name="Locations") fg_nodes_counts = FeatureGroup(name="Counts") circles = [ { "radius": 5, "stroke": False, "fill": True, "fill_color": "crimson", "fill_opacity": opacity, "location": [latitude, longitude], "popup": Popup( html=f""" <style> tbody {{ text-align: center; }} table, tr, td {{ border-collapse: collapse; border: 1px solid black; }} </style> <h3>{ip}</h3> <table> <tbody> <tr> <td><strong>ISP</strong></td> <td>{org}</td> </tr> <tr> <td><strong>Completed requests</strong></td> <td>{completed_requests}</td> </tr> </tbody> </table> """, max_width=300, ), } for ip, latitude, longitude, org, completed_requests, opacity in [ named_tuple[2:] for named_tuple in data.itertuples(index=False) ] ] q1, q2, q3, q4 = nodes_counts_quantiles() def opacity(scaled_nodes_count): # print(scaled_nodes_count) if scaled_nodes_count < q1: return 0 elif q1 <= scaled_nodes_count < q2: return 0.1 elif q2 <= scaled_nodes_count < q3: return 0.25 elif q3 <= scaled_nodes_count < q4: return 0.5 else: return 0.75 def style_function(feature): fillOpacity = opacity(feature["properties"]["scaled_nodes_count"]) return {"fillColor": "blue", "weight": 0, "fillOpacity": fillOpacity} fg_nodes_counts.add_child( GeoJson( data=open("data/enriched_world.json", encoding="utf-8-sig").read(), style_function=style_function, ) ) for circle in circles: fg_nodes_locations.add_child(CircleMarker(**circle)) map.add_child(fg_nodes_counts) map.add_child(fg_nodes_locations) map.add_child(LayerControl()) map.save(file_name)
hospedero_map = Map(location=[5.190831, -72.322258], tiles=None, zoom_start=9) basemaps['Google Satellite'].add_to(hospedero_map) basemaps['Google Terrain'].add_to(hospedero_map) # TileLayer('Stamen Terrain', name='Stamen Terrain', overlay=False, show=False).add_to(hospedero_map) style = { 'fillColor': '#FFFFFF', 'color': '#FFFFFF', "weight": 3, 'fillOpacity': 0.05 } GeoJson(casanare_mapa, name='Municipios de Casanare', overlay=True, style_function=lambda x: style, tooltip=GeoJsonTooltip(fields=['MPIO_CNMBR'], aliases=['MUNICIPIO'])).add_to(hospedero_map) feature_articulos = FeatureGroup('Publicaciones', show=True) for index, row in df_articulos.iterrows(): html_popup = """ <h2><b>{}</b></h2> <h4><i>{}</i></h4> <p>{}</p> <p><b>Secuenciación:</b> {}</p> <p><b>Especie(s):</b> <i>{}</i></p> """.format iframe = IFrame(html_popup(row['Articulo'], row['Autor'], row['Fecha'], row['Secuenciación'], row['Trypanosoma']),
def main(): # Paso 1: Eliminar clúster de puntos en base al tiempo medio que pasan las # personas en los puntos de interés (PDI). El archivo tiempo.json está # filtrado por los PDI y contiene el nombre y tiempo de los puntos. print("Leyendo archivo tiempo...") pdi_df = gpd.read_file('opendata/tiempo.json') print("Eliminando clúster de puntos...") pdi_df, coords = del_cluster_points(pdi_df) # Paso 2: Generar el diagrama de Voronoi para el procesamiento de datos. vor = Voronoi(coords) regions, vertices = voronoi_finite_polygons(vor) min_x = vor.min_bound[0] - 0.1 max_x = vor.max_bound[0] + 0.1 min_y = vor.min_bound[1] - 0.1 max_y = vor.max_bound[1] + 0.1 box = Polygon([[min_x, min_y], [min_x, max_y], [max_x, max_y], [max_x, min_y]]) voro_df = clip_voronoi(regions, vertices, box) # Paso 3: Agregar los datos de población, tráfico y tweets. # Población print('Leyendo archivo manzanas_pob...') pobl_df = gpd.read_file('opendata/manzanas_pob.json') print('Agregando datos de población...') pdi_df = add_pobl(pobl_df, voro_df, pdi_df) # Tráfico print('Leyendo archivos de tráfico...') traficos_df = [] for filename in listdir('opendata/trafico'): traficos_df.append(gpd.read_file('opendata/trafico/' + filename)) print('Agregando datos de tráfico...') pdi_df = add_traffic(traficos_df, voro_df, pdi_df) # Tweets print('Leyendo archivo valencia_tweets...') with open('opendata/valencia_tweets.json', 'r') as input_file: tweets = json.load(input_file) tweets_df = gpd.GeoDataFrame(gpd.GeoSeries( Point(t['coordinates']['coordinates']) for t in tweets), columns=['geometry']) print('Agregando datos de redes sociales...') pdi_df = add_tweets(tweets_df, voro_df, pdi_df) # Paso 4: Guardar los archivos para el funcionamiento del algoritmo genético. print('Guardando puntos de interés...') pdi_df.to_file('puntos_de_interes.json', driver="GeoJSON") print('Guardando voronoi...') voro_df.to_file('voronoi.json', driver="GeoJSON") # Paso 5: Visualizar la información en mapa web. print('Generando mapa web...') valencia = [39.4561165311493, -0.3545661635] mapa = Map(location=valencia, tiles='OpenStreetMap', zoom_start=10) GeoJson(open('voronoi.json'), name='Diagrama de Voronoi').add_to(mapa) GeoJson(open('puntos_de_interes.json'), name='Puntos de Interés').add_to(mapa) LayerControl().add_to(mapa) mapa.save('valencia.html') print('Listo')
def html_map(contiguity_fname, html_out_fname, json_out_fname): """ Create HTML and GeoJSON files showing the valid geometry for the input contiguity image. :param contiguity_fname: A full file pathname to the image representing the data contiguity. :param html_out_fname: A full file pathname that will contain the html bounday map. :param json_out_fname: A full file pathname that will contain the json bounday map. :return: None; Outputs will be saved directly to disk. """ # remove any previous creations try: os.remove(html_out_fname) except OSError: pass try: os.remove(json_out_fname) except OSError: pass # Find metadata yaml and add to geopandas attributes #metadata = os.path.abspath(os.path.join(out_dir, "..", "ARD-METADATA.yaml")) logging.info("Create valid bounds " + json_out_fname) geom, crs = valid_region(contiguity_fname) gpdsr = gpd.GeoSeries([geom]) gpdsr.crs = crs gpdsr = gpdsr.to_crs({'init': 'epsg:4326'}) # TODO - Add metadata to PopUp #with open(metadata, 'r') as stream: # try: # yaml_metadata = yaml.load(stream) # except yaml.YAMLError as exc: # print(exc) #gpdyaml = gpd.GeoSeries(yaml_metadata) gpdsr.to_file(json_out_fname, driver='GeoJSON') m = folium.Map() #GeoJson(gpdsr, name='geojson').add_to(m) style_function = lambda x: {'fillColor': None, 'color': '#0000ff'} GeoJson(json_out_fname, name='bounds.geojson', style_function=style_function).add_to(m) # TODO - add MGRS tile reference to map with layer active = False #style_function = lambda x: {'fillColor': None, 'fillOpacity': 0.1, 'weight': 0.1, # 'color' : '#ff0000'} #GeoJson('/home/simonaoliver/reference/agdcv2-reference/MGRS_Australia.geojson', name='MGRS_tiles.geojson', style_function=style_function).add_to(m) m.fit_bounds(GeoJson(gpdsr).get_bounds()) folium.LatLngPopup().add_to(m) #m.add_child(folium.Popup("Insert Date Here")) folium.LayerControl().add_to(m) m.save(html_out_fname)
def test_geojson_find_identifier(): def _create(*properties): return { "type": "FeatureCollection", "features": [{ "type": "Feature", "properties": item } for item in properties] } def _assert_id_got_added(data): _geojson = GeoJson(data) assert _geojson.find_identifier() == 'feature.id' assert _geojson.data['features'][0]['id'] == '0' data_with_id = _create(None, None) data_with_id['features'][0]['id'] = 'this-is-an-id' data_with_id['features'][1]['id'] = 'this-is-another-id' geojson = GeoJson(data_with_id) assert geojson.find_identifier() == 'feature.id' assert geojson.data['features'][0]['id'] == 'this-is-an-id' data_with_unique_properties = _create( {'property-key': 'some-value'}, {'property-key': 'another-value'}, ) geojson = GeoJson(data_with_unique_properties) assert geojson.find_identifier() == 'feature.properties.property-key' data_with_unique_properties = _create( {'property-key': 42}, {'property-key': 43}, {'property-key': 'or a string'}, ) geojson = GeoJson(data_with_unique_properties) assert geojson.find_identifier() == 'feature.properties.property-key' # The test cases below have no id field or unique property, # so an id will be added to the data. data_with_identical_ids = _create(None, None) data_with_identical_ids['features'][0]['id'] = 'identical-ids' data_with_identical_ids['features'][1]['id'] = 'identical-ids' _assert_id_got_added(data_with_identical_ids) data_with_some_missing_ids = _create(None, None) data_with_some_missing_ids['features'][0]['id'] = 'this-is-an-id' # the second feature doesn't have an id _assert_id_got_added(data_with_some_missing_ids) data_with_identical_properties = _create( {'property-key': 'identical-value'}, {'property-key': 'identical-value'}, ) _assert_id_got_added(data_with_identical_properties) data_bare = _create(None) _assert_id_got_added(data_bare) data_empty_dict = _create({}) _assert_id_got_added(data_empty_dict) data_without_properties = _create(None) del data_without_properties['features'][0]['properties'] _assert_id_got_added(data_without_properties) data_some_without_properties = _create({'key': 'value'}, 'will be deleted') # the first feature has properties, but the second doesn't del data_some_without_properties['features'][1]['properties'] _assert_id_got_added(data_some_without_properties) data_with_nested_properties = _create({ "summary": { "distance": 343.2 }, "way_points": [3, 5], }) _assert_id_got_added(data_with_nested_properties) data_with_incompatible_properties = _create({ "summary": { "distances": [0, 6], "durations": None }, "way_points": [3, 5], }) _assert_id_got_added(data_with_incompatible_properties) data_loose_geometry = { "type": "LineString", "coordinates": [ [3.961389, 43.583333], [3.968056, 43.580833], [3.974722, 43.578333], [3.986389, 43.575278], [3.998333, 43.5725], [4.163333, 43.530556], ] } geojson = GeoJson(data_loose_geometry) geojson.convert_to_feature_collection() assert geojson.find_identifier() == 'feature.id' assert geojson.data['features'][0]['id'] == '0'
def _assert_id_got_added(data): _geojson = GeoJson(data) assert _geojson.find_identifier() == 'feature.id' assert _geojson.data['features'][0]['id'] == '0'