I'm trying to overlay an esri bathymetry map on my south polar stereographic map using the 'url' function in ipyleaflet. Doing this results with {z}/{y}/{x} in the url inserts the layer, but at a smaller size in the right-hand corner of the basemap. I tried to give the tilelayer the same crs, but that did not change the output. My code is as such:
from ipyleaflet import (
Map,
basemaps,
TileLayer,
basemap_to_tiles,
projections)
from ipywidgets import (Layout,
widgets as w
tile_layer = TileLayer(url='https://tiles.arcgis.com/tiles/C8EMgrsFcRFL6LrL/arcgis/rest/services/Antarctic_Basemap/MapServer/tile/{z}/{y}/{x}')
spsLayout = Layout(width='800px', height='800px')
m = Map(center=(-90, 0),
zoom=0,
layout=spsLayout,
basemap= basemaps.NASAGIBS.BlueMarble3031,
crs=projections.EPSG3031)
m.add_layer(tile_layer)
m
Here's where I got the url for the tiles In the bottom right. Thanks for your help!
I think the issue here is that this bathymetry base map use a different tilegrid(metatiles 3x3) from the one used with ipyleaflet(4x4). Unfortunately I don't think there is currently a way for Leaflet(hence ipyleaflet) to understand multiple tilegrids in the same map. A workaround would be to use ArcGIS in your notebook instead of ipyleaflet but that would require a paid subscription.
If you don't mind defining your own projection and resolutions you can use the ArcGIS layers and avoid completely thedefault polar projection and basemaps from ipyleaflet. i.e.
from ipyleaflet import (
Map,
basemaps,
TileLayer,
basemap_to_tiles,
projections)
ESRI_3031 = dict(
name='EPSG:3031',
custom=True,
proj4def="""+proj=stere +lat_0=-90 +lat_ts=-71 +lon_0=0 +k=1
+x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs""",
origin=[-3.06361E7, 3.0636099999999993E7],
resolutions=[
67733.46880027094,
33866.73440013547,
16933.367200067736,
8466.683600033868,
4233.341800016934,
2116.670900008467,
1058.3354500042335,
529.1677250021168,
264.5838625010584,
],
bounds=[
[-4524583.19363305,-4524449.487765655],
[4524449.4877656475,4524583.193633042]
]
)
tile_layer = TileLayer(url='https://tiles.arcgis.com/tiles/C8EMgrsFcRFL6LrL/arcgis/rest/services/Antarctic_Basemap/MapServer/tile/{z}/{y}/{x}')
spsLayout = Layout(width='800px', height='800px')
m = Map(center=(-90, 0),
zoom=0,
layout=spsLayout,
basemap= tile_layer,
crs=ESRI_3031)
m
Related
I am trying to plot Antarctic Sea-Ice EPSG:3031 data using ipyleaflet like so:
from ipyleaflet import Map, WMSLayer, basemaps
wms = WMSLayer(
url='http://geos.polarview.aq/geoserver/wms',
layers='polarview:iceedgeS15',
format='image/png',
transparent=True,
attribution='Polarview'
)
m = Map(basemap=basemaps.NASAGIBS.BlueMarble3031, center=(-90, 0), zoom=1, crs=projections.EPSG3031)
m.add_layer(wms)
m
The photos in the following links illustrate my issues clearly:
The data and the basemap do not align
If I omit the basemap and projection information it looks reasonable in terms of alignment but doesn't have the perspective and projection I desire. I have been also been using Leafmap to add local geotiffs and run into similar issues.
I have read through a few relevant PRs and checked out xarray-leaflet but haven't had any luck. This sea-ice concentration data is an example of a non-wms data source that I encounter the same problem with which could be helpful for testing purposes.
Great question.
You'll need to add coordinate reference system (CRS) information to your WMSLayer. See the custom projections notebook within the ipyleaflet examples. For spatial projections that are not Web Mercator (EPSG:3857), you'll likely need to define the bounds of your imagery.
from ipyleaflet import Map, WMSLayer, basemaps
# create map with NASA Blue Marble as background
m2 = Map(basemap=basemaps.NASAGIBS.BlueMarble3031,
center=(-90, 0), zoom=1, crs=projections.EPSG3031)
# projection for Polarview sea ice edge
POLAR3031 = dict(
name='EPSG:3031',
custom=True,
proj4def="""+proj=stere +lat_0=-90 +lat_ts=-71 +lon_0=0 +k=1
+x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs""",
bounds=[[-2822131.5,-3057369.25],[3744213.75,3822194.25]]
)
wms = WMSLayer(
url='http://geos.polarview.aq/geoserver/wms',
layers='polarview:iceedgeS15',
format='image/png',
transparent=True,
attribution='Polarview',
crs=POLAR3031
)
m2.add(wms)
# show map
m2
I am exploring Google Earth Engine and trying some band operation. I have calculated NDVI using two methods,
Calculating using normalizedDifference function
Calculating using normal band operation.
But I have checked both returns different results, why is so? Is not it the same operation that runs in the normalized difference function.
Here is my code.
#Import earth engine
import ee
# Trigger the authentication flow.
ee.Authenticate()
# Initialize the library.
ee.Initialize()
# Load two 5 year Landsat 7 composite
landsat2008 = ee.Image('LANDSAT/LE7_TOA_5YEAR/2008_2012')
# Compute NDVI using normalizedDifference
ndvi2008_m1 = landsat2008.normalizedDifference(["B4", 'B3'])
##NDVI using method2
diff=landsat2008.select('B4').subtract(landsat2008.select('B3'))
added=landsat2008.select('B4').add(landsat2008.select('B3'))
ndvi2008_m2 = diff.divide(added)
ndvi2008_m2==ndvi2008_m1
ndviParams = {'palette': ["#d73027", "#f46d43", "#fdae61", "#fee08b", "#d9ef8b", '#a6d96a', '#66bd63', '#1a9850']}
# Import the Folium library.
import folium
# Define a method for displaying Earth Engine image tiles to folium map.
def add_ee_layer(self, ee_image_object, vis_params, name):
map_id_dict = ee.Image(ee_image_object).getMapId(vis_params)
folium.raster_layers.TileLayer(
tiles = map_id_dict['tile_fetcher'].url_format,
attr = 'Map Data © Google Earth Engine',
name = name,
overlay = True,
control = True
).add_to(self)
# Add EE drawing method to folium.
folium.Map.add_ee_layer = add_ee_layer
# Create a folium map object.
my_map = folium.Map(location=[9, 39], zoom_start = 2)
# Add the layer to the map object.
my_map.add_ee_layer(ndvi2008_m1, ndviParams, 'ndvi2008_m1')
my_map.add_ee_layer(ndvi2008_m2, ndviParams, 'ndvi2008_m2')
# Add a layer control panel to the map.
my_map.add_child(folium.LayerControl())
# Display the map.
display(my_map)
Casting the image to float solve this (in Javascript).
Anyway, the difference is very (very) small.
I am creating an interactive map using ipyleaflet using the following code:
from ipyleaflet import Map, Polygon
polygon = Polygon(
locations=[[(38.844185,-4.804621),(39.241299,-1.899833),(40.74308,-2.205491),(40.34742,-5.17429),(38.844185,-4.804621)],[(39.365192,-1.941078),(40.867912,-1.567062),(41.276688,-4.670904),(39.775406,-4.976737),(39.365192,-1.941078)],[(39.706161,-1.849863),(41.207623,-1.465817),(41.617561,-4.594476),(40.117233,-4.908839),(39.706161,-1.849863)],[(39.702591,-5.033657),(40.101254,-2.077048),(41.602196,-2.389729),(41.204681,-5.413605),(39.702591,-5.033657)]],
color="green",
fill_opacity= 0.5,
fill_color="green"
)
m = Map(center=(38.5531, -4.6914), zoom=6)
m.add_layer(polygon);
m
The ouptut looks like this:
I am wondering how can I make the intersection of the polygons not be fully transparent. Looking at the attributes https://ipyleaflet.readthedocs.io/en/latest/api_reference/polygon.html in the documentation, I don't see any option?
An example of the desired output can be seen in the image below:
You've got bad results because ipyleaflet subtracts ovellaped polygons (you can see it in second example in the documentation link you posted, "Polygon with hole")
You need to add each polygon separately, I changed your code a bit, now it creates and applies polygons in loop:
from ipyleaflet import Map, Polygon
poligons = [[(38.844185,-4.804621),(39.241299,-1.899833),(40.74308,-2.205491),(40.34742,-5.17429),(38.844185,-4.804621)],
[(39.365192,-1.941078),(40.867912,-1.567062),(41.276688,-4.670904),(39.775406,-4.976737),(39.365192,-1.941078)],
[(39.706161,-1.849863),(41.207623,-1.465817),(41.617561,-4.594476),(40.117233,-4.908839),(39.706161,-1.849863)],
[(39.702591,-5.033657),(40.101254,-2.077048),(41.602196,-2.389729),(41.204681,-5.413605),(39.702591,-5.033657)]]
m = Map(center=(38.5531, -4.6914), zoom=6)
for poly in poligons:
polygon = Polygon(
locations= poly,
color="green",
fill_opacity= 0.5,
fill_color="green"
)
m.add_layer(polygon);
m
Result:
I am using folium to generate some maps and one of the features I am including is the markercluster overlay - as I am frequently plotting thousands of points on a map. The clustering groups GPS points of varying quantities together and overlays a number on top of the map icon, which represents how many points have been grouped together into that cluster. By default, the fewer points grouped together in a cluster will result in a green color for the map icon and the more points grouped together will be more towards the red spectrum. Ideally, I would like to reverse this, so that when there are a lot of consolidated points in one location, the icon will be green. Whereas when there are only a few consolidated points, the color will be red. I'm thinking this needs to be edited in the branca module somewhere, but I'm not sure and generally pretty unfamiliar with how branca works. Any help is much appreciated.
Here's an example of how marker clusters are typically created:
import folium
from folium.plugins import MarkerCluster
#Create the map image and establish the center point
mapImage = folium.Map(location=[40.165505, -99.788130],
zoom_start=12,
tiles='OpenStreetMap')
#Create the marker cluster group, which organizes all the gps points put into it
marker_cluster_group = MarkerCluster(name='Cluster Icons')
#This is just a reference to a default google mapping icon, purely optional
pointIcon_url = "http://maps.google.com/mapfiles/kml/shapes/shaded_dot.png"
#Create the icon object
icon = folium.features.CustomIcon(pointIcon_url, icon_size=(15, 15))
#Create the marker/gps point and add it to the cluster group
folium.Marker([40.058377, -99.939192], icon=icon).add_to(marker_cluster_group)
#Adding the cluster group to the map image
marker_cluster_group.add_to(mapImage)
You can provide the MarkerCluster class with an argument icon_create_function which will style the cluster icons:
https://github.com/python-visualization/folium/blob/8595240517135d1637ca4cf7cc624045f1d911b3/folium/plugins/marker_cluster.py#L31
Here you can see an example of how that function should look like:
https://github.com/Leaflet/Leaflet.markercluster#customising-the-clustered-markers
So it's a Javascript function, that you provide to folium as a string.
With the help of #Conengmo 's response, I was able to get the info I needed and modify it as needed to create the below.
import folium
from folium.plugins import MarkerCluster
#Create the map image and establish the center point
mapImage = folium.Map(location=[40.165505, -99.788130],
zoom_start=12,
tiles='OpenStreetMap')
#Create a variable to store your javascript function (written as a string), which adjusts the default css functionality
#The below are the attributes that I needed for my project, but they can be whatever is needed for you
icon_create_function = """
function(cluster) {
var childCount = cluster.getChildCount();
var c = ' marker-cluster-';
if (childCount < 50) {
c += 'large';
} else if (childCount < 300) {
c += 'medium';
} else {
c += 'small';
}
return new L.DivIcon({ html: '<div><span>' + childCount + '</span></div>', className: 'marker-cluster' + c, iconSize: new L.Point(40, 40) });
}
"""
#Create the marker cluster group, which organizes all the gps points put into it
marker_cluster_group = MarkerCluster(name='Cluster Icons', icon_create_function=icon_create_function)
#This is just a reference to a default google mapping icon, purely optional
pointIcon_url = "http://maps.google.com/mapfiles/kml/shapes/shaded_dot.png"
#Create the icon object
icon = folium.features.CustomIcon(pointIcon_url, icon_size=(15, 15))
#Create the marker/gps point and add it to the cluster group
folium.Marker([40.058377, -99.939192], icon=icon).add_to(marker_cluster_group)
#Adding the cluster group to the map image
marker_cluster_group.add_to(mapImage)
I have a folium map of a neighborhood in New York City generated using the following code:
m = folium.Map(location=[40.7035, -73.990],
zoom_start=16.5,
tiles='cartodbpositron')
I then try to add lines connecting points on the map using folium.PolyLine(), but even though I see them listed when I call m._children, they don't show up on the map.
Here's the code to create the lines, where G is a networkx graph:
for x, y in G.edges():
points = [nx.get_node_attributes(G, 'loc')[x], nx.get_node_attributes(G, 'loc')[y]]
egde = folium.PolyLine(locations=points, weight=5, color='red')
edge.add_to(m)
A sample point:
[(-73.986635, 40.703988), (-73.988683, 40.702674)]
Output of m.children (first few lines):
OrderedDict([('cartodbpositron',
<folium.raster_layers.TileLayer at 0x12279feb8>),
('poly_line_ae5785771a2148c5a8559cb0085b10a4',
<folium.vector_layers.PolyLine at 0x122892128>),
('poly_line_ee73b495559940d484064e8c8492eda5',
<folium.vector_layers.PolyLine at 0x1229734a8>),
('poly_line_415a7ed70a2a425e876c8a6711408a6a', ...
Any idea what I might be doing wrong?
This is kind of odd that folium polyline expects coordinates in [latitude, longitude] format, whereas in general accepted format is [longitude, latitude].
Let's take an example:
I'm assuming you are using OSRM to get geometries.
OSRM geometries returns coordinates in the form of [[longitude,latitude],...].
If you'll directly use them with folium, it'll not show the polyline.
Reverse the geometry coordinates using following function:
def reverse_lon_lat(x):
a = [[p[1], p[0]] for p in x]
return a
and draw the polylines you intend to.