Opening Street View with Python Folium map
Folium is a powerful Python library dedicated to geospatial data visualization. Its major engine is based on Leaflet – an open-source JavaScript library for mobile-friendly interactive maps. There are a lot of sources on the web, where anyone can find the basics of data displaying with Python Folium in several different ways. Most of them are similar to each other and their range plays within a standard frame of the Folium documentation. I am going to show you just a simple example of playing with One of the subjects inscribed in the Folium documentation is defining the string with the elements of HTML code, which can be used not only for reading data purposes but also for bringing up some additional features potentially desired in our final geospatial data visualization.
I think we can consider two of the simplest ways of providing the Street View to our Folium map. The first way is including the relevant link in the popup assigned to our layer, and the second way is like the on-click feature, where by knowing the current coordinates you can access the Street View from the place on which you already clicked.
Let’s start from scratch basically and consider the link, which is “responsible” for initiating the Google Street View page elsewhere without any hassle. I do not mean the link, which you can see later when your streetside is loaded, but the link, which initializes it.
https://www.google.com/maps?layer=c&cbll=51.553691,-0.262228
http://maps.google.com/maps?q=&layer=c&cbll=51.553691,-0.262228
http://maps.google.com/maps=&layer=c&cbll=31.335198,-89.287204&cbp=11,0,0,0,0
https://www.google.com/maps/@51.5537806,-0.2621203,3a,75y,90t/data=!3m6!1
e1!3m4!1sIKvOBTCKtaz2fi80vT7hIg!2e0!7i16384!8i8192
The first 4 links provided are the most important because it initializes Google Street View, which eventually works under the fifth link, which has been discussed in the previous article. Knowing the initial link, we can plot it in any string programmatically. It can be done simply by concatenation, which works similarly for various programming languages.
1. Access to Street View by Pop-up – it’s the way of getting the street view image from the popup feature defined for our items fetched i.e. from .geojson or .csv file. See the example below (wrapped code without line breaks):
df = pd.read_csv("cf_geo.csv") fc=folium.FeatureGroup(name="CF_GEO",overlay=True) cf_cluster = MarkerCluster(name="CF_GEO").add_to(map) for i,row in df.iterrows(): lat = df.at[i, 'lat'] #latitude lng = df.at[i, 'lng'] #longitude sp = df.at[i, 'sp'] stat = df.at[i,'status'] popup = df.at[i,'sp'] +'<br>' + str(df.at[i, 'street']) + '<br>' + str(df.at[i, 'post code']) + '<br>' + '<a href="https://www.google.com/maps?layer=c&cbll=' + str(df.at[i, 'lat']) + ',' + str(df.at[i, 'lng']) + '" target="blank">GOOGLE STREET VIEW</a>' cf_marker = folium.Marker(location=[lat,lng], popup=popup, icon = folium.Icon(color='green', icon='glyphicon-calendar')) cf_cluster.add_child(cf_marker)
which corresponds to the image below (Pic. 1):
but we have to remember one thing here. The coordinates provided from our .geojson or .csv file are numerical. Placing them directly inside the string will result in the following error:
TypeError: can only concatenate str (not “NumPy.float64”) to str
therefore instead of just:
df.at[i, 'lat']
we have to convert these numerical values to strings
str(df.at[i, 'lat'])
and then include them in the URL string.
2. Street View access like on-click feature – this is another method of opening the Google Street View in Python folium map. There is a nice feature for Python folium map – LatLngPopup, which brings you the on-click coordinates of any point on your map. The code can look like this:
map.add_child(folium.LatLngPopup())
and populates the on-click coordinates in the popup. With the help of friendly Python libraries (branca.element.MacroElement and jinja2) this plugin can be edited by the access to the JavaScript code, which initially looks like this (wrapped code without line breaks):
class LatLngtoForm(folium.LatLngPopup):
"""
Place for the description of the tool
"""
_template = Template(u"""
{% macro script(this, kwargs) %}
var {{this.get_name()}} = L.popup();
function latLngPop(e) {
{{this.get_name()}}
.setLatLng(e.latlng)
.setContent("Latitude: " + e.latlng.lat.toFixed(4) + "<br>Longitude: " + e.latlng.lng.toFixed(4))
.openOn({{this._parent.get_name()}});
} {{this._parent.get_name()}}.on('click', latLngPop);
{% endmacro %}
""") # noqa
def __init__(self):
super(LatLngtoForm, self).__init__()
self._name = 'LatLngtoPopup'
latlon = LatLngPopup()
map.add_child(latlon)
and everything is enclosed with {% macro script(this, kwargs) %} JavaScript code {% endmacro %}
For us, the most important is the content of our popup, which has been emboldened. We can find there the string concatenated with the latlng property. Now, we will expand this concatenation by adding the anchor for the Street View location. Moreover, the icon could be also added optionally.
class LatLngPopup(MacroElement): """ Place for the description of the tool """ _template = Template(u""" {% macro script(this, kwargs) %} var {{this.get_name()}} = L.popup(); function latLngPop(e) { data = e.latlng.lat.toFixed(4) + "," + e.latlng.lng.toFixed(4); {{this.get_name()}} .setLatLng(e.latlng) .setContent( "<a href=https://www.google.com/maps?layer=c&cbll=" + data + " target=blank ><img src=img/streetview.svg width=150></img></a>") .openOn({{this._parent.get_name()}}) } {{this._parent.get_name()}}.on('click', latLngPop); {% endmacro %} """) # noqa def __init__(self): super(LatLngPopup, self).__init__() self._name = 'LatLngPopup' latlon = LatLngPopup() map.add_child(latlon)
As proof let’s see the image below (Pic. 2):
It’s not the last way of accessing the Street View from the Python Folium map. Analog approaches can be made by using the folium.ClickForMarker feature, which initially looks as follows:
class ClickForOneMarker(folium.ClickForMarker): """ Description of the tool """ _template = Template(u""" {% macro script(this, kwargs) %} var new_mark = L.marker(); function newMarker(e){ new_mark.setLatLng(e.latlng).addTo({{this._parent.get_name()}}); new_mark.dragging.enable(); new_mark.on('dblclick', function(e){ {{this._parent.get_name()}}.removeLayer(e.target)}) var lat = e.latlng.lat.toFixed(4), lng = e.latlng.lng.toFixed(4); new_mark.bindPopup({{ this.popup }}); parent.document.getElementById("latitude").value = lat; parent.document.getElementById("longitude").value =lng; }; {{this._parent.get_name()}}.on('click', newMarker); {% endmacro %} """) # noqa def __init__(self, popup=None): super(ClickForOneMarker, self).__init__(popup) self._name = 'ClickForOneMarker' click_for_marker = ClickForOneMarker() map.add_child(click_for_marker)
and after modifying the popup content it could look as this:
class ClickForOneMarker(folium.ClickForMarker): """ Description of the tool """ _template = Template(u""" {% macro script(this, kwargs) %} var new_mark = L.marker(); function newMarker(e){ new_mark.setLatLng(e.latlng).addTo({{this._parent.get_name()}}); new_mark.dragging.enable(); new_mark.on('dblclick', function(e){ {{this._parent.get_name()}}.removeLayer(e.target)}) var lat = e.latlng.lat.toFixed(4), lng = e.latlng.lng.toFixed(4); new_mark.bindPopup("<a href=https://www.google.com/maps?layer=c&cbll=" + lat + "," + lng + " target=blank >Google Street View</a>"); parent.document.getElementById("latitude").value = lat; parent.document.getElementById("longitude").value =lng; }; {{this._parent.get_name()}}.on('click', newMarker); {% endmacro %} """) # noqa def __init__(self, popup=None): super(ClickForOneMarker, self).__init__(popup) self._name = 'ClickForOneMarker' click_for_marker = ClickForOneMarker() map.add_child(click_for_marker)
with the result as shown in the image below (Pic. 3), where Street View can be launched by clicking on the popup.
We can also use another way of launching Street View from the Python Folium map. Besides using MacroElement, we can simply quote JavaScript code inside the freestanding Folium element, as shown below (wrapped code without line breaks):
gugl = """ $ (document).ready(function (e) { var new_mark = L.marker(); function newMarker(e){ new_mark.setLatLng(e.latlng).addTo({map}); new_mark.setZIndexOffset(-1); new_mark.on('dblclick', function(e){ ({map}).removeLayer(e.target)}) var lat = e.latlng.lat.toFixed(4), lng = e.latlng.lng.toFixed(4); new_mark.bindPopup( "<a href=https://www.google.com/maps?layer=c&cbll=" + lat + "," + lng + " target=blank><img src=img/streetview.svg width=70 title=StreetView class=StreetViewImage></img></a>",{ maxWidth: "auto", className: 'StreetViewPopup' }); }; ({map}).on('click', newMarker); }); """.replace("{map}", mapCirclVar) e = folium.Element(gugl) html = map.get_root() html.script.add_child(e)
where the code looks exactly the same, but instead of embedding it inside the MacroElement we define it under folium.Element enshrouding it with the jQuery elements $ (document).ready(function (e) { the js code }); which means, that the Javascript code can be run safely. Make sure, that your current map ID (defined automatically by Folium) is superseded with some generic variable, as presented above in the code.
The way of running Street View from Python Folium map is effortless. The examples provided can be modified further with respect to making your popup displayed automatically, etc.
Mariusz Krukar
Links:
- https://python-visualization.github.io/folium/
- https://towardsdatascience.com/creating-a-simple-map-with-folium-and-python-4c083abfff94
- https://copyprogramming.com/howto/link-to-street-view-url-using-address
- https://www.w3schools.com/python/gloss_python_string_concatenation.asp
- https://bobbyhadz.com/blog/python-typeerror-can-only-concatenate-str-not-numpy-int64-to-str
- https://www.kaggle.com/code/codebreaker619/introduction-to-folium/notebook
- https://snyk.io/advisor/python/branca/functions/branca.element.MacroElement
- https://github.com/python-visualization/folium/blob/main/folium/features.py
- https://raw.githubusercontent.com/chlyoo/lostring/master/user_folium/user_folium.py
- https://learn.jquery.com/using-jquery-core/document-ready/
Forums:
- https://stackoverflow.com/questions/387942/google-street-view-url
- https://stackoverflow.com/questions/38426844/link-to-street-view-url-using-address
- Drupal.org: Wondering how to add Google Street View link
- https://gis.stackexchange.com/questions/100062/convert-google-street-view-urls-from-old-to-new
- Github.com: Returning Latitude, Longitude values from folium map on mouse click to python script (streamlit webapp)
- https://stackoverflow.com/questions/63413571/returning-latitude-longitude-values-from-folium-map-on-mouse-click-to-python-sc
- https://stackoverflow.com/questions/73481046/how-to-overide-a-feature-method-in-folium
- https://gis.stackexchange.com/questions/313382/click-event-on-maps-with-folium-and-information-retrieval
- https://stackoverflow.com/questions/60479995/adding-javascript-to-folium-map
- https://stackoverflow.com/questions/74869635/show-paths-in-folium-map-by-clicking-on-markers
My questions: