@@ -936,71 +936,82 @@ def json_style(style_cnt, line_color, line_weight, line_opacity,
936936 self .template_vars .setdefault ('gjson_layers' , []).append (layer )
937937
938938 @iter_obj ('image_overlay' )
939- def image_overlay (self , data , opacity = 0.75 , min_lat = - 90.0 , max_lat = 90.0 ,
939+ def image_overlay (self , data , image_opacity = 1 , min_lat = - 90.0 , max_lat = 90.0 ,
940940 min_lon = - 180.0 , max_lon = 180.0 , image_name = None ,
941- filename = None , data_projection = 'mercator' ):
942- """Simple image overlay of raster data from a numpy array. This is a
943- lightweight way to overlay geospatial data on top of a map.
944- If your data is high res, consider implementing a WMS server
945- and adding a WMS layer.
946-
947- This function works by generating a PNG file from a numpy
948- array. If you do not specify a filename, it will embed the
949- image inline. Otherwise, it saves the file in the current
950- directory, and then adds it as an image overlay layer in
951- leaflet.js. By default, the image is placed and stretched
952- using bounds that cover the entire globe. By default, we
953- assume that your data is in geodetic projection and thus
954- project it to web mercator for display purposes. If you are
955- overlaying a non-georeferenced image, set data_projection to
956- None.
941+ filename = None ):
942+ """
943+ Simple image overlay of raster `data` from an image or a NumPy array.
944+ This is a lightweight way to overlay geospatial data on top of a map.
945+ The default lon, lat corners are the whole globe. Adjust it to your
946+ image.
947+
948+ If `data` is is a NumPy array a PNG file will be created for you.
949+ If you do not specify a filename the image will be embedded inline.
950+
951+ NOTE: The image must be projected as Web Mercator
952+ (https://en.wikipedia.org/wiki/Web_Mercator). See the examples below
953+ for re-projection.
957954
958955 Parameters
959956 ----------
960- data: numpy array OR url string, required.
961- if numpy array, must be a image format,
962- i.e., NxM (mono), NxMx3 (RGB), or NxMx4 (RGBA)
963- if url, must be a valid url to a image (local or external)
964- opacity: float, default 0.75
965- Image layer opacity in range 0 (transparent) to 1 (opaque)
966- min_lat: float, default -90.0
967- max_lat: float, default 90.0
968- min_lon: float, default -180.0
969- max_lon: float, default 180.0
957+ data: NumPy array OR image.
958+ The NumPy array can NxM (mono), NxMx3 (RGB), or NxMx4 (RGBA)
959+ image_opacity: float, default 1
960+ Image layer image_opacity in range 0 (transparent) to 1 (opaque)
961+ min_lat: float (default: -90)
962+ max_lat: float (default: 90)
963+ min_lon: float (default: -180)
964+ max_lon: float (default" 180)
970965 image_name: string, default None
971966 The name of the layer object in leaflet.js
972967 filename: string or None, default None
973968 Optional file name of output.png for image overlay.
974969 If None, we use a inline PNG.
975- data_projection: string or None, default 'mercator'
976- Used to specify projection of image. If None, do no projection
977970
978971 Output
979972 ------
980973 Image overlay data layer in obj.template_vars
981974
982975 Examples
983976 -------
984- # Assumes a map object `m` has been created.
985977 >>> import numpy as np
986- >>> data = np.random.random((180,360))
987-
988- # Place the data over all of the globe (will be pretty pixelated!)
989- >>> m.image_overlay(data)
990-
991- # Put it only over a single city (Paris)
992- >>> m.image_overlay(data, min_lat=48.80418, max_lat=48.90970,
993- ... min_lon=2.25214, max_lon=2.44731)
978+ >>> import matplotlib
979+ >>> def sample_data(shape=(73, 145)):
980+ ... nlats, nlons = shape
981+ ... lats = np.linspace(-np.pi / 2, np.pi / 2, nlats)
982+ ... lons = np.linspace(0, 2 * np.pi, nlons)
983+ ... lons, lats = np.meshgrid(lons, lats)
984+ ... wave = 0.75 * (np.sin(2 * lats) ** 8) * np.cos(4 * lons)
985+ ... mean = 0.5 * np.cos(2 * lats) * ((np.sin(2 * lats)) ** 2 + 2)
986+ ... lats = np.rad2deg(lats)
987+ ... lons = np.rad2deg(lons)
988+ ... data = wave + mean
989+ ... return lons, lats, data
990+ >>> # Lets create some data,
991+ >>> lon, lat, data = sample_data(shape=(73, 145))
992+ >>> lon -= 180
993+ >>> # and color it.
994+ >>> cm = matplotlib.cm.get_cmap('cubehelix')
995+ >>> normed_data = (data - data.min()) / (data.max() - data.min())
996+ >>> colored_data = cm(normed_data)
997+ >>> # First no projection (wrong).
998+ >>> map = folium.Map(location=[lat.mean(), lon.mean()], zoom_start=1)
999+ >>> map.image_overlay(colored_data,
1000+ ... min_lat=lat.min(), max_lat=lat.max(),
1001+ ... min_lon=lon.min(), max_lon=lon.max(),
1002+ ... image_opacity=0.25)
1003+ >>> # Now lets project the data as to Web Mercator (correct).
1004+ >>> map = folium.Map(location=[lat.mean(), lon.mean()], zoom_start=1)
1005+ >>> project = geodetic_to_mercator(colored_data)
1006+ >>> map.image_overlay(projected,
1007+ ... min_lat=lat.min(), max_lat=lat.max(),
1008+ ... min_lon=lon.min(), max_lon=lon.max(),
1009+ ... image_opacity=0.25)
9941010
9951011 """
9961012 if isinstance (data , str ):
9971013 filename = data
9981014 else :
999- assert data_projection in [None , 'mercator' ]
1000- # This assumes a lat x long array.
1001- # with 2x as many points in long as lat dims.
1002- if data_projection is 'mercator' :
1003- data = utilities .geodetic_to_mercator (data )
10041015 try :
10051016 png_str = utilities .write_png (data )
10061017 except Exception as e :
@@ -1015,19 +1026,20 @@ def image_overlay(self, data, opacity=0.75, min_lat=-90.0, max_lat=90.0,
10151026
10161027 if image_name not in self .added_layers :
10171028 if image_name is None :
1029+ # FIXME: This will fails with multiple overlays!
10181030 image_name = "Image_Overlay"
10191031 else :
1032+ # FIXME: We should write a more robust `name_normalizer()`.
10201033 image_name = image_name .replace (" " , "_" )
10211034 image_url = filename
10221035 image_bounds = [[min_lat , min_lon ], [max_lat , max_lon ]]
1023- image_opacity = opacity
10241036
1025- image_temp = self .env .get_template ('image_layer.js' )
1037+ image_templ = self .env .get_template ('image_layer.js' )
10261038
1027- image = image_temp .render ({'image_name' : image_name ,
1028- 'image_url' : image_url ,
1029- 'image_bounds' : image_bounds ,
1030- 'image_opacity' : image_opacity })
1039+ image = image_templ .render ({'image_name' : image_name ,
1040+ 'image_url' : image_url ,
1041+ 'image_bounds' : image_bounds ,
1042+ 'image_opacity' : image_opacity })
10311043
10321044 self .template_vars ['image_layers' ].append (image )
10331045 self .added_layers .append (image_name )
0 commit comments