def main(args): if not args.output[-5:] == '.html': exit('ERROR Output file must be .html') heatmap_data = [] for gpx_file in get_gpx_files(args): if not args.quiet: print('Reading {}'.format(gpx_file)) with open(gpx_file, 'r') as file: last_point = None for line in file: if '<trkpt' in line: r = re.findall('[-]?[0-9]*[.]?[0-9]+', line) point = [float(r[0]), float(r[1])] if last_point is not None and distance(point, last_point) < args.skip_distance: continue heatmap_data.append(point) last_point = point if not args.quiet: print('Loaded {} trackpoints'.format(len(heatmap_data))) fmap = Map(tiles = 'CartoDB positron' if args.light_map else 'CartoDB dark_matter', location=args.center, zoom_start=11, prefer_canvas = True, max_zoom = HEATMAP_MAXZOOM) HeatMap(heatmap_data, radius = args.radius, blur = args.blur, gradient = HEATMAP_GRAD['light' if args.light_map else 'dark'], min_opacity = args.min_opacity, max_val = args.max_val).add_to(fmap) if args.center is None: fmap.fit_bounds(fmap.get_bounds()) fmap.save(args.output) if not args.quiet: print('Saved {}'.format(args.output)) if not args.quiet: webbrowser.open(args.output, new = 2, autoraise = True)
def main(args): if not args.output[-5:] == '.html': exit('ERROR Output file must be .html') heatmap_data = [] for gpx_file in get_gpx_files(args): if not args.quiet: print('Reading {}'.format(gpx_file)) with open(gpx_file, 'r') as file: for line in file: if '<trkpt' in line: r = re.findall('[-]?[0-9]*[.]?[0-9]+', line) heatmap_data.append([float(r[0]), float(r[1])]) if not args.quiet: print('Loaded {} trackpoints'.format(len(heatmap_data))) if args.skip_ratio > 1: heatmap_data = heatmap_data[::args.skip_ratio] print('Reduced to {} trackpoints'.format(len(heatmap_data))) fmap = Map(tiles = 'CartoDB positron' if args.light_map else 'CartoDB dark_matter', prefer_canvas = True, max_zoom = HEATMAP_MAXZOOM) HeatMap(heatmap_data, radius = args.radius, blur = args.blur, gradient = HEATMAP_GRAD['light' if args.light_map else 'dark'], min_opacity = args.min_opacity, max_val = args.max_val).add_to(fmap) fmap.fit_bounds(fmap.get_bounds()) fmap.save(args.output) if not args.quiet: print('Saved {}'.format(args.output)) webbrowser.open(args.output, new = 2, autoraise = True)
def build_map(trackpoint, trips): ''' Build and display Folium map ''' html_file = args.output # color map for heatmap plugin heatmap_grad = \ {0.0: '#000004', 0.1: '#160b39', 0.2: '#420a68', 0.3: '#6a176e', 0.4: '#932667', 0.5: '#bc3754', 0.6: '#dd513a', 0.7: '#f37819', 0.8: '#fca50a', 0.9: '#f6d746', 1.0: '#fcffa4'} fmap = Map(tiles='CartoDB dark_matter', prefer_canvas=True, max_zoom=16) # Individual coordonate as heatmap HeatMap( trackpoint, radius=5, blur=5, gradient=heatmap_grad, max_zoom=19).add_to(fmap) # Trace the trip as polyline for trip in trips: PolyLine( locations=trip, weight=5, color='#FFC300', opacity=0.6).add_to(fmap) # Set map bounds fmap.fit_bounds(fmap.get_bounds()) # save map to HTML file and open with browser print('writing ' + html_file + '...') fmap.save(html_file) webbrowser.open(html_file, new=2, autoraise=True) print('done')
def map_points_circles(df, feature, date): print(feature.title(), 'at time:', date) # Create a map this_map = Map(prefer_canvas=True) # Check for the inputs to be on the dataframe # Getting data data = df[df['datetime'] == date] # Create a color map color_var = str(feature) #what variable will determine the color cmap = LinearColormap(['blue', 'red'], vmin=data[color_var].quantile(0.05), vmax=data[color_var].quantile(0.95), caption=color_var) # Add the color map legend to your map this_map.add_child(cmap) def plotDot(point): '''Takes a series that contains a list of floats named latitude and longitude and this function creates a CircleMarker and adds it to your this_map''' CircleMarker(location=[point.latitude, point.longitude], fill_color=cmap(point[color_var]), fill=True, fill_opacity=0.4, radius=40, weight=0).add_to(this_map) # Iterate over rows data.apply(plotDot, axis=1) # Set the boundaries this_map.fit_bounds(this_map.get_bounds()) # Show plot return this_map
def main(args): if not args.output[-5:] == '.html': exit('ERROR Output file must be .html') gpx_files = glob.glob('{}/{}'.format(args.dir, args.filter)) if not gpx_files: exit('ERROR No GPX files in {}'.format(args.dir)) heatmap_data = [] for gpx_file in gpx_files: print('Reading {}'.format(gpx_file)) with open(gpx_file, 'r') as file: for line in file: if '<trkpt' in line: r = re.findall('[-]?[0-9]*[.]?[0-9]+', line) heatmap_data.append([float(r[0]), float(r[1])]) print('Loaded {} trackpoints'.format(len(heatmap_data))) fmap = Map(tiles='CartoDB dark_matter', prefer_canvas=True, max_zoom=HEATMAP_MAXZOOM) HeatMap(heatmap_data, radius=args.radius, blur=args.blur, gradient=HEATMAP_GRAD, min_opacity=args.min_opacity).add_to(fmap) fmap.fit_bounds(fmap.get_bounds()) fmap.save(args.output) print('Saved {}'.format(args.output)) webbrowser.open(args.output, new=2, autoraise=True)
def create_map(self): try: import branca.colormap as cm from folium import Map from folium.vector_layers import Polygon except ImportError: # pragma: no cover logger.error( "Mapping requires folium==0.10.0 to be installed, geo mapping will not work." "Install it with: pip install scikit-hts[geo]") return _map = Map(tiles="cartodbpositron") geos = self.get_geos() max_lat, max_lon, min_lat, min_lon = get_min_max_ll(geos) geos = [(i, numpy.log(j + 1) / (self.tree.get_node_height(k) + 1), k) for i, j, k in geos] mx, mn = max([j for i, j, k in geos]), min([j for i, j, k in geos]) geos = [(i, (j - mn) / (mx - mn), k) for i, j, k in geos] for points, count, h in sorted(geos, key=lambda x: x[1]): tooltip = f"hex: {h}" polygon = Polygon( locations=points, tooltip=tooltip, fill=True, color=cm.linear.OrRd_03.rgb_hex_str(count), fill_color=cm.linear.OrRd_03.rgb_hex_str(count), fill_opacity=0.3, weight=3, opacity=0.4, ) polygon.add_to(_map) _map.fit_bounds([[min_lat, min_lon], [max_lat, max_lon]]) return _map
class EWBMap(): """ A class to represent the entire folium map. ... Attributes ---------- layers : array array of all layers to be shown on this map map : Map (folium) map to be displayed layerNames : array list of names of layers in the map Methods ------- makeMapfromLayers(): Creates a map from the existing layers. recenter(string="all"): Recenter the map around the given points. """ # Jannie def __init__(self): """ Constructs all the necessary attributes for the EWBMap object. Parameters ---------- None """ self.layers = [] self.map = Map(location=[45.372, -121.6972], zoom_start=12, tiles='Stamen Terrain') listOfTiles = ['Stamen Toner', 'openstreetmap'] for tile in listOfTiles: folium.TileLayer(tile).add_to(self.map) self.layerNames = [] # Jannie def makeMapfromLayers(self): for layer in self.layers: layer.featureGroup.add_to(self.map) folium.LayerControl().add_to(self.map) # Chen def recenter(self, string="all"): # center around the town - hardcode location TBD if string == 'town': x = 45.5236 y = -122.6750 self.map.location = [x, y] elif string in self.layerNames: xMin, xMax, yMin, yMax = [100, -100, 181, -181] idx = self.layerNames.index(string) layer = self.layers[idx] # layer.df[0] - latitutde, layer.df[1] - longitude --> I know this looks ugly # but is only meant to be a quick fix, will be optimized later xMin = min(xMin, min(layer.df.iloc[:, 0])) xMax = max(xMax, max(layer.df.iloc[:, 0])) yMin = min(yMin, min(layer.df.iloc[:, 1])) yMax = max(yMax, max(layer.df.iloc[:, 1])) # adjust the map bound according the upper and lower bound of the dataset self.map.fit_bounds([[xMin, yMin], [xMax, yMax]]) elif string == 'all': xMin, xMax, yMin, yMax = [100, -100, 181, -181] for layer in self.layers: xMin = min(xMin, min(layer.df.iloc[:, 0])) xMax = max(xMax, max(layer.df.iloc[:, 0])) yMin = min(yMin, min(layer.df.iloc[:, 1])) yMax = max(yMax, max(layer.df.iloc[:, 1])) # adjust the map bound according the upper and lower bound of the dataset self.map.fit_bounds([[xMin, yMin], [xMax, yMax]]) # if the input string does not match any of the options else: print( f"ERROR: wrong string input: {string}\n, valid inputs are: {self.layerNames} or 'all' or 'town" )
def render(g, nodes, edges, file_name_out, markers=False, lines=False, host="localhost", port=5000, prefix=""): from limic.util import start, end, status, file_size from folium import Map, Marker, Icon, PolyLine from folium.plugins import BeautifyIcon from binascii import hexlify from pathlib import Path from math import log2 from pkg_resources import resource_string start("Rendering graph") min_lat = min_long = float('inf') max_lat = max_long = -float('inf') for n in nodes: if n[1] < min_lat: min_lat = n[1] if n[2] < min_long: min_long = n[2] if n[1] > max_lat: max_lat = n[1] if n[2] > max_long: max_long = n[2] m = Map() m.fit_bounds([(min_lat, min_long), (max_lat, max_long)]) if markers: for n in nodes: Marker(n[1:3], icon=BeautifyIcon(icon='none', iconStyle="opacity: 0.1;", borderColor='#7f7f00', backgroundColor='#ffff00'), tooltip=("id: %d" % n[0])).add_to(m) if lines: for u, v, weight in edges: PolyLine([u[1:3], v[1:3]], color="#3f3f00", opacity=0.4, weight=6, tooltip=("weight: %.1f" % weight)).add_to(m) TEMPLATE = resource_string("limic", "render.js").decode('utf8') from branca.element import MacroElement, Template class LatLngListener(MacroElement): _template = Template(TEMPLATE % { 'host': host, 'port': port, 'prefix': prefix }) def __init__(self): super(MacroElement, self).__init__() self._name = 'LatLngListener' LatLngListener().add_to(m) end() start("Saving result to HTML file", file_name_out) #m.save(file_name_out) end('') file_size(file_name_out) return g, nodes
class SpatialPlot: """ a plotting system that allows overlaying spatial elements on a map. Currently we support markers, circles and contours. """ def __init__(self) -> None: # keep tabs on all the locations (self.data) that have been added and then determine the center of gravity # and then call fit_bounds from the map object to determine the best zoom size self.canvass = None self.filename_html = tempfile.NamedTemporaryFile().name + '.html' self.data = None def initialize_canvass(self, center=None) -> None: """ determine the center based on a given locations by finding the latitude mean and longitude mean """ if self.canvass is None: if center is None: self.canvass = Map(location=self.center, zoom_start=6) else: self.canvass = Map(location=center, zoom_start=6) def update_locations(self, new_data, lat_col, lon_col): """ since we allow multiple calls to add contour, points and markers, it's important to keep all locations in track. Doing so is helpful to, for example, determine the boundaries for the whole graph. """ new_data = new_data[[lat_col, lon_col]] new_data.columns = ['LAT', 'LON'] self.data = concat([self.data, new_data]) @property def center(self): if self.data is not None: df_points = self.data[['LAT', 'LON']] center = df_points.mean(axis=0).values center = [round(location, 2) for location in center] return center else: raise ValueError('no location data are available.') def add_marker(self, points: Union[DataFrame, list], lat_col: str = 'LAT', lon_col: str = 'LON', clustered: str = 'auto', **kwargs) -> SpatialPlot: """ this method adds a marker on the map. All info besides the locations will be neglected. allows either list of list or data frame as input The clustered gives an option to fold the locations into clusters if there are too many of them. This functionality will be activated when there is more than 30 locations. User can overwrite this behavior by setting clustered to 'no'. :param points: either a dataframe or a list with location info and the values observed at the location :param lat_col: the column name (str) for latitude information :param lon_col: the column name (str) for longitude information :param clustered: determines if we fold the markers to clusters. 'auto' will fold the markers if there's too many (30). 'no' means we won't fold the markers regardless. 'yes' means we will fold the markers regardless. """ if clustered not in ['yes', 'no', 'auto']: raise ValueError( 'clustered only take yes, no or auto as legit input values') if isinstance(points, DataFrame): if lat_col not in points or lon_col not in points: raise KeyError( 'We need a column for latitude information and a column for longitude' ) df_points = points elif isinstance(points, list): logger.critical( 'we will assume the first position is latitude, and the second is longitude' ) df_points = DataFrame(points).iloc[:, 0:2] df_points.columns = [lat_col, lon_col] else: raise TypeError( 'only list and dataframe are supported in this method') self.update_locations(new_data=df_points, lon_col=lon_col, lat_col=lat_col) self.initialize_canvass() use_cluster, marker_cluster = False, None if (clustered == 'auto' and len(df_points) >= 30) or (clustered == 'yes'): marker_cluster = MarkerCluster(icons="dd").add_to(self.canvass) use_cluster = True logger.critical( f'there are {len(df_points)} locations, and we fold them by clustering. ' f'Set clustered to no to overwrite this behavior.') for _, point in df_points.iterrows(): geo_location = [point[lat_col], point[lon_col]] if use_cluster: Marker(location=geo_location, **kwargs).add_to(marker_cluster) else: Marker(location=geo_location, **kwargs).add_to(self.canvass) return self def add_circles(self, points: Union[DataFrame, list], lat_col: str, lon_col: str, y_col: str, multiplier: float = 2, **kwargs) -> SpatialPlot: """ the difference between the add_circle and add_marker is that the former uses the size of the circle to visualize the value observed at that point :param points: either a dataframe or a list with location info and the values observed at the location :param lat_col: the column name (str) for latitude information :param lon_col: the column name (str) for longitude information :param y_col: the column name (str) for observed value at that location :param multiplier: size of the point. Increase this value to get large circles. """ if isinstance(points, DataFrame): if lat_col not in points or lon_col not in points or y_col not in points: raise KeyError( 'We need a column for latitude information and a column for longitude' ) df_points = points elif isinstance(points, list): logger.critical( 'we will assume the first position is latitude,' ' and the second is longitude, and the third position is y') df_points = DataFrame(points).iloc[:, 0:3] df_points.columns = [lat_col, lon_col, y_col] else: raise TypeError( 'only list and dataframe are supported in this method') df_points = df_points[[lat_col, lon_col, y_col]] self.update_locations(new_data=df_points, lat_col=lat_col, lon_col=lon_col) self.initialize_canvass() for idx, row in df_points.iterrows(): value = row[y_col] location = (row[lat_col], row[lon_col]) CircleMarker(location=location, radius=multiplier*abs(value), **kwargs) \ .add_to(self.canvass) return self def add_contour(self, contour: Union[Polygon, MultiPolygon, str]) -> SpatialPlot: """ :param contour: either a polygon object or a string (state acronym) if it's a string, this method will pull the contour with get_state_contour() function and plot it. """ if isinstance(contour, str): contour_polygon = get_state_contours(contour) elif isinstance(contour, MultiPolygon) or isinstance(contour, Polygon): contour_polygon = contour else: raise TypeError( 'this method only supports state name or polygon object from shapely' ) min_x, min_y, max_x, max_y = contour_polygon.bounds make_df = DataFrame({'LAT': [min_y, max_y], 'LON': [min_x, max_x]}) self.update_locations(new_data=make_df, lat_col='LAT', lon_col='LON') [centroid_] = list(contour_polygon.centroid.coords) longitude, latitude = centroid_ self.initialize_canvass(center=[ latitude, longitude ]) # no need to infer the center this time just use centroid GeoJson(contour_polygon).add_to(self.canvass) return self def _rebalance(self): """ write the map object to a local html so we can open it. before saving: we need to decide the best way to show the map More details: folium package has a parameter the initial zoom (zoom_start). this function helps picking the best zoom size; since we would like to support saving to local functionality (by doing screen shot), it is important to know the best zoom scale """ sw = self.data[['LAT', 'LON']].min().values.tolist() ne = self.data[['LAT', 'LON']].max().values.tolist() self.canvass.fit_bounds([sw, ne]) self.canvass.save(self.filename_html) def show(self): """ show() will open the map in a browser the map will be automatically saved to the current directory with a time stamp """ self._rebalance() webbrowser.open('file://' + os.path.realpath(self.filename_html)) logger.critical( f'the graph has been saved into file named {self.filename_html}') def save_to_file(self, filename=None): """ save the html file to a local dir. The implementation is simply open a browser, take a screen shot and then close the browser. """ self._rebalance() try: browser = webdriver.Firefox() browser.get('file://' + os.path.realpath(self.filename_html)) time.sleep(1) if filename is None: # it's date time plus a random name from datetime import datetime from names import get_first_name time_stamp = str(datetime.now().month).zfill(2) + str( datetime.now().day) filename = '.'.join( [time_stamp + '-' + get_first_name(), 'png']) browser.save_screenshot(os.path.join(os.getcwd(), filename)) browser.quit() except common.exceptions.WebDriverException: warning_message = """ if you are running into a geckodriver issue. Make sure you have firefox installed on a mac os system: make sure to run brew install geckodriver in the terminal or you can do pip install selenium==2.53.6 """ logger.critical(warning_message)
def save_path(costpath, out_file=None, visualize=False): from sys import stdout if visualize and not out_file: status("WARNING (use --output to specify HTML file) ", end='') visualize = False cost, path = costpath if visualize: from folium import Map, Marker, Icon, PolyLine from folium.plugins import BeautifyIcon from binascii import hexlify from webbrowser import open as wopen from pathlib import Path from math import log2 min_lat = min_long = float('inf') max_lat = max_long = -float('inf') for x in path: if x[4] < min_lat: min_lat = x[4] if x[5] < min_long: min_long = x[5] if x[4] > max_lat: max_lat = x[4] if x[5] > max_long: max_long = x[5] m = Map() m.fit_bounds([(min_lat, min_long), (max_lat, max_long)]) start_color = (63, 255, 63) end_color = (63, 63, 255) diff_color = tuple( map(lambda x: x[0] - x[1], zip(end_color, start_color))) length = float(len(path)) for i in range(len(path)): x = path[i] background_color = "#" + hexlify( bytes( map(lambda x: int(x[0] + i * x[1] / length), zip(start_color, diff_color)))).decode('utf8') border_color = "#" + hexlify( bytes( map(lambda x: int((x[0] + i * x[1] / length) / 2), zip(start_color, diff_color)))).decode('utf8') line_color = background_color line_weight = 6 icon = None iconStyle = "" if x[3] < 0: icon = 'times' background_color = "#ffff3f" border_color = "#7f1f1f" elif x[2]: icon = 'flash' background_color = "#ff0000" border_color = "#7f0000" line_color = background_color line_weight = 10 elif i + 1 < len(path) and path[i + 1][2]: icon = 'flash' background_color = "#ff0000" border_color = "#7f0000" elif i == 0 or i + 1 == len(path): icon = 'flash' else: icon = 'none' iconStyle = "opacity: 0.1;" if i > 0 and cost is not None: PolyLine([path[i - 1][4:6], path[i][4:6]], color=line_color, opacity=0.4, weight=line_weight).add_to(m) if icon: Marker(x[4:6], icon=BeautifyIcon(icon=icon, iconStyle=iconStyle, borderColor=border_color, backgroundColor=background_color), popup=("cost: %.1fm, dist: %.1fm, air: %r, id: %d" % x[:4])).add_to(m) m.save(out_file) wopen(Path(out_file).resolve().as_uri(), new=2) else: file = open(out_file, "w") if out_file else stdout print("node(id:" + ",".join(map(lambda x: str(x[3]), path)) + ");out;", file=file)
def main(args): # arguments gpx_dir = args.dir gpx_filter = args.filter html_file = args.output heatmap_radius = args.radius heatmap_blur = args.blur if not html_file[-5:] == '.html': print('ERROR output file must be .html') quit() # parse GPX files gpx_files = glob.glob(gpx_dir + '/' + gpx_filter) if not gpx_files: print('ERROR no GPX files in ' + gpx_dir) quit() heatmap_data = [] for gpx_file in gpx_files: print('reading ' + gpx_file + '...') with open(gpx_file, 'r') as file: for line in file: if '<trkpt' in line: tmp = re.findall('[-]?[0-9]*[.]?[0-9]+', line) heatmap_data.append([float(tmp[0]), float(tmp[1])]) print('read ' + str(len(heatmap_data)) + ' trackpoints') # color map heatmap_grad = \ {0.0: '#000004', 0.1: '#160b39', 0.2: '#420a68', 0.3: '#6a176e', 0.4: '#932667', 0.5: '#bc3754', 0.6: '#dd513a', 0.7: '#f37819', 0.8: '#fca50a', 0.9: '#f6d746', 1.0: '#fcffa4'} # create Folium map fmap = Map(tiles='CartoDB positron', prefer_canvas=True, max_zoom=HEATMAP_MAXZOOM) HeatMap(heatmap_data, radius=heatmap_radius, blur=heatmap_blur, gradient=heatmap_grad, max_zoom=19).add_to(fmap) fmap.fit_bounds(fmap.get_bounds()) # save map to HTML file and open with browser print('writing ' + html_file + '...') fmap.save(html_file) webbrowser.open(html_file, new=2, autoraise=True) print('done')
location=[row[5], row[6]], popup=row[1] )) mapElement.add_child(markuster) # for i in range # plotDot(getLoc('', 'CHENNAI', 'TAMIL NADU', '600029')) #create a map main_map = Map(prefer_canvas=True) #Connect with database db_connection = sqlite3.connect(database='../db.sqlite3') # db_connection = sql.connect(host='hostname', database='db_name', user='******', password='******') df = pd.read_sql('SELECT lat, long FROM main_userprofile', con=db_connection) #Load dataframe and cluster mupLoader(main_map, df) #Add LayerControl LayerControl().add_to(main_map) #Set the zoom to the maximum possible main_map.fit_bounds(main_map.get_bounds()) #Save the map to an HTML file main_map.save('MarkerMap.html') print('Time Taken: {} secs'.format(time()-start))