from veroviz._common import *
from veroviz._validation import valCreateLeaflet
from veroviz._validation import valAddLeafletCircle
from veroviz._validation import valAddLeafletMarker
from veroviz._validation import valAddLeafletPolygon
from veroviz._validation import valAddLeafletPolyline
from veroviz._validation import valAddLeafletText
from veroviz._validation import valAddLeafletIcon
from veroviz._validation import valAddLeafletIsochrones
from veroviz._validation import valAddLeafletWeather
from veroviz._internal import replaceBackslashToSlash
from veroviz._internal import splitLeafletCustomIconType
from veroviz._deconstructAssignments import deconstructAssignments
from veroviz._createEntitiesFromList import privCreateArcsFromLocSeq
from veroviz._utilities import privGetMapBoundary
from veroviz._geometry import geoDistancePath2D
from veroviz._geometry import geoMileageInPath2D
from veroviz._geometry import geoDistance2D
from veroviz._geometry import geoGetHeading
from veroviz._geometry import geoPointInDistance2D
foliumMaps = [
'cartodb positron',
'cartodb dark_matter',
'openstreetmap',
'stamen terrain',
'stamen toner',
'stamen watercolor'
]
weatherMaps = {
'clouds': {
'tiles': 'https://tile.openweathermap.org/map/clouds_new/{z}/{x}/{y}.png?appid=',
'attr': 'openweathermap.org'
},
'precip': {
'tiles': 'https://tile.openweathermap.org/map/precipitation_new/{z}/{x}/{y}.png?appid=',
'attr': 'openweathermap.org'
},
'pressure': {
'tiles': 'https://tile.openweathermap.org/map/pressure_new/{z}/{x}/{y}.png?appid=',
'attr': 'openweathermap.org'
},
'wind': {
'tiles': 'https://tile.openweathermap.org/map/wind_new/{z}/{x}/{y}.png?appid=',
'attr': 'openweathermap.org'
},
'temp': {
'tiles': 'https://tile.openweathermap.org/map/temp_new/{z}/{x}/{y}.png?appid=',
'attr': 'openweathermap.org'
}
}
customMaps = {
'arcgis aerial': {
'tiles': 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
'attr': 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
},
'arcgis gray': {
'tiles': 'https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}',
'attr': 'Tiles © Esri — Esri, DeLorme, NAVTEQ'
},
'arcgis ocean': {
'tiles': 'https://server.arcgisonline.com/ArcGIS/rest/services/Ocean_Basemap/MapServer/tile/{z}/{y}/{x}',
'attr': 'Tiles © Esri — Sources: GEBCO, NOAA, CHS, OSU, UNH, CSUMB, National Geographic, DeLorme, NAVTEQ, and Esri'
},
'arcgis roadmap': {
'tiles': 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}',
'attr': 'Tiles © Esri — Source: Esri'
},
'arcgis shaded relief': {
'tiles': 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/{z}/{y}/{x}',
'attr': 'Tiles © Esri — Source: Esri'
},
'arcgis topo': {
'tiles': 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}',
'attr': 'Tiles © Esri — Source: Esri'
},
'open topo': {
'tiles': 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png',
'attr': 'Map data: © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, <a href="http://viewfinderpanoramas.org">SRTM</a> | Map style: © <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)'
},
}
[docs]def createLeaflet(mapObject=None, mapFilename=None, mapBackground=config['VRV_DEFAULT_LEAFLET_MAPTILES'], mapBoundary=None, zoomStart=None, nodes=None, iconPrefix=None, iconType=None, iconColor=None, iconText=None, arcs=None, arcWeight=None, arcStyle=None, arcOpacity=None, arcCurveType=None, arcCurvature=None, arcColor=None, useArrows=None, arrowsPerArc=1, boundingRegion=None, boundingWeight=config['VRV_DEFAULT_LEAFLETBOUNDINGWEIGHT'], boundingOpacity=config['VRV_DEFAULT_LEAFLETBOUNDINGOPACITY'], boundingStyle=config['VRV_DEFAULT_LEAFLETBOUNDINGSTYLE'], boundingColor=config['VRV_DEFAULT_LEAFLETBOUNDINGCOLOR']):
"""
createLeaflet is used to generate Leaflet objects using folium. The function takes a boundingRegion polygon, `Nodes`, `Arcs`, and `Assignments` dataframes as inputs, and creates a folium/leaflet map showing boundings, nodes and/or arcs.
Parameters
----------
mapObject: Folium object, Optional, default as None
If you already have a map (as a Folium object), you can provide that object and add content to that map.
mapFilename: string, Optional, default as None
This is the name of the map file that will be created (e.g., "../output/map.html" or "map.html"). The filename should have a `.html` extension. If `mapFilename` is not provided, no map file will be generated. The returned map object can be viewed within a Jupyter notebook.
mapBackground: string, Optional, default as 'CartoDB positron'
Sets the background tiles of the map. See :ref:`Leaflet Style` for the list of options.
mapBoundary: list of lists, Optional, default as None
Allows customization of the zoom level. If a map boundary is provided, the zoom level will correspond to the rectangle defined by the two map boundary points. This feature is useful if you want to create multiple comparison maps, each with the same zoom level and centering. Must be in the form [[south lat, west lon], [north lat, east lon]].
zoomStart: int, Optional, default as None
Specifies the default zoom level. 1 --> global view; 18 --> max zoom. Note that some map tiles have maximum zoom levels less than 18. The `zoomStart` will be overridden by a `mapBoundary` (if one is provided).
nodes: :ref:`Nodes`, Conditional, `nodes`, `arcs`, and `boundingRegion` can not be None at the same time
A Nodes dataframe describing the collection of nodes to be displayed on the Leaflet map. See :ref:`Nodes` for documentation on this type of dataframe.
iconPrefix: string, Optional, default as None
Overrides the `leafletIconPrefix` column of an input :ref:`Nodes` dataframe. If provided, all nodes will use this icon prefix. Valid options are "glyphicon", "fa", or "custom". See :ref:`Leaflet Style` for details.
iconType: string, Optional, default as None
Overrides the `leafletIconType` column of an input :ref:`Nodes` dataframe. If provided, all nodes will use this icon type. The valid `iconType` options depend on the choice of `iconPrefix`. See :ref:`Leaflet Style` for the collection of valid icon prefix/type combinations.
iconColor: string, Optional, default as None
Overrides the `leafletColor` column of an input :ref:`Nodes` dataframe. If provided, all icons will use this color when displayed on this Leaflet map. See :ref:`Leaflet Style` for the list of available color options.
iconText: string, Optional, default as None
Overrides the `leafletIconText` column of an input :ref:`Nodes` dataframe. If provided, this text will be displayed within the node on a Leaflet map. This text will only be shown if `leafletIconPrefix` is 'custom' and `leafletIconType` includes a font color and font size. A value of None will result in the node ID being displayed in the node. See :ref:`Leaflet style`.
arcs: :ref:`Arcs` or :ref:`Assignments`, Conditional, `nodes`, `arcs` and `boundingRegion` can not be None at the same time
An :ref:`Arcs` or :ref:`Assignments` dataframe describing vehicle routes. Each row of this dataframe will be shown as a line on the Leaflet map. See the documentation on :ref:`Arcs` and :ref:`Assignments` for more information.
arcWeight: int, Optional, default as None
Overrides the `leafletWeight` column of an input :ref:`Arcs` or :ref:`Assignments` dataframe. If provided, all arcs will be displayed with this line thickness (in pixels).
arcStyle: string, Optional, default as None
Overrides the `leafletStyle` column of an input :ref:`Arcs` or :ref:`Assignments` dataframe. If provided, all arcs will be displayed with this type. Valid options are 'solid', 'dotted', or 'dashed'. See :ref:`Leaflet Style` for more information.
arcOpacity: float in [0, 1], Optional, default as None
Overrides the `leafletOpacity` column of an input :ref:`Arcs` or :ref:`Assignments` dataframe. If provided, each arc will be displayed with this opacity. Valid values are in the range from 0 (invisible) to 1 (no transparency).
arcColor: string, Optional, default as None
Overrides the `leafletColor` column of an input :ref:`Arcs` or :ref:`Assignments` dataframe. If provided, all arcs will be displayed with this color. See :ref:`Leaflet Style` for a list of available colors.
arcCurveType: string, Optional, default as 'straight'
Choose the type of curve to be shown on leaflet map for :ref:`Arcs` dataframe (curves will not be applied to :ref:`Assignments` dataframes). The options are `Bezier`, `greatcircle`, and 'straight'. If `Bezier` is provided, the `arcCurvature` should not be None, leaflet will draw a Bezier curve between given nodes. If `greatcircle` is provided, the curve will go along with the surface of the Earth.
arcCurvature: float in (-90, 90), Conditional, default as 45
If choose `Bezier` as `arcCurveType`, then `arcCurvature` is required; otherwise this argument will not be used. The meaning of this argument is as following: link two nodes using straight line, the degrees between this straight line and the curve at two nodes is this argument, therefore it should be greater or equal to 0 and less than 90. A degree between -45 and 45 is recommended.
useArrows: boolean, Optional, default as None
Indicates whether arrows should be shown on all arcs on the Leaflet map.
arrowsPerArc: int, Optional, default as 1
Number of arrows display on each arc, should be integer greater than 0. Each arc will have the same number of arrows, regardless of arc length. If useArrows is False, this parameter will be ignored (i.e., no arrows will be drawn).
boundingRegion: list of lists, Conditional, `nodes`, `arcs` and `boundingRegion` can not be None at the same time
A sequence of lat/lon coordinates defining a boundary polygon. The format is [[lat, lon], [lat, lon], ..., [lat, lon]].
boundingWeight: int, Optional, default as 3
Specifies the weight (in pixels) of the line defining the `boundingRegion` (if provided) when displayed in Leaflet.
boundingStyle: string, Optional, default as 'dashed'
Specifies the line style of the `boundingRegion` (if provided). Valid options are 'solid', 'dotted', 'dashed'. See :ref:`Leaflet Style` for more information.
boundingOpacity: float in [0, 1], Optional, default as 0.6
Specifies the opacity of the `boundingRegion` (if provided) when displayed in Leaflet. Valid values are in the range from 0 (invisible) to 1 (no transparency).
boundingColor: string, Optional, default as 'brown'
Specifies the line color of the `boundingRegion` (if provided) when displayed in Leaflet. See :ref:`Leaflet Style` for a list of available colors.
Return
------
Folium object
A new/updated map that displays the nodes, arcs, and/or bounding region.
Examples
--------
First, import veroviz and check the latest version
>>> import veroviz as vrv
>>> vrv.checkVersion()
Now, generate some example nodes inside a bounding region
>>> bounding = [
... [42.98355351219673, -78.90518188476564],
... [43.04731443361136, -78.83857727050783],
... [43.02221961002041, -78.7108612060547],
... [42.92777124914475, -78.68957519531251],
... [42.866402688514626, -78.75343322753908],
... [42.874957707517865, -78.82415771484375],
... [42.90111863978987, -78.86878967285158],
... [42.92224052343343, -78.8921356201172]]
>>> exampleNodes = vrv.generateNodes(
... nodeType = 'customer',
... nodeDistrib = 'normalBB',
... nodeDistribArgs = {
... 'center' : [42.90, -78.80],
... 'stdDev' : 10000,
... 'boundingRegion' : bounding
... },
... numNodes = 3,
... leafletColor = 'orange')
The first example is using all default setting for generating a set of given nodes in Nodes dataframe.
>>> vrv.createLeaflet(nodes=exampleNodes)
Define some arcs based on the nodes we just generated:
>>> exampleArcs = vrv.createArcsFromNodeSeq(
... nodes = exampleNodes,
... nodeSeq = [1, 2, 3])
>>> exampleArcs
Display the nodes, arcs, and bounding region simultaneously:
>>> vrv.createLeaflet(
... nodes = exampleNodes,
... arcs = exampleArcs,
... boundingRegion = bounding)
The createLeaflet function provides options to override styles that were defined in the input nodes and/or arcs dataframes. Note: These overrides will not change the contents in the dataframes.
>>> nodesAndArcsMap = vrv.createLeaflet(
... nodes = exampleNodes,
... iconPrefix = 'fa',
... iconType = 'car',
... iconColor = 'blue',
... arcs = exampleArcs,
... arcStyle = 'dotted')
>>> nodesAndArcsMap
If you already have a folium map object, you can add more into it.
Here, we add a bounding region to the `nodesAndArcsMap` object defined above.
>>> nodesAndArcsMap = vrv.createLeaflet(
... mapObject = nodesAndArcsMap,
... boundingRegion = bounding)
>>> nodesAndArcsMap
A new collection of nodes is defined here:
>>> newNodes = vrv.generateNodes(
... nodeType = 'customer',
... nodeDistrib = 'uniformBB',
... nodeDistribArgs = {
... 'boundingRegion' : bounding
... },
... numNodes = 4,
... leafletColor = 'red')
>>> newNodes
We will add these nodes to our existing map,
but we're overriding these new nodes with a green color:
Notice that the addition of new entities will not change the style of previous entities that were already added into the map.
>>> newMapWithArcsAndMoreNodes = vrv.createLeaflet(
... mapObject = nodesAndArcsMap,
... nodes = newNodes,
... iconColor = 'green')
>>> newMapWithArcsAndMoreNodes
The following example includes all of the function arguments.
>>> vrv.createLeaflet(
... mapObject = None,
... mapFilename = 'example.html',
... mapBackground = 'CartoDB positron',
... mapBoundary = None,
... zoomStart = 10,
... nodes = exampleNodes,
... iconPrefix = 'fa',
... iconType = 'flag',
... iconColor = 'red',
... iconText = 'Here are some nodes',
... arcs = exampleArcs,
... arcWeight = 5,
... arcStyle = 'dashed',
... arcOpacity = 1,
... arcColor = 'green',
... useArrows = True,
... boundingRegion = bounding,
... boundingWeight = 1,
... boundingOpacity = 0.8,
... boundingStyle = 'dotted',
... boundingColor = 'black')
"""
# validation
[valFlag, errorMsg, warningMsg] = valCreateLeaflet(mapObject, mapFilename, mapBackground, mapBoundary, zoomStart, nodes, iconPrefix, iconType, iconColor, iconText, arcs, arcWeight, arcStyle, arcOpacity, arcColor, arcCurveType, arcCurvature, useArrows, arrowsPerArc, boundingRegion, boundingWeight, boundingOpacity, boundingStyle, boundingColor)
if (not valFlag):
print (errorMsg)
return
elif (config['VRV_SETTING_SHOWWARNINGMESSAGE'] and warningMsg != ""):
print (warningMsg)
# Replace backslash
mapFilename = replaceBackslashToSlash(mapFilename)
# If no mapObject exists, define a new mapObject
if (mapObject == None):
# Adjust the scope of the map to proper bounds
if (nodes is None and arcs is None and boundingRegion is None):
[midLat, midLon] = [0, 0]
else:
[[minLat, maxLon], [maxLat, minLon]] = privGetMapBoundary(nodes, arcs, boundingRegion)
midLat = (maxLat + minLat) / 2.0
midLon = (maxLon + minLon) / 2.0
mapObject = _createLeafletMap(mapBackground=mapBackground, center=[midLat,midLon], zoomStart=zoomStart)
# set the map boundary for mapObject
if (zoomStart is None):
if (mapBoundary is not None):
mapObject.fit_bounds(mapBoundary)
elif (mapBoundary is None):
if (nodes is not None or arcs is not None or boundingRegion is not None):
mapObject.fit_bounds(privGetMapBoundary(nodes, arcs, boundingRegion))
# Plot arcs
if (type(arcs) is pd.core.frame.DataFrame):
mapObject = _createLeafletArcs(mapObject, arcs, arcWeight, arcOpacity, arcStyle, arcColor, arcCurveType, arcCurvature, useArrows, config['VRV_DEFAULT_LEAFLET_ARROWSIZE'], arrowsPerArc)
# Plot bounding
if (type(boundingRegion) is list):
mapObject = _createLeafletBoundingRegion(mapObject, boundingRegion, boundingWeight, boundingOpacity, boundingStyle, boundingColor)
# Plot node markers
if (type(nodes) is pd.core.frame.DataFrame):
mapObject = _createLeafletNodes(mapObject, nodes, iconPrefix, iconType, iconColor, iconText)
if (mapFilename is not None):
mapDirectory = ""
strList = mapFilename.split("/")
for i in range(len(strList) - 1):
mapDirectory += strList[i] + "/"
if (mapDirectory != ""):
if (not os.path.exists(mapDirectory)):
os.makedirs(mapDirectory, exist_ok=True)
mapObject.save(mapFilename)
if (config['VRV_SETTING_SHOWOUTPUTMESSAGE']):
print("Message: Map page written to %s." % (mapFilename))
return mapObject
def _createLeafletMap(mapBackground=config['VRV_DEFAULT_LEAFLET_MAPTILES'], center=[0,0], zoomStart=None):
try:
mapBackground = mapBackground.lower()
except:
pass
# Define a new mapObject
mapObject = folium.Map(
location = center,
zoom_start = zoomStart if (zoomStart != None) else 3,
tiles = None)
# Add the chosen map background first:
if (mapBackground in foliumMaps):
folium.TileLayer(mapBackground).add_to(mapObject)
elif (mapBackground in customMaps):
folium.TileLayer(tiles=customMaps[mapBackground]['tiles'],
attr=customMaps[mapBackground]['attr']).add_to(mapObject)
'''
# Now, loop over our other map background options (excluding the chosen one):
for (mBG in foliumMaps):
if (mBG != mapBackground):
folium.TileLayer(mBG).add_to(mapObject)
for (mBG in customMaps):
if (mBG != mapBackground):
folium.TileLayer(tiles=customMaps[mBG]['tiles'],
attr=customMaps[mBG]['attr'],
name=mBG).add_to(mapObject)
'''
return mapObject
def _createLeafletNodes(mapObject=None, nodes=None, iconPrefix=None, iconType=None, iconColor=None, iconText=None):
"""
A sub-function to create leaflet nodes
Parameters
----------
mapObject: Folium object, Required
Add content to a folium map.
nodes: :ref:`Nodes`, Required
The Nodes dataframe to be generated in Leaflet
iconPrefix: string, Optional
The collection of Leaflet icons. Options are "glyphicon", "fa", or "custom". See :ref:`Leaflet Style`
iconType: string, Optional
The specific icon to be used for all generated nodes. The list of available options depends on the choice of the iconType. See :ref:`Leaflet Style`
iconColor: string, Optional
The icon color of the generated nodes when displayed in Leaflet. One of a collection of pre-specified colors. See :ref:`Leaflet Style`
iconText: string, Optional
Text that will be displayed within the node on a Leaflet map. This text will only be shown if `iconPrefix` is 'custom' and `iconType` includes a font color and font size. A value of None will result in the node ID being displayed in the node. See :ref:`Leaflet style`.
return
------
Folium object
A new/updated map that contains the nodes
"""
# Note: In nodes dataframe, we already checked 'leaflet-' columns, and those columns have default values, for sake of consistency in here I delete the 'failsafes'
for i in range(0, len(nodes)):
# If not overridden, use the info in nodes dataframe
if (iconColor == None):
newColor = nodes.iloc[i]['leafletColor']
else:
newColor = iconColor
if ((iconPrefix == None) or (iconType == None)):
newPrefix = nodes.iloc[i]['leafletIconPrefix']
newType = nodes.iloc[i]['leafletIconType']
else:
newPrefix = iconPrefix
newType = iconType
if (iconText == None):
newText = nodes.iloc[i]['leafletIconText']
else:
newText = iconText
if (newColor != None):
newColor = newColor.lower()
if (newPrefix != None):
newPrefix = newPrefix.lower()
if (newType != None):
newType = newType.lower()
_drawLeafletNode(mapObject, [nodes.iloc[i]['lat'], nodes.iloc[i]['lon']], nodes.iloc[i]['popupText'], newPrefix, newType, newColor, newText)
return mapObject
def _drawLeafletNode(mapObject, loc, popupText, iconPrefix, iconType, iconColor, iconText):
# Format popup text
if (popupText is not None):
popupText = str(popupText)
if (iconPrefix in ['fa', 'glyphicon']):
# Folium draw nodes
folium.Marker(
loc,
icon=folium.Icon(
color = iconColor.lower(),
prefix = iconPrefix.lower(),
icon = iconType.lower()),
popup=popupText
).add_to(mapObject)
else:
[radius, fontColor, fontSize] = splitLeafletCustomIconType(iconType)
# Add marker:
folium.CircleMarker(
loc,
radius = radius,
stroke = True,
weight = 1,
color = iconColor.lower(),
fill_color = iconColor.lower(),
fill_opacity = 0.9,
popup = popupText
).add_to(mapObject)
# Add text:
if ((iconText is not None) and (fontColor is not None)):
try:
fontColor = fontColor.lower()
except:
pass
iconSizeX = radius*2 # FIXME -- Not sure if this is good.
iconAnchorX = iconSizeX / 2
folium.map.Marker(loc, popup=popupText, icon=DivIcon(
icon_size = (iconSizeX, fontSize),
icon_anchor = (iconAnchorX, fontSize),
html = "<div style=\"font-size: %dpt; color: %s; text-align: center;\">%s</div>" % (fontSize, fontColor, iconText)
)).add_to(mapObject)
return
def _createLeafletArcs(mapObject=None, arcs=None, arcWeight=None, arcOpacity=None, arcStyle=None, arcColor=None, arcCurveType=None, arcCurvature=None, useArrows=None, arrowSize=6, arrowsPerArc=4):
"""
A sub-function to create leaflet arcs
Parameters
----------
mapObject: Folium object, Required
Add content to a folium map.
arcs: ref:`Arcs`/:ref:`Assignments`, Required
The Arc dataframe to be generated in Leaflet
arcWeight: string, Optional
The weight of generated route when displayed in Leaflet. See :ref:`Leaflet Style`
arcStyle: string, Optional, default as 'solid'
The line style of geneareted route, options are 'solid', 'dotted', 'dashed'. See :ref:`Leaflet Style`
arcOpacity: string, Optional
The opacity of generated route when displayed in Leaflet, range from 0 (invisible) to 1. See :ref:`Leaflet Style`
arcColor: string, Optional
The color of generated route when displayed in Leaflet. One of a collection of pre-specified colors. See :ref:`Leaflet Style`
arcCurveType: string, Optional
Options are 'bezier', 'greatcircle' or None.
arcCurvature: float in [-45,45], Optional
Only used if arcCurveType=='bezier'.
useArrows: boolean, Optional, default as None
Whether or not to add arrows to leaflet map.
arrowSize: int Optional, default as
Size of arrows
return
------
Folium object
A new/updated map that contains the arcs
"""
# In here "arcs" can be Arcs/Assignments, each path should have its own odID. Use lstPath as a list of Arcs/Assignments dataframe, each item in it is a path, with the same styles
lstPath = []
# For Arcs dataframe, each row is a path, i.e. each row should have different odID
if (not {'startTimeSec'}.issubset(arcs.columns)):
for i in range(0, len(arcs)):
if (arcCurveType == None):
newArcCurveType = arcs.iloc[i]['leafletCurveType'].lower()
else:
newArcCurveType = arcCurveType.lower()
if (arcCurvature == None):
newArcCurvature = arcs.iloc[i]['leafletCurvature']
else:
newArcCurvature = arcCurvature
newPath = pd.DataFrame(columns=['odID', 'startLat', 'startLon', 'endLat', 'endLon', 'leafletColor', 'leafletWeight', 'leafletStyle', 'leafletOpacity', 'useArrows'])
if (newArcCurveType == 'greatcircle'):
curvePoints = _getCurveGreatCircle([arcs.iloc[i]['startLat'], arcs.iloc[i]['startLon']], [arcs.iloc[i]['endLat'], arcs.iloc[i]['endLon']])
for j in range(1, len(curvePoints)):
newPath = newPath.append({
'odID' : arcs.iloc[i]['odID'],
'startLat' : curvePoints[j - 1][0],
'startLon' : curvePoints[j - 1][1],
'endLat' : curvePoints[j][0],
'endLon' : curvePoints[j][1],
'leafletColor' : arcs.iloc[i]['leafletColor'],
'leafletWeight' : arcs.iloc[i]['leafletWeight'],
'leafletStyle' : arcs.iloc[i]['leafletStyle'],
'leafletOpacity' : arcs.iloc[i]['leafletOpacity'],
'useArrows' : arcs.iloc[i]['useArrows'],
'popupText' : arcs.iloc[i]['popupText']
}, ignore_index=True)
elif (newArcCurveType == 'bezier'):
curvePoints = _getCurveBezier([arcs.iloc[i]['startLat'], arcs.iloc[i]['startLon']], [arcs.iloc[i]['endLat'], arcs.iloc[i]['endLon']], newArcCurvature)
for j in range(1, len(curvePoints)):
newPath = newPath.append({
'odID' : arcs.iloc[i]['odID'],
'startLat' : curvePoints[j - 1][0],
'startLon' : curvePoints[j - 1][1],
'endLat' : curvePoints[j][0],
'endLon' : curvePoints[j][1],
'leafletColor' : arcs.iloc[i]['leafletColor'],
'leafletWeight' : arcs.iloc[i]['leafletWeight'],
'leafletStyle' : arcs.iloc[i]['leafletStyle'],
'leafletOpacity' : arcs.iloc[i]['leafletOpacity'],
'useArrows' : arcs.iloc[i]['useArrows'],
'popupText' : arcs.iloc[i]['popupText']
}, ignore_index=True)
elif (newArcCurveType == 'straight'):
newPath = newPath.append({
'odID' : arcs.iloc[i]['odID'],
'startLat' : arcs.iloc[i]['startLat'],
'startLon' : arcs.iloc[i]['startLon'],
'endLat' : arcs.iloc[i]['endLat'],
'endLon' : arcs.iloc[i]['endLon'],
'leafletColor' : arcs.iloc[i]['leafletColor'],
'leafletWeight' : arcs.iloc[i]['leafletWeight'],
'leafletStyle' : arcs.iloc[i]['leafletStyle'],
'leafletOpacity' : arcs.iloc[i]['leafletOpacity'],
'useArrows' : arcs.iloc[i]['useArrows'],
'popupText' : arcs.iloc[i]['popupText']
}, ignore_index=True)
lstPath.append(newPath.copy())
# For Assignments dataframe, use deconstructAssignments to generate a list of assignments dataframe
if ({'objectID'}.issubset(arcs.columns) and {'startTimeSec'}.issubset(arcs.columns)):
lstOD = deconstructAssignments(assignments=arcs)
for i in range(len(lstOD)):
if (arcCurveType == None):
newArcCurveType = lstOD[i].iloc[0]['leafletCurveType'].lower()
else:
newArcCurveType = arcCurveType.lower()
if (arcCurvature == None):
newArcCurvature = lstOD[i].iloc[0]['leafletCurvature']
else:
newArcCurvature = arcCurvature
newOrigin = [lstOD[i].iloc[0]['startLat'], lstOD[i].iloc[0]['startLon']]
newDestine = [lstOD[i].iloc[len(lstOD[i]) - 1]['endLat'], lstOD[i].iloc[len(lstOD[i]) - 1]['endLon']]
newPath = pd.DataFrame(columns=['odID', 'startLat', 'startLon', 'endLat', 'endLon', 'leafletColor', 'leafletWeight', 'leafletStyle', 'leafletOpacity', 'useArrows'])
if (newArcCurveType == 'greatcircle'):
curvePoints = _getCurveGreatCircle(newOrigin, newDestine)
for j in range(1, len(curvePoints)):
newPath = newPath.append({
'odID' : i,
'startLat' : curvePoints[j - 1][0],
'startLon' : curvePoints[j - 1][1],
'endLat' : curvePoints[j][0],
'endLon' : curvePoints[j][1],
'leafletColor' : lstOD[i].iloc[0]['leafletColor'],
'leafletWeight' : lstOD[i].iloc[0]['leafletWeight'],
'leafletStyle' : lstOD[i].iloc[0]['leafletStyle'],
'leafletOpacity' : lstOD[i].iloc[0]['leafletOpacity'],
'useArrows' : lstOD[i].iloc[0]['useArrows'],
'popupText' : lstOD[i].iloc[0]['popupText']
}, ignore_index=True)
elif (newArcCurveType == 'bezier'):
curvePoints = _getCurveBezier(newOrigin, newDestine, newArcCurvature)
for j in range(1, len(curvePoints)):
newPath = newPath.append({
'odID' : i,
'startLat' : curvePoints[j - 1][0],
'startLon' : curvePoints[j - 1][1],
'endLat' : curvePoints[j][0],
'endLon' : curvePoints[j][1],
'leafletColor' : lstOD[i].iloc[0]['leafletColor'],
'leafletWeight' : lstOD[i].iloc[0]['leafletWeight'],
'leafletStyle' : lstOD[i].iloc[0]['leafletStyle'],
'leafletOpacity' : lstOD[i].iloc[0]['leafletOpacity'],
'useArrows' : lstOD[i].iloc[0]['useArrows'],
'popupText' : lstOD[i].iloc[0]['popupText']
}, ignore_index=True)
elif (newArcCurveType == 'straight'):
newPath = lstOD[i]
lstPath.append(newPath.copy())
# For each path, generate the arcs and arrows accordingly
for i in range(len(lstPath)):
lstPath[i] = lstPath[i].reset_index(drop=True)
arcPath = []
arcPath.append([lstPath[i]['startLat'][0], lstPath[i]['startLon'][0]])
for j in range(len(lstPath[i])):
arcPath.append([lstPath[i]['endLat'][j], lstPath[i]['endLon'][j]])
# FIXMELP -- Some of these values below aren't used anywhere that I can see.
# For example, curveType or curvature.
# If not overridden, use the info in arcs dataframe
if (arcColor == None):
newColor = lstPath[i]['leafletColor'][0]
else:
newColor = arcColor
if (arcWeight == None):
newWeight = lstPath[i]['leafletWeight'][0]
else:
newWeight = arcWeight
if (arcOpacity == None):
newOpacity = lstPath[i]['leafletOpacity'][0]
else:
newOpacity = arcOpacity
if (arcStyle == None):
newStyle = lstPath[i]['leafletStyle'][0]
else:
newStyle = arcStyle.lower()
if (arcCurveType == None):
newArcCurveType = lstPath[i]['leafletStyle'][0]
else:
newArcCurveType = arcCurveType.lower()
if (arcCurvature == None):
newArcCurvature = lstPath[i]['leafletStyle'][0]
else:
newArcCurvature = arcCurvature
# Interpret arc style
if (newStyle == 'dashed'):
dashArray = '30 10'
elif (newStyle == 'dotted'):
dashArray = '1 6'
else:
dashArray = None
try:
newColor = newColor.lower()
except:
pass
for j in range(1, len(arcPath)):
# Format popup text
if (lstPath[i]['popupText'][j-1] is not None):
popupText = str(lstPath[i]['popupText'][j-1])
else:
popupText = None
# Folium draw arcs
folium.PolyLine(
[arcPath[j-1], arcPath[j]],
color = newColor,
weight = newWeight,
opacity = newOpacity,
dash_array = dashArray,
popup = popupText
).add_to(mapObject)
# Check if we add arrows
arrowFlag = False
if (useArrows == True):
arrowFlag = True
elif (useArrows == None):
if ({'useArrows'}.issubset(lstPath[i].columns)):
if (lstPath[i].iloc[0]['useArrows'] == True):
arrowFlag = True
else:
arrowFlag = False
elif (useArrows == False):
arrowFlag = False
if (arrowFlag):
mapObject = _createLeafletArrowsPathOnGround(mapObject, arcPath, newColor, arrowSize, mode='equal_division_spacing', arrowsPerArc=arrowsPerArc, arrowDistanceInMeters=1000)
return mapObject
def _createLeafletBoundingRegion(mapObject=None, boundingRegion=None, boundingWeight=config['VRV_DEFAULT_LEAFLETBOUNDINGWEIGHT'], boundingOpacity=config['VRV_DEFAULT_LEAFLETBOUNDINGOPACITY'], boundingStyle=config['VRV_DEFAULT_LEAFLETBOUNDINGSTYLE'], boundingColor=config['VRV_DEFAULT_LEAFLETBOUNDINGCOLOR'], boundingIsFitEarthCurvature=False):
"""
A sub-function to create leaflet bounding region
Parameters
----------
mapObject: Folium object, Required
Add content to a folium map.
boundingRegion: list of lists, Required
A sequence of lat/lon coordinates defining the boundary of the objects.
boundingWeight: string, Optional
The weight of bounding region when displayed in Leaflet. See :ref:`Leaflet Style`
boundingStyle: string, Optional, default as 'solid'
The line style of bounding region, options are 'solid', 'dotted', 'dashed'. See :ref:`Leaflet Style`
boundingOpacity: string, Optional
The opacity of bounding region when displayed in Leaflet, range from 0 (invisible) to 1. See :ref:`Leaflet Style`
boundingColor: string, Optional
The color of bounding region when displayed in Leaflet. One of a collection of pre-specified colors. See :ref:`Leaflet Style`
return
------
Folium object
A new/updated map that contains the boundings
"""
# Make the bounding region a closed circle
boundings = boundingRegion[:]
if (boundings[0] != boundings[len(boundings) - 1]):
boundings.append(boundings[0])
# Interpret bounding style
try:
boundingStyle = boundingStyle.lower()
except:
pass
if (boundingStyle == 'dashed'):
dashArray = '30 10'
elif (boundingStyle == 'dotted'):
dashArray = '1 6'
else:
dashArray = None
try:
boundingColor = boundingColor.lower()
except:
pass
if (boundingIsFitEarthCurvature):
tmpBoundings = boundings.copy()
boundings = []
for i in range(1, len(tmpBoundings)):
boundings.extend(_getCurveGreatCircle(tmpBoundings[i - 1], tmpBoundings[i]))
# Draw bounding region in folium (for now is not filled)
folium.PolyLine(
boundings,
color = boundingColor,
weight = boundingWeight,
opacity = boundingOpacity,
dash_array = dashArray
).add_to(mapObject)
return mapObject
def _createLeafletArrowsPathOnGround(mapObject=None, path=None, color=None, size=7, mode='equal_division_spacing', arrowsPerArc=1, arrowDistanceInMeters=None):
"""
A sub-function to generate arrows for one path that curved to the Earth
Parameters
----------
mapObject: Folium object, Required
Add content to a folium map.
lats: list, Required
A list of latitudes
lons: list, Required
A list of longitudes
color: string, Required
The color for arrow, we are not providing any default value here because it has to be consistent with the color of arcs/assignments
size: int, Optional, default as 7
The size of the arrow
mode: string, Optional, default as 'equal_division_spacing'
For 'equal_division_spacing', divide the entire path equally in to several parts and add arrows accordingly. For 'equal_distance_spacing', add arrow for every given distance.
arrowsPerArc: int, Optional, default as 1
If we are using 'equal_division_spacing', it defines the number of arrows in the path, otherwise it will be ignored
arrowDistanceInMeters: float, Optional
If we are using 'equal_distance_spacing', it defines the distance between arrows
Return
------
Folium object
A map that contains arrows above the arcs
"""
# Calculate totalDistance
totalDistance = geoDistancePath2D(path)
# Use different modes to decide how many arrows to be generated and where are them
lstMilages = []
if (mode == 'equal_division_spacing'):
for i in range(1, arrowsPerArc + 1):
lstMilages.append(totalDistance * (i / (arrowsPerArc + 1)))
elif (mode == 'equal_distance_spacing'):
accuDistance = 0
while accuDistance < totalDistance:
accuDistance += arrowDistanceInMeters
lstMilages.append(accuDistance)
remainingDistance = totalDistance - accuDistance
for i in range(len(lstMilages)):
lstMilages[i] = lstMilages[i] + remainingDistance/2
else:
return
try:
color = color.lower()
except:
pass
# Draw arrows
for i in range(len(lstMilages)):
arrowLoc = geoMileageInPath2D(path, lstMilages[i])
folium.RegularPolygonMarker(
location = arrowLoc['loc'],
number_of_sides = 3,
rotation = arrowLoc['bearingInDegree']-90,
radius = size,
color = color,
fill_color = color,
fill_opacity = 1.0
).add_to(mapObject)
return mapObject
def _createLeafletArrowsPathProjected(mapObject=None, path=None, color=None, size=7, mode='equal_division_spacing', arrowsPerArc=1, arrowDistanceInMeters=None):
"""
A sub-function to generate arrows for one path that curved to the Earth
Parameters
----------
mapObject: Folium object, Required
Add content to a folium map.
lats: list, Required
A list of latitudes
lons: list, Required
A list of longitudes
color: string, Required
The color for arrow, we are not providing any default value here because it has to be consistent with the color of arcs/assignments
size: int, Optional, default as 7
The size of the arrow
mode: string, Optional, default as 'equal_division_spacing'
For 'equal_division_spacing', divide the entire path equally in to several parts and add arrows accordingly. For 'equal_distance_spacing', add arrow for every given distance.
arrowsPerArc: int, Optional, default as 1
If we are using 'equal_division_spacing', it defines the number of arrows in the path, otherwise it will be ignored
arrowDistanceInMeters: float, Optional
If we are using 'equal_distance_spacing', it defines the distance between arrows
Return
------
Folium object
A map that contains arrows above the arcs
"""
# Calculate totalDistance
totalDistance = geoDistancePath2D(path)
# Use different modes to decide how many arrows to be generated and where are them
lstMilages = []
if (mode == 'equal_division_spacing'):
for i in range(1, arrowsPerArc + 1):
lstMilages.append(totalDistance * (i / (arrowsPerArc + 1)))
elif (mode == 'equal_distance_spacing'):
accuDistance = 0
while accuDistance < totalDistance:
accuDistance += arrowDistanceInMeters
lstMilages.append(accuDistance)
remainingDistance = totalDistance - accuDistance
for i in range(len(lstMilages)):
lstMilages[i] = lstMilages[i] + remainingDistance/2
else:
return
try:
color = color.lower()
except:
pass
# Draw arrows
for i in range(len(lstMilages)):
arrowLoc = geoMileageInPath2D(path, lstMilages[i])
folium.RegularPolygonMarker(
location = arrowLoc['loc'],
number_of_sides = 3,
rotation = arrowLoc['bearingInDegree']-90,
radius = size,
color = color,
fill_color = color,
fill_opacity = 1.0
).add_to(mapObject)
return mapObject
def _getCurveBezier(startLoc, endLoc, curvature=45, numShapepoint=50):
midLoc = [(startLoc[0] + endLoc[0]) / 2 + (startLoc[1] + endLoc[1]) / 2]
distanceAwayFromStartLoc = (geoDistance2D(startLoc, endLoc)) / math.cos(math.radians(curvature)) / 2
headingFromStartLocToRefLoc = geoGetHeading(startLoc, endLoc) - curvature
refLoc = geoPointInDistance2D(startLoc, headingFromStartLocToRefLoc, distanceAwayFromStartLoc)
headingFromRefLocToEndLoc = geoGetHeading(refLoc, endLoc)
distStartLocToRefLoc = geoDistance2D(startLoc, refLoc)
distRefLocToEndLoc = geoDistance2D(refLoc, endLoc) # Should be the same as distStartLocToRefLoc, in no curvature plane
path = []
for i in range(numShapepoint + 1):
refStart = geoPointInDistance2D(startLoc, headingFromStartLocToRefLoc, i * distStartLocToRefLoc / float(numShapepoint))
refEnd = geoPointInDistance2D(refLoc, headingFromRefLocToEndLoc, i * distRefLocToEndLoc / float(numShapepoint))
refHeading = geoGetHeading(refStart, refEnd)
refDist = geoDistance2D(refStart, refEnd)
newLoc = geoPointInDistance2D(refStart, refHeading, i * refDist / float(numShapepoint))
path.append(newLoc)
return path
def _getCurveGreatCircle(startLoc, endLoc, numShapepoint=50):
odPath = [startLoc, endLoc]
direction = geoGetHeading(startLoc, endLoc)
path = []
totalDist = geoDistance2D(startLoc, endLoc)
accDist = 0
while (accDist < totalDist):
path.append(geoPointInDistance2D(startLoc, direction, accDist))
accDist = accDist + totalDist / float(numShapepoint)
path.append(endLoc)
return path
[docs]def addLeafletCircle(mapObject=None, mapFilename=None, mapBackground=config['VRV_DEFAULT_LEAFLET_MAPTILES'], mapBoundary=None, zoomStart=None, center=None, radius=None, text=None, fontSize=config['VRV_DEFAULT_LEAFLET_FONTSIZE'], fontColor=config['VRV_DEFAULT_LEAFLET_FONTCOLOR'], popupText=None, lineWeight=3, lineColor=None, lineOpacity=0.8, lineStyle='solid', fillColor=config['VRV_DEFAULT_LEAFLET_OBJECT_COLOR_LINE'], fillOpacity=0.3):
"""
Add a circle, with a radius specified in [meters], to a Leaflet map.
Note
----
This function differs from addLeafletMarker, in which the circle's radius is specified in [pixels].
Parameters
----------
mapObject: Folium object, Optional, default None
A Folium map object. If provided, the circle will be added to an existing map. Otherwise, a new map will be created.
mapFilename: string, Optional, default as None
This is the name of the map file that will be created (e.g., "../output/map.html" or "map.html"). The filename should have a `.html` extension. If `mapFilename` is not provided, no map file will be generated. The returned map object can be viewed within a Jupyter notebook.
mapBackground: string, Optional, default as 'CartoDB positron'
Sets the background tiles of the map. See :ref:`Leaflet Style` for the list of options.
mapBoundary: list of lists, Optional, default as None
Allows customization of the zoom level. If a map boundary is provided, the zoom level will correspond to the rectangle defined by the two map boundary points. This feature is useful if you want to create multiple comparison maps, each with the same zoom level and centering. Must be in the form [[south lat, west lon], [north lat, east lon]].
zoomStart: int, Optional, default as None
Specifies the default zoom level. 1 --> global view; 18 --> max zoom. Note that some map tiles have maximum zoom levels less than 18. The `zoomStart` will be overridden by a `mapBoundary` (if one is provided).
center: list, Required, default None
Specifies the center point of the circle. Must be a list of the form `[lat, lon]` or `[lat, lon, alt]`. If provided, the altitude component will be ignored (as all locations on Leaflet maps are assumed to be at ground level).
radius: float, Required, default None
The radius of the circle, in units of [meters].
text: string, Optional, default None
Specifies the text to be displayed on the map, centered as the `center` location.
fontSize: float, Optional, default 24
The size of the font, in units of [points]. The default is 24-point font.
fontColor: string, Optional, default 'orange'
The color of the text string. `fontColor` may be one of Leaflet's pre-specified colors (see :ref:`Leaflet style`), or it may be a hex value, such as `#ff0000` (see https://www.w3schools.com/colors/colors_picker.asp).
popupText: string, Optional, default as None
The circle will include this text as a popup label (you will need to click on the circle in the map to see this label).
lineWeight: int, Optional, default 3
The width of the circle's outline, in units of [pixels]. This value is ignored if `lineColor = None`.
lineColor: string, Optional, default None
The color of the circle's outline. `lineColor` may be one of Leaflet's pre-specified colors (see :ref:`Leaflet style`), or it may be a hex value, such as `#ff0000` (see https://www.w3schools.com/colors/colors_picker.asp). No line will be drawn if `lineColor = None`.
lineOpacity: float in [0, 1], Optional, default 0.8
Specifies the opacity of the circle's outline. Valid values are in the range from 0 (invisible) to 1 (no transparency).
lineStyle: string, Optional, default 'solid'
The style of the circle's outline. See :ref:`Leaflet Style` for a list of valid options.
fillColor: string, Optional, default 'red'
The color of the interior of the circle. `fillColor` may be one of Leaflet's pre-specified colors (see :ref:`Leaflet style`), or it may be a hex value, such as `#ff0000` (see https://www.w3schools.com/colors/colors_picker.asp). The circle will not be filled if `fillColor = None`.
fillOpacity: float in [0, 1], Optional, default 0.3
Specifies the opacity of the circle's interior. Valid values are in the range from 0 (invisible) to 1 (no transparency).
Return
------
Folium object
A Folium map object containing a circle (and pre-existing items previously specified in mapObject).
Example
-------
>>> # Draw a circle of radius 10 meters, centered on the Univ. at Buffalo campus.
>>> # Save this as "a_circle.html".
>>> import veroviz as vrv
>>> myMap = vrv.addLeafletCircle(
... zoomStart=18,
... center=[43.00154, -78.7871],
... radius=100,
... mapFilename="a_circle.html")
>>> myMap
>>> # Draw a circle of radius 2000 meters, centered on the Univ. at Buffalo campus.
>>> # This example includes all of the available function arguments.
>>> import veroviz as vrv
>>> myMap = vrv.addLeafletCircle(
... mapObject = None,
... mapFilename = None,
... mapBackground = 'OpenStreetMap',
... mapBoundary = None,
... zoomStart = 13,
... center = [43.00154, -78.7871],
... radius = 2000,
... text = 'UB',
... fontSize = 24,
... fontColor = 'black',
... popupText = 'Univ. at Buffalo',
... lineWeight = 6,
... lineColor = '#ff66ff',
... lineOpacity = 0.7,
... lineStyle = 'dotted',
... fillColor = 'green',
... fillOpacity = 0.4)
>>> myMap
"""
# validation
[valFlag, errorMsg, warningMsg] = valAddLeafletCircle(mapObject, mapFilename, mapBackground, mapBoundary, zoomStart, center, radius, text, fontSize, fontColor, lineWeight, lineColor, lineOpacity, lineStyle, fillColor, fillOpacity)
if (not valFlag):
print (errorMsg)
return
elif (config['VRV_SETTING_SHOWWARNINGMESSAGE'] and warningMsg != ""):
print (warningMsg)
try:
mapBackground = mapBackground.lower()
except:
pass
center = [center[0], center[1]]
# If no mapObject exists, define a new mapObject
if (mapObject == None):
mapObject = _createLeafletMap(mapBackground=mapBackground, center=center, zoomStart=zoomStart)
# set the map boundary for mapObject
if (zoomStart is None):
if (mapBoundary is not None):
mapObject.fit_bounds(mapBoundary)
try:
lineStyle = lineStyle.lower()
except:
pass
# Interpret line style
if (lineStyle == 'dashed'):
dashArray = '30 10'
elif (lineStyle == 'dotted'):
dashArray = '1 6'
else:
dashArray = None
try:
lineColor = lineColor.lower()
except:
pass
try:
fillColor = fillColor.lower()
except:
pass
# Format popup text
if (popupText is not None):
popupText = str(popupText)
# Draw circle:
folium.Circle(center,
radius = radius,
stroke = True,
weight = lineWeight,
color = lineColor,
opacity = lineOpacity,
dash_array = dashArray,
fill_color = fillColor,
fill_opacity = fillOpacity,
popup = popupText
).add_to(mapObject)
# Add text:
if (text is not None):
try:
fontColor = fontColor.lower()
except:
pass
iconSizeX = 900 # FIXME -- Not sure if this is good.
iconAnchorX = iconSizeX / 2
folium.map.Marker(center, popup=popupText, icon=DivIcon(
icon_size = (iconSizeX, fontSize),
icon_anchor = (iconAnchorX, fontSize),
html = "<div style=\"font-size: %dpt; color: %s; text-align: center;\">%s</div>" % (fontSize, fontColor, text)
)).add_to(mapObject)
if (mapFilename is not None):
mapObject.save(mapFilename)
if (config['VRV_SETTING_SHOWOUTPUTMESSAGE']):
print("Message: Map page written to %s." % (mapFilename))
return mapObject
[docs]def addLeafletMarker(mapObject=None, mapFilename=None, mapBackground=config['VRV_DEFAULT_LEAFLET_MAPTILES'], mapBoundary=None, zoomStart=None, center=None, radius=5, text=None, fontSize=config['VRV_DEFAULT_LEAFLET_FONTSIZE'], fontColor=config['VRV_DEFAULT_LEAFLET_FONTCOLOR'], popupText=None, lineWeight=3, lineColor=None, lineOpacity=0.8, lineStyle='solid', fillColor=config['VRV_DEFAULT_LEAFLET_OBJECT_COLOR_LINE'], fillOpacity=0.3):
"""
Add a circle-shaped marker, with a radius specified in [pixels], to a Leaflet map.
Note
----
This function differs from addLeafletCircle, in which the circle's radius is specified in [meters].
Parameters
----------
mapObject: Folium object, Optional, default None
A Folium map object. If provided, the marker will be added to an existing map. Otherwise, a new map will be created.
mapFilename: string, Optional, default None
If provided, the map will be saved to this file, which should have a `.html` extension. `mapFilename` can contain a filepath. If `mapFilename` is not provided, no file will be generated. The returned mapObject can be viewed within a Jupyter notebook.
mapBackground: string, Optional, default 'CartoDB positron'
The tiles of the map, default to be 'CartoDB positron', for options, see :ref:`Leaflet Style`, also see folium documentation (https://python-visualization.github.io/folium/modules.html) for more options
mapBoundary: list [LIST OF LISTS?], Optional, default None
If provided, the mapBoundary coordinates are used to determine a zoom level such that these coordinates are contained within view when the map is opened. This feature is useful if you want to create multiple comparison maps, each with the same zoom level and centering. `mapBoundary` must be in the form [[south lat, west lon], [north lat, east lon]].
zoomStart: int, Optional, default as None
Specifies the default zoom level. 1 --> global view; 18 --> max zoom. Note that some map tiles have maximum zoom levels less than 18. The `zoomStart` will be overridden by a `mapBoundary` (if one is provided).
center: list, Required, default None
Specifies the center point of the circle marker. Must be a list of the form `[lat, lon]` or `[lat, lon, alt]`. If provided, the altitude component will be ignored (as all locations on Leaflet maps are assumed to be at ground level).
radius: float, Required, default None
The radius of the circle marker, in units of [pixels].
text: string, Optional, default None
Specifies the text to be displayed on the map, centered as the `center` location.
fontSize: float, Optional, default 24
The size of the font, in units of [points]. The default is 24-point font.
fontColor: string, Optional, default 'orange'
The color of the text string. `fontColor` may be one of Leaflet's pre-specified colors (see :ref:`Leaflet style`), or it may be a hex value, such as `#ff0000` (see https://www.w3schools.com/colors/colors_picker.asp).
popupText: string, Optional, default as None
The marker will include this text as a popup label (you will need to click on the marker in the map to see this label).
lineWeight: int, Optional, default 3
The width of the circle marker's outline, in units of [pixels]. This value is ignored if `line = False`.
lineColor: string, Optional, default 'red'
The color of the circle marker's outline. `lineColor` may be one of Leaflet's pre-specified colors (see :ref:`Leaflet style`), or it may be a hex value, such as `#ff0000` (see https://www.w3schools.com/colors/colors_picker.asp). The line color is ignored if `line = False`.
lineOpacity: float in [0, 1], Optional, default 0.8
The opacity of the circle marker's outline, where 0 is invisible and 1 represents no transparency. See :ref:`Leaflet Style`
lineStyle: string, Optional, default 'solid'
The style of the circle marker's outline. See :ref:`Leaflet Style` for a list of valid options.
fillColor: string, Optional, default None
The color of the interior of the circle marker. `fillColor` may be one of Leaflet's pre-specified colors (see :ref:`Leaflet style`), or it may be a hex value, such as `#ff0000` (see https://www.w3schools.com/colors/colors_picker.asp). The fill color is ignored if `fill = False`.
fillOpacity: float in [0, 1], Optional, default 0.3
The opacity of the circle marker's interior, where 0 is invisible and 1 represents no transparency. See :ref:`Leaflet Style`
Return
------
Folium object
A Folium map object containing a circle marker (and pre-existing items previously specified in mapObject).
Example
-------
>>> # Draw a circle of radius 10 pixels, centered on the Univ. at Buffalo campus.
>>> # Save this as "a_marker.html".
>>> import veroviz as vrv
>>> myMap = vrv.addLeafletMarker(
... center=[43.00154, -78.7871],
... radius=10,
... mapFilename="a_marker.html")
>>> myMap
>>> # Draw a circle of radius 30 pixels, centered on the Univ. at Buffalo campus.
>>> # This example includes all of the available function arguments.
>>> import veroviz as vrv
>>> myMap = vrv.addLeafletMarker(
... mapObject = None,
... mapFilename = None,
... mapBackground = 'CartoDB positron',
... mapBoundary = None,
... zoomStart = 11,
... center = [43.00154, -78.7871],
... radius = 30,
... text = 'UB',
... fontSize = 24,
... fontColor = 'black',
... popupText = 'Univ. at Buffalo',
... lineWeight = 3,
... lineColor = 'orange',
... lineOpacity = 0.6,
... lineStyle = 'dashed',
... fillColor = 'blue',
... fillOpacity = 0.3)
>>> myMap
"""
# validation
[valFlag, errorMsg, warningMsg] = valAddLeafletMarker(mapObject, mapFilename, mapBackground, mapBoundary, zoomStart, center, radius, text, fontSize, fontColor, lineWeight, lineColor, lineOpacity, lineStyle, fillColor, fillOpacity)
if (not valFlag):
print (errorMsg)
return
elif (config['VRV_SETTING_SHOWWARNINGMESSAGE'] and warningMsg != ""):
print (warningMsg)
try:
mapBackground = mapBackground.lower()
except:
pass
center = [center[0], center[1]]
# If no mapObject exists, define a new mapObject
if (mapObject == None):
mapObject = _createLeafletMap(mapBackground=mapBackground, center=center, zoomStart=zoomStart)
# set the map boundary for mapObject
if (zoomStart is None):
if (mapBoundary is not None):
mapObject.fit_bounds(mapBoundary)
try:
lineStyle = lineStyle.lower()
except:
pass
# Interpret line style
if (lineStyle == 'dashed'):
dashArray = '30 10'
elif (lineStyle == 'dotted'):
dashArray = '1 6'
else:
dashArray = None
try:
lineColor = lineColor.lower()
except:
pass
try:
fillColor = fillColor.lower()
except:
pass
# Format popup text
if (popupText is not None):
popupText = str(popupText)
# Add marker:
folium.CircleMarker(center,
radius = radius,
stroke = True,
weight = lineWeight,
color = lineColor,
opacity = lineOpacity,
dash_array = dashArray,
fill_color = fillColor,
fill_opacity = fillOpacity,
popup = popupText
).add_to(mapObject)
# Add text:
if (text is not None):
try:
fontColor = fontColor.lower()
except:
pass
iconSizeX = radius*2 # FIXME -- Not sure if this is good.
iconAnchorX = iconSizeX / 2
folium.map.Marker(center, popup=popupText, icon=DivIcon(
icon_size = (iconSizeX, fontSize),
icon_anchor = (iconAnchorX, fontSize),
html = '<div style="font-size: %dpt; color: %s; text-align: center;">%s</div>' % (fontSize, fontColor, text)
)).add_to(mapObject)
if (mapFilename is not None):
mapObject.save(mapFilename)
if (config['VRV_SETTING_SHOWOUTPUTMESSAGE']):
print("Message: Map page written to %s." % (mapFilename))
return mapObject
[docs]def addLeafletPolygon(mapObject=None, mapFilename=None, mapBackground=config['VRV_DEFAULT_LEAFLET_MAPTILES'], mapBoundary=None, zoomStart=None, points=None, popupText=None, lineWeight=3, lineColor=config['VRV_DEFAULT_LEAFLET_OBJECT_COLOR_LINE'], lineOpacity=0.8, lineStyle='solid', fillColor=None, fillOpacity=0.3):
"""
Add a polygon, as defined by an ordered collection of lat/lon coordinates, to a Leaflet map.
Note
----
There is also a "polyline" function, which does not assume a closed shape.
Parameters
----------
mapObject: Folium object, Optional, default None
A Folium map object. If provided, the polygon will be added to an existing map. Otherwise, a new map will be created.
mapFilename: string, Optional, default as None
This is the name of the map file that will be created (e.g., "../output/map.html" or "map.html"). The filename should have a `.html` extension. If `mapFilename` is not provided, no map file will be generated. The returned map object can be viewed within a Jupyter notebook.
mapBackground: string, Optional, default as 'CartoDB positron'
Sets the background tiles of the map. See :ref:`Leaflet Style` for the list of options.
mapBoundary: list of lists, Optional, default as None
Allows customization of the zoom level. If a map boundary is provided, the zoom level will correspond to the rectangle defined by the two map boundary points. This feature is useful if you want to create multiple comparison maps, each with the same zoom level and centering. Must be in the form [[south lat, west lon], [north lat, east lon]].
zoomStart: int, Optional, default as None
Specifies the default zoom level. 1 --> global view; 18 --> max zoom. Note that some map tiles have maximum zoom levels less than 18. The `zoomStart` will be overridden by a `mapBoundary` (if one is provided).
points: list of lists, Required, default None
Specifies the ordered collection of lat/lon coordinates comprising the polygon. This must be a list of lists, of the form `[[lat1, lon1], [lat2, lon2], ..., [latn, lonn]]` or `[[lat1, lon1, alt1], [lat2, lon2, alt2], ..., [latn, lonn, altn]]`. If an altitude is provided with each coordinate, this component will be ignored (as all Leaflet maps assume that objects are at ground level). It is not necessary for `[lat1, lon1]` and `[latn, lonn]` to be the same point. In other words, the polygon will automatically connect the first and last locations specified in the `points` list.
popupText: string, Optional, default as None
The polygon will include this text as a popup label (you will need to click on the polygon in the map to see this label).
lineWeight: int, Optional, default 3
The width of the polygon's outline, in units of [pixels]. This value is ignored if `lineColor = None`.
lineColor: string, Optional, default 'red'
The color of the polygon's outline. `lineColor` may be one of Leaflet's pre-specified colors (see :ref:`Leaflet style`), or it may be a hex value, such as `#ff0000` (see https://www.w3schools.com/colors/colors_picker.asp). No line will be drawn if `lineColor = None`.
lineOpacity: float in [0, 1], Optional, default 0.8
Specifies the opacity of the polygon's outline. Valid values are in the range from 0 (invisible) to 1 (no transparency).
lineStyle: string, Optional, default 'solid'
The style of the polygon's outline. See :ref:`Leaflet Style` for a list of valid options.
fillColor: string, Optional, default None
The color of the interior of the polygon. `fillColor` may be one of Leaflet's pre-specified colors (see :ref:`Leaflet style`), or it may be a hex value, such as `#ff0000` (see https://www.w3schools.com/colors/colors_picker.asp). The polygon will not be filled if `fillColor = None`.
fillOpacity: float in [0, 1], Optional, default 0.3
Specifies the opacity of the polygon's interior. Valid values are in the range from 0 (invisible) to 1 (no transparency).
Return
------
Folium object
A Folium map object containing a polygon (and pre-existing items previously specified in mapObject).
Example
-------
>>> # Draw a filled polygon around the Univ. at Buffalo campus.
>>> # Save this as "a_polygon.html".
>>> import veroviz as vrv
>>> campusPoints = [[43.0121, -78.7858],
... [43.0024, -78.7977],
... [42.9967, -78.7921],
... [42.9988, -78.7790]]
>>> myMap = vrv.addLeafletPolygon(
... points=campusPoints,
... mapFilename="a_polygon.html")
>>> myMap
>>> # Draw a filled polygon around the Univ. at Buffalo campus.
>>> # This example includes all of the available function arguments.
>>> import veroviz as vrv
>>> campusPoints = [[43.0121, -78.7858],
... [43.0024, -78.7977],
... [42.9967, -78.7921],
... [42.9988, -78.7790]]
>>> myMap = vrv.addLeafletPolygon(
... mapObject = None,
... mapFilename = None,
... mapBackground = 'OpenStreetMap',
... mapBoundary = vrv.getMapBoundary(locs=campusPoints),
... zoomStart = 15,
... points = campusPoints,
... popupText = 'Univ. at Buffalo',
... lineWeight = 7,
... lineColor = '#ff00ff',
... lineOpacity = 0.9,
... lineStyle = 'solid',
... fillColor = '#ff66ff',
... fillOpacity = 0.3)
>>> myMap
"""
# validation
[valFlag, errorMsg, warningMsg] = valAddLeafletPolygon(mapObject, mapFilename, mapBackground, mapBoundary, zoomStart, points, lineWeight, lineColor, lineOpacity, lineStyle, fillColor, fillOpacity)
if (not valFlag):
print (errorMsg)
return
elif (config['VRV_SETTING_SHOWWARNINGMESSAGE'] and warningMsg != ""):
print (warningMsg)
# Do we have a rectangle?
if (len(points) == 2):
if ( (len(points[0]) == 2) & (len(points[1]) == 2)):
points = [points[0], [points[0][0], points[1][1]], points[1], [points[1][0], points[0][1]]]
if (config['VRV_SETTING_SHOWWARNINGMESSAGE']):
print("NOTE: Only two pairs of coordinates were provided in 'points'. This is being interpreted as a rectangle.")
try:
mapBackground = mapBackground.lower()
except:
pass
# If no mapObject exists, define a new mapObject
if (mapObject == None):
# Adjust the scope of the map to proper bounds
[[minLat, maxLon], [maxLat, minLon]] = privGetMapBoundary(None, None, points)
midLat = (maxLat + minLat) / 2.0
midLon = (maxLon + minLon) / 2.0
mapObject = _createLeafletMap(mapBackground=mapBackground, center=[midLat,midLon], zoomStart=zoomStart)
# set the map boundary for mapObject
if (zoomStart is None):
if (mapBoundary is not None):
mapObject.fit_bounds(mapBoundary)
elif (mapBoundary is None):
mapObject.fit_bounds(privGetMapBoundary(None, None, points))
try:
lineStyle = lineStyle.lower()
except:
pass
# Interpret line style
if (lineStyle == 'dashed'):
dashArray = '30 10'
elif (lineStyle == 'dotted'):
dashArray = '1 6'
else:
dashArray = None
try:
lineColor = lineColor.lower()
except:
pass
try:
fillColor = fillColor.lower()
except:
pass
points2D = []
for i in range(len(points)):
points2D.append([points[i][0], points[i][1]])
# Format popup text
if (popupText is not None):
popupText = str(popupText)
folium.Polygon(locations = points2D,
stroke = True,
weight = lineWeight,
color = lineColor,
opacity = lineOpacity,
dash_array = dashArray,
fill_color = fillColor,
fill_opacity = fillOpacity,
popup = popupText
).add_to(mapObject)
if (mapFilename is not None):
mapObject.save(mapFilename)
if (config['VRV_SETTING_SHOWOUTPUTMESSAGE']):
print("Message: Map page written to %s." % (mapFilename))
return mapObject
[docs]def addLeafletPolyline(mapObject=None, mapFilename=None, mapBackground=config['VRV_DEFAULT_LEAFLET_MAPTILES'], mapBoundary=None, zoomStart=None, points=None, popupText=None, lineWeight=3, lineColor=config['VRV_DEFAULT_LEAFLET_OBJECT_COLOR_LINE'], lineOpacity=0.8, lineStyle='solid', lineCurveType='straight', lineCurvature=45, useArrows=False, arrowsPerArc=1):
"""
Add a polyline, as described by an ordered collection of lat/lon coordinates, to a Leaflet map.
Note
----
The polyline is an "open" shape, in the sense that there's nothing connecting the first and last locations. By contrast, the "polygon" shape will automatically connect the first and last locations.
Parameters
----------
mapObject: Folium object, Optional, default None
A Folium map object. If provided, the polyline will be added to an existing map. Otherwise, a new map will be created.
mapFilename: string, Optional, default as None
This is the name of the map file that will be created (e.g., "../output/map.html" or "map.html"). The filename should have a `.html` extension. If `mapFilename` is not provided, no map file will be generated. The returned map object can be viewed within a Jupyter notebook.
mapBackground: string, Optional, default as 'CartoDB positron'
Sets the background tiles of the map. See :ref:`Leaflet Style` for the list of options.
mapBoundary: list of lists, Optional, default as None
Allows customization of the zoom level. If a map boundary is provided, the zoom level will correspond to the rectangle defined by the two map boundary points. This feature is useful if you want to create multiple comparison maps, each with the same zoom level and centering. Must be in the form [[south lat, west lon], [north lat, east lon]].
zoomStart: int, Optional, default as None
Specifies the default zoom level. 1 --> global view; 18 --> max zoom. Note that some map tiles have maximum zoom levels less than 18. The `zoomStart` will be overridden by a `mapBoundary` (if one is provided).
points: list of lists, Required, default None
Specifies the ordered collection of lat/lon coordinates comprising the polyline. This must be a list of lists, of the form `[[lat1, lon1], [lat2, lon2], ..., [latn, lonn]]` or `[[lat1, lon1, alt1], [lat2, lon2, alt2], ..., [latn, lonn, altn]]`. If an altitude is provided with each coordinate, this component will be ignored (as all Leaflet maps assume that objects are at ground level). Note that the polyline will not automatically connect the first and last locations specified in the `points` list. (By contrast the "polygon" function does connect those locatons.)
popupText: string, Optional, default as None
The polyline will include this text as a popup label (you will need to click on the polyline in the map to see this label).
lineWeight: int, Optional, default 3
The width of the polyline's outline, in units of [pixels]. This value is ignored if `lineColor = None`.
lineColor: string, Optional, default 'red'
The color of the polyline's outline. `lineColor` may be one of Leaflet's pre-specified colors (see :ref:`Leaflet style`), or it may be a hex value, such as `#ff0000` (see https://www.w3schools.com/colors/colors_picker.asp). No line will be drawn if `lineColor = None`.
lineOpacity: float in [0, 1], Optional, default 0.8
Specifies the opacity of the polyline. Valid values are in the range from 0 (invisible) to 1 (no transparency).
lineStyle: string, Optional, default 'solid'
The style of the polyine. See :ref:`Leaflet Style` for a list of valid options.
lineCurveType: string, Optional, default as 'straight'
The type of curve to be shown on leaflet map for :ref:`Arcs` dataframes (curves will not be applied to :ref:Assignments dataframes). The options are 'Bezier', 'greatcircle', and 'straight'. If Bezier is provided, the leafletCurvature is also required. If greatcircle is provided, the arc follow the curvature of the Earth.
lineCurvature: float in (-90, 90), Conditional, default as 45
If leafletCurveType is 'Bezier', then leafletCurvature is required; otherwise this argument will not be used. The curvature specifies the angle between a straight line connecting the two nodes and the curved arc emanating from those two nodes. Therefore, this value should be in the open interval (-90, 90), although values in the (-45, 45) range tend to work best.
useArrows: boolean, Optional, default as None
Indicates whether arrows should be shown on all arcs on the Leaflet map.
arrowsPerArc: int, Optional, default as 1
Number of arrows display on each arc, should be integer greater than 0. Each arc will have the same number of arrows, regardless of arc length. If useArrows is False, this parameter will be ignored (i.e., no arrows will be drawn).
Return
------
Folium object
A Folium map object containing a polyline (and pre-existing items previously specified in mapObject).
Example
-------
>>> # Draw a polyline around the northern portion of the Univ. at Buffalo campus.
>>> # Save this as "a_polyline.html".
>>> import veroviz as vrv
>>> campusPoints = [[43.0024, -78.7977],
... [43.0121, -78.7858],
... [42.9988, -78.7790]]
>>> myMap = vrv.addLeafletPolyline(
... points=campusPoints,
... mapFilename="a_polyline.html")
>>> myMap
>>> # Draw a polyline around the northern portion of the Univ. at Buffalo campus.
>>> # This example includes all of the available function arguments.
>>> import veroviz as vrv
>>> campusPoints = [[43.0024, -78.7977],
... [43.0121, -78.7858],
... [42.9988, -78.7790]]
>>> myMap = vrv.addLeafletPolyline(
... mapObject = None,
... mapFilename = None,
... mapBackground = 'CartoDB positron',
... mapBoundary = vrv.getMapBoundary(locs=campusPoints),
... zoomStart = None,
... points = campusPoints,
... popupText = 'Univ. at Buffalo',
... lineWeight = 3,
... lineColor = '#0055ff',
... lineOpacity = 0.8,
... lineStyle = 'solid',
... lineCurveType = 'bezier',
... lineCurvature = 30,
... useArrows = True,
... arrowsPerArc = 1)
>>> myMap
"""
# validation
[valFlag, errorMsg, warningMsg] = valAddLeafletPolyline(mapObject, mapFilename, mapBackground, mapBoundary, zoomStart, points, lineWeight, lineColor, lineOpacity, lineStyle, lineCurveType, lineCurvature, useArrows, arrowsPerArc)
if (not valFlag):
print (errorMsg)
return
elif (config['VRV_SETTING_SHOWWARNINGMESSAGE'] and warningMsg != ""):
print (warningMsg)
try:
mapBackground = mapBackground.lower()
except:
pass
# If no mapObject exists, define a new mapObject
if (mapObject == None):
# Adjust the scope of the map to proper bounds
[[minLat, maxLon], [maxLat, minLon]] = privGetMapBoundary(None, None, points)
midLat = (maxLat + minLat) / 2.0
midLon = (maxLon + minLon) / 2.0
mapObject = _createLeafletMap(mapBackground=mapBackground, center=[midLat,midLon], zoomStart=zoomStart)
# set the map boundary for mapObject
if (zoomStart is None):
if (mapBoundary is not None):
mapObject.fit_bounds(mapBoundary)
elif (mapBoundary is None):
mapObject.fit_bounds(privGetMapBoundary(None, None, points))
try:
lineStyle = lineStyle.lower()
except:
pass
# Interpret line style
if (lineStyle == 'dashed'):
dashArray = '30 10'
elif (lineStyle == 'dotted'):
dashArray = '1 6'
else:
dashArray = None
try:
lineColor = lineColor.lower()
except:
pass
# print("FIXMELP -- DONE? Your branch has some code here, but it cannot be implemented because it is missing some variables. Please fix this appropriately.")
arcs = privCreateArcsFromLocSeq(locSeq = points, popupText = popupText)
mapObject = _createLeafletArcs(mapObject=mapObject, arcs=arcs, arcWeight=lineWeight, arcOpacity=lineOpacity, arcStyle=lineStyle, arcColor=lineColor, arcCurveType=lineCurveType, arcCurvature=lineCurvature, useArrows=useArrows, arrowSize=config['VRV_DEFAULT_LEAFLET_ARROWSIZE'], arrowsPerArc=arrowsPerArc)
if (mapFilename is not None):
mapObject.save(mapFilename)
if (config['VRV_SETTING_SHOWOUTPUTMESSAGE']):
print("Message: Map page written to %s." % (mapFilename))
return mapObject
[docs]def addLeafletText(mapObject=None, mapFilename=None, mapBackground=config['VRV_DEFAULT_LEAFLET_MAPTILES'], mapBoundary=None, zoomStart=None, anchorPoint=None, text=None, fontSize=config['VRV_DEFAULT_LEAFLET_FONTSIZE'], fontColor=config['VRV_DEFAULT_LEAFLET_FONTCOLOR'], horizAlign='center'):
"""
Add a text label to a Leaflet map.
Parameters
----------
mapObject: Folium object, Optional, default None
A Folium map object. If provided, the text label will be added to an existing map. Otherwise, a new map will be created.
mapFilename: string, Optional, default as None
This is the name of the map file that will be created (e.g., "../output/map.html" or "map.html"). The filename should have a `.html` extension. If `mapFilename` is not provided, no map file will be generated. The returned map object can be viewed within a Jupyter notebook.
mapBackground: string, Optional, default as 'CartoDB positron'
Sets the background tiles of the map. See :ref:`Leaflet Style` for the list of options.
mapBoundary: list of lists, Optional, default as None
Allows customization of the zoom level. If a map boundary is provided, the zoom level will correspond to the rectangle defined by the two map boundary points. This feature is useful if you want to create multiple comparison maps, each with the same zoom level and centering. Must be in the form [[south lat, west lon], [north lat, east lon]].
zoomStart: int, Optional, default as None
Specifies the default zoom level. 1 --> global view; 18 --> max zoom. Note that some map tiles have maximum zoom levels less than 18. The `zoomStart` will be overridden by a `mapBoundary` (if one is provided).
anchorPoint: list, Required, default None
Specifies an anchor point (location) for the text label. Must be a list of the form `[lat, lon]` or `[lat, lon, alt]`. If provided, the altitude component will be ignored (as all locations on Leaflet maps are assumed to be at ground level). See also the `horizAlign` field below.
text: string, Required, default None
Specifies the text to be displayed on the map at the location of `anchorPoint`.
fontSize: float, Optional, default 24
The size of the font, in units of [points]. The default is 24-point font.
fontColor: string, Optional, default 'orange'
The color of the text string. `fontColor` may be one of Leaflet's pre-specified colors (see :ref:`Leaflet style`), or it may be a hex value, such as `#ff0000` (see https://www.w3schools.com/colors/colors_picker.asp).
horizAlign: string, Optional, default 'center'
The horizontal alignment of the text string, relative to the location specified by the `anchorPoint` input argument. Valid options are 'left' (the text begins at the `anchorPoint` location), 'right' (the text ends at the `anchorPoint` location), or 'center' (the text is centered at the 'anchorPoint' location).
Return
------
Folium object
A Folium map object containing a text string (and pre-existing items previously specified in mapObject).
Example
-------
>>> # Draw a text label at the location of Bell Hall on the
>>> # Univ. at Buffalo campus.
>>> # Save this as "a_text_label.html".
>>> import veroviz as vrv
>>> myMap = vrv.addLeafletText(
... anchorPoint=[43.00154, -78.7871],
... text="Bell Hall",
... mapFilename="a_text_label.html")
>>> myMap
>>> # Draw a text label at the location of Bell Hall on the
>>> # Univ. at Buffalo campus.
>>> # This example includes all of the available function arguments.
>>> import veroviz as vrv
>>> myMap = vrv.addLeafletText(
... mapObject=None,
... mapFilename=None,
... mapBackground='CartoDB positron',
... mapBoundary=None,
... zoomStart=10,
... anchorPoint=[43.00154, -78.7871],
... text="Bell Hall",
... fontSize=34,
... fontColor='black',
... horizAlign='left')
>>> myMap
"""
# validation
[valFlag, errorMsg, warningMsg] = valAddLeafletText(mapObject, mapFilename, mapBackground, mapBoundary, zoomStart, anchorPoint, text, fontSize, fontColor, horizAlign)
if (not valFlag):
print (errorMsg)
return
elif (config['VRV_SETTING_SHOWWARNINGMESSAGE'] and warningMsg != ""):
print (warningMsg)
try:
mapBackground = mapBackground.lower()
except:
pass
anchorPoint = [anchorPoint[0], anchorPoint[1]]
# If no mapObject exists, define a new mapObject
if (mapObject == None):
mapObject = _createLeafletMap(mapBackground=mapBackground, center=anchorPoint, zoomStart=zoomStart)
# set the map boundary for mapObject
if (zoomStart is None):
if (mapBoundary is not None):
mapObject.fit_bounds(mapBoundary)
iconSizeX = 900 # FIXME -- Not sure if this is good.
try:
horizAlign = horizAlign.lower()
except:
pass
if (horizAlign == 'left'):
iconAnchorX = 0
elif (horizAlign == 'right'):
iconAnchorX = iconSizeX
else:
iconAnchorX = iconSizeX / 2
try:
fontColor = fontColor.lower()
except:
pass
folium.map.Marker(anchorPoint, icon=DivIcon(
icon_size = (iconSizeX, fontSize),
icon_anchor = (iconAnchorX, fontSize),
html = "<div style=\"font-size: %dpt; color: %s; text-align: %s;\">%s</div>" % (fontSize, fontColor, horizAlign, text)
)).add_to(mapObject)
if (mapFilename is not None):
mapObject.save(mapFilename)
if (config['VRV_SETTING_SHOWOUTPUTMESSAGE']):
print("Message: Map page written to %s." % (mapFilename))
return mapObject
[docs]def addLeafletIcon(mapObject=None, mapFilename=None, mapBackground=config['VRV_DEFAULT_LEAFLET_MAPTILES'], mapBoundary=None, zoomStart=None, location=None, iconPrefix=config['VRV_DEFAULT_LEAFLETICONPREFIX'], iconType=config['VRV_DEFAULT_LEAFLETICONTYPE'], iconColor=config['VRV_DEFAULT_LEAFLETICONCOLOR'], iconText=None, popupText=None):
"""
Add a single icon/pin to a Leaflet map.
Parameters
----------
mapObject: Folium object, Optional, default None
A Folium map object. If provided, the marker will be added to an existing map. Otherwise, a new map will be created.
mapFilename: string, Optional, default None
If provided, the map will be saved to this file, which should have a `.html` extension. `mapFilename` can contain a filepath. If `mapFilename` is not provided, no file will be generated. The returned mapObject can be viewed within a Jupyter notebook.
mapBackground: string, Optional, default 'CartoDB positron'
The tiles of the map, default to be 'CartoDB positron', for options, see :ref:`Leaflet Style`, also see folium documentation (https://python-visualization.github.io/folium/modules.html) for more options
mapBoundary: list of lists, Optional, default None
If provided, the mapBoundary coordinates are used to determine a zoom level such that these coordinates are contained within view when the map is opened. This feature is useful if you want to create multiple comparison maps, each with the same zoom level and centering. `mapBoundary` must be in the form [[south lat, west lon], [north lat, east lon]].
zoomStart: int, Optional, default as None
Specifies the default zoom level. 1 --> global view; 18 --> max zoom. Note that some map tiles have maximum zoom levels less than 18. The `zoomStart` will be overridden by a `mapBoundary` (if one is provided).
location: list, Required, default as None
Specifies the GPS coordinates of the icon/pin. Must be a list of the form `[lat, lon]` or `[lat, lon, alt]`. If provided, the altitude component will be ignored (as all locations on Leaflet maps are assumed to be at ground level).
iconPrefix: string, Optional, default as "glyphicon"
There are a large number of Leaflet icons available. The `iconPrefix` identifies one of three collections: "glyphicon", "fa", or "custom". See :ref:`Leaflet Style` for more information.
iconType: string, Optional, default as "info-sign"
Specifies the particular icon to be used for the icon/pin. The list of available options depends on the choice of `iconPrefix`. See :ref:`Leaflet Style` for available options.
iconColor: string, Optional, default as "blue"
Defines the color of the icon/pin. See :ref:`Leaflet Style` for the list of available color options.
iconText: string, Optional, default as None
Text that will be displayed within the node on a Leaflet map. This text will only be shown if `iconPrefix` is 'custom' and `iconType` includes a font color and font size. See :ref:`Leaflet style`.
popupText: string, Optional, default as None
The icon/pin will include this text as a popup label (you will need to click on the pin in the map to see this label).
Return
------
Folium object
A Folium map object containing an icon/pin (and pre-existing items previously specified in mapObject).
Example
-------
Import veroviz and check if the version is up-to-date:
>>> import veroviz as vrv
>>> vrv.checkVersion()
Define a location:
>>> whiteHouse = [38.8977, -77.0365]
A minimal example, using mostly default parameters:
>>> vrv.addLeafletIcon(location = whiteHouse)
An example showing all function parameters:
>>> vrv.addLeafletIcon(mapObject = None,
... mapFilename = None,
... mapBackground = 'arcgis aerial',
... mapBoundary = None,
... zoomStart = None,
... location = whiteHouse,
... iconPrefix = 'custom',
... iconType = '18-yellow-12',
... iconColor = 'purple',
... iconText = 'WH',
... popupText = '<nobr>click icon to see this single-line text</nobr>')
"""
# validation
[valFlag, errorMsg, warningMsg] = valAddLeafletIcon(mapObject, mapFilename, mapBackground, mapBoundary, zoomStart, location, iconPrefix, iconType, iconColor, popupText)
if (not valFlag):
print (errorMsg)
return
elif (config['VRV_SETTING_SHOWWARNINGMESSAGE'] and warningMsg != ""):
print (warningMsg)
try:
mapBackground = mapBackground.lower()
except:
pass
location = [location[0], location[1]]
# If no mapObject exists, define a new mapObject
if (mapObject == None):
mapObject = _createLeafletMap(mapBackground=mapBackground, center=location, zoomStart=zoomStart)
# set the map boundary for mapObject
if (zoomStart is None):
if (mapBoundary is not None):
mapObject.fit_bounds(mapBoundary)
_drawLeafletNode(mapObject, location, popupText, iconPrefix, iconType, iconColor, iconText)
if (mapFilename is not None):
mapObject.save(mapFilename)
if (config['VRV_SETTING_SHOWOUTPUTMESSAGE']):
print("Message: Map page written to %s." % (mapFilename))
return mapObject
[docs]def addLeafletIsochrones(mapObject=None, mapFilename=None, mapBackground=config['VRV_DEFAULT_LEAFLET_MAPTILES'], mapBoundary=None, zoomStart=None, iso=None, showBoundingRegion=False, iconPrefix=config['VRV_DEFAULT_LEAFLETICONPREFIX'], iconType=config['VRV_DEFAULT_LEAFLETICONTYPE'], iconColor=config['VRV_DEFAULT_LEAFLETICONCOLOR'], iconText=None, popupText=None, lineWeight=3, lineOpacity=0.8, lineStyle='solid', fillOpacity=0.3):
"""
Easily draw isochrones on a Leaflet map. Be sure to run the `isochrones()` function first.
Parameters
----------
mapObject: Folium object, Optional, default None
A Folium map object. If provided, the marker will be added to an existing map. Otherwise, a new map will be created.
mapFilename: string, Optional, default None
If provided, the map will be saved to this file, which should have a `.html` extension. `mapFilename` can contain a filepath. If `mapFilename` is not provided, no file will be generated. The returned mapObject can be viewed within a Jupyter notebook.
mapBackground: string, Optional, default 'CartoDB positron'
The tiles of the map, default to be 'CartoDB positron', for options, see :ref:`Leaflet Style`, also see folium documentation (https://python-visualization.github.io/folium/modules.html) for more options
mapBoundary: list of lists, Optional, default None
If provided, the mapBoundary coordinates are used to determine a zoom level such that these coordinates are contained within view when the map is opened. This feature is useful if you want to create multiple comparison maps, each with the same zoom level and centering. `mapBoundary` must be in the form [[south lat, west lon], [north lat, east lon]].
zoomStart: int, Optional, default as None
Specifies the default zoom level. 1 --> global view; 18 --> max zoom. Note that some map tiles have maximum zoom levels less than 18. The `zoomStart` will be overridden by a `mapBoundary` (if one is provided).
iso: isochrone object, Required, default as None
See the `isochrones()` function for details on how to create this object.
showBoundingRegion: boolean, Optional, default as False
The isochrone object contains a bounding region, which is the smallest rectangle enclosing the isochrones. If you wish to include this rectangle on the map, set `showBoundingRegion=True`.
iconPrefix: string, Optional, default as "glyphicon"
There are a large number of Leaflet icons available. The `iconPrefix` identifies one of three collections: "glyphicon", "fa", or "custom". See :ref:`Leaflet Style` for more information.
iconType: string, Optional, default as "info-sign"
Specifies the particular icon to be used for the icon/pin. The list of available options depends on the choice of `iconPrefix`. See :ref:`Leaflet Style` for available options.
iconColor: string, Optional, default as "blue"
Defines the color of the icon/pin. See :ref:`Leaflet Style` for the list of available color options.
iconText: string, Optional, default as None
Text that will be displayed within the node on a Leaflet map. This text will only be shown if `iconPrefix` is 'custom' and `iconType` includes a font color and font size. See :ref:`Leaflet style`.
popupText: string, Optional, default as None
The icon/pin will include this text as a popup label (you will need to click on the pin in the map to see this label).
lineWeight: int, Optional, default 3
The width of the polygon's outline, in units of [pixels]. This value is ignored if `lineColor = None`.
lineOpacity: float in [0, 1], Optional, default 0.8
Specifies the opacity of the polygon's outline. Valid values are in the range from 0 (invisible) to 1 (no transparency).
lineStyle: string, Optional, default 'solid'
The style of the polygon's outline. See :ref:`Leaflet Style` for a list of valid options.
fillOpacity: float in [0, 1], Optional, default 0.3
Specifies the opacity of the polygon's interior. Valid values are in the range from 0 (invisible) to 1 (no transparency).
Return
------
Folium object
A Folium map object containing a polygon (and pre-existing items previously specified in mapObject).
Example
-------
Import veroviz and check if the version is up-to-date:
>>> import veroviz as vrv
>>> vrv.checkVersion()
The following examples assume the use of ORS as the data provider. If you have saved your API keys as environment variables, you may use `os.environ` to access them:
>>> import os
>>>
>>> ORS_API_KEY = os.environ['ORSKEY']
>>>
>>> # Otherwise, you may specify your keys here:
>>> # ORS_API_KEY = 'YOUR_ORS_KEY_GOES_HERE'
Get isochrone data:
>>> iso = vrv.isochrones(location = [43.00154, -78.7871],
... locationType = 'start',
... travelMode = 'driving-car',
... rangeType = 'time',
... rangeSize = vrv.convertTime(5, 'minutes', 'seconds'),
... interval = vrv.convertTime(2.5, 'minutes', 'seconds'),
... smoothing = 5,
... dataProvider ='ors-online',
... dataProviderArgs = {'APIkey': ORS_API_KEY})
A minimal working example, using mostly default values:
>>> vrv.addLeafletIsochrones(iso = iso)
An example using all of the functional parameters:
>>> vrv.addLeafletIsochrones(mapObject = None,
... mapFilename = None,
... mapBackground = 'cartodb dark_matter',
... mapBoundary = None,
... zoomStart = None,
... iso = iso,
... showBoundingRegion = True,
... iconPrefix = 'custom',
... iconType = '12-white-12',
... iconColor = 'red',
... iconText = '1',
... popupText = None,
... lineWeight = 3,
... lineOpacity = 0.8,
... lineStyle = 'solid',
... fillOpacity = 0.3)
"""
# validation
[valFlag, errorMsg, warningMsg] = valAddLeafletIsochrones(mapObject, mapFilename, mapBackground, mapBoundary, zoomStart, iso, showBoundingRegion, iconPrefix, iconType, iconColor, popupText, lineWeight, lineOpacity, lineStyle, fillOpacity)
if (not valFlag):
print (errorMsg)
return
elif (config['VRV_SETTING_SHOWWARNINGMESSAGE'] and warningMsg != ""):
print (warningMsg)
try:
mapBackground = mapBackground.lower()
except:
pass
# If no mapObject exists, define a new mapObject
if (mapObject == None):
# Adjust the scope of the map to properly show all objects
[[minLat, maxLon], [maxLat, minLon]] = privGetMapBoundary(None, None, iso['boundingRegion'])
midLat = (maxLat + minLat) / 2.0
midLon = (maxLon + minLon) / 2.0
mapObject = _createLeafletMap(mapBackground=mapBackground, center=[midLat,midLon], zoomStart=zoomStart)
# set the map boundary for mapObject
if (zoomStart is None):
if (mapBoundary is not None):
mapObject.fit_bounds(mapBoundary)
elif (mapBoundary is None):
mapObject.fit_bounds(privGetMapBoundary(None, None, iso['boundingRegion']))
if (showBoundingRegion):
folium.PolyLine(
iso['boundingRegion'],
color = config['VRV_DEFAULT_LEAFLETBOUNDINGCOLOR'],
weight = config['VRV_DEFAULT_LEAFLETBOUNDINGWEIGHT'],
opacity = config['VRV_DEFAULT_LEAFLETBOUNDINGOPACITY'],
dash_array = '30 10',
popup = 'bounding region'
).add_to(mapObject)
_drawLeafletNode(mapObject, iso['location'], popupText, iconPrefix, iconType, iconColor, iconText)
try:
lineStyle = lineStyle.lower()
except:
pass
# Interpret line style
if (lineStyle == 'dashed'):
dashArray = '30 10'
elif (lineStyle == 'dotted'):
dashArray = '1 6'
else:
dashArray = None
try:
fillColor = fillColor.lower()
except:
pass
isoColorList = ['#9e0142', '#d53e4f', '#f46d43', '#fdae61', '#fee08b', '#ffffbf', '#e6f598', '#abdda4', '#66c2a5', '#3288bd', '#5e4fa2']
# Need to draw in reverse order (largest to smallest) so they are layered properly on map. Otherwise, the big polygon will prevent clicking on smaller ones.
for i in range(len(iso['isochrones'])-1, -1, -1):
tmpText = '<nobr>value: {} {}</nobr>\n'.format(iso['isochrones'][i]['value'], iso['isochrones'][i]['valueUnits'])
tmpText += '<nobr>area: {} sq meters</nobr>\n'.format(iso['isochrones'][i]['area'])
tmpText += '<nobr>pop: {}</nobr>\n'.format(iso['isochrones'][i]['pop'])
tmpText += '<nobr>reachfactor: {}</nobr>\n'.format(iso['isochrones'][i]['reachfactor'])
lineColor = isoColorList[i%len(isoColorList)]
fillColor = lineColor
# Each isochrone may have several polylines.
for j in range(0, len(iso['isochrones'][i]['poly'])):
folium.Polygon(locations = iso['isochrones'][i]['poly'][j],
stroke = True,
weight = lineWeight,
color = lineColor,
opacity = lineOpacity,
dash_array = dashArray,
fill_color = fillColor,
fill_opacity = fillOpacity,
popup=str(tmpText)
).add_to(mapObject)
if (mapFilename is not None):
mapObject.save(mapFilename)
if (config['VRV_SETTING_SHOWOUTPUTMESSAGE']):
print("Message: Map page written to %s." % (mapFilename))
return mapObject
[docs]def addLeafletWeather(mapObject=None, mapType='precip', APIkey=None, mapFilename=None, mapBackground=config['VRV_DEFAULT_LEAFLET_MAPTILES']):
"""
Adds map tiles showing weather conditions to a Leaflet map. Weather tiles are obtained via openweathermap.org (an API key is required).
Parameters
----------
mapObject: Folium object, Optional, default as None
If you already have a map (as a Folium object), you can provide that object and overlay weather on that map.
mapType: string, Required, default as 'precip'
Specifies the type of weather map to overlay on the mapObject. Valid options are: 'clouds', 'precip', 'pressure', 'wind', and 'temp'.
APIkey: string, Required, default at None
These weather maps are hosted by openweathermap.org. You may register for a free API key at their website.
mapFilename: string, Optional, default as None
This is the name of the map file that will be created (e.g., "../output/map.html" or "map.html"). The filename should have a `.html` extension. If `mapFilename` is not provided, no map file will be generated. The returned map object can be viewed within a Jupyter notebook.
mapBackground: string, Optional, default as 'CartoDB positron'
Sets the background tiles of the map. See :ref:`Leaflet Style` for the list of options.
Return
------
Folium object
A Folium map object containing a text string (and pre-existing items previously specified in mapObject).
Example
-------
Import veroviz and check if the version is up-to-date:
>>> import veroviz as vrv
>>> vrv.checkVersion()
If you have saved your API keys as environment variables, you may use `os.environ` to access them:
>>> import os
>>>
>>> OPENWEATHER_KEY = os.environ['OPENWEATHERKEY']
>>>
>>> # Otherwise, you may specify your keys here:
>>> # OPENWEATHER_KEY = 'YOUR_OPENWEATHERMAP_KEY_GOES_HERE'
Display a map showing wind conditions. This example includes all available function arguments.
>>> vrv.addLeafletWeather(mapObject = None,
... mapType = 'wind',
... APIkey = OPENWEATHER_KEY,
... mapFilename = None,
... mapBackground = 'cartodb dark_matter')
"""
# validation
[valFlag, errorMsg, warningMsg] = valAddLeafletWeather(mapObject, mapType, APIkey, mapFilename, mapBackground)
if (not valFlag):
print (errorMsg)
return
elif (config['VRV_SETTING_SHOWWARNINGMESSAGE'] and warningMsg != ""):
print (warningMsg)
# Replace backslash
mapFilename = replaceBackslashToSlash(mapFilename)
try:
mapType = mapType.lower()
except:
pass
try:
mapBackground = mapBackground.lower()
except:
pass
# If no mapObject exists, define a new mapObject
if (mapObject == None):
mapObject = _createLeafletMap(mapBackground=mapBackground, center=[0,0])
# Add the weather map layer:
folium.TileLayer(
tiles = '%s%s' % (weatherMaps[mapType]['tiles'], APIkey),
attr = weatherMaps[mapType]['attr']
).add_to(mapObject)
if (mapFilename is not None):
mapDirectory = ""
strList = mapFilename.split("/")
for i in range(len(strList) - 1):
mapDirectory += strList[i] + "/"
if (mapDirectory != ""):
if (not os.path.exists(mapDirectory)):
os.makedirs(mapDirectory, exist_ok=True)
mapObject.save(mapFilename)
if (config['VRV_SETTING_SHOWOUTPUTMESSAGE']):
print("Message: Map page written to %s." % (mapFilename))
return mapObject
# weatherMaps