Created
August 13, 2019 10:30
-
-
Save vikas-git/27b9731a4fc3ef940b7e1501f83e8dcb to your computer and use it in GitHub Desktop.
Implement folium library
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
""" | |
Created on Tuesday 23-July-2019 | |
@author: Vikas shrivastava | |
For more info go to official documentation of folium https://python-visualization.github.io/folium/modules.html | |
""" | |
import random | |
import folium | |
import pandas as pd | |
import numpy as np | |
from collections import namedtuple | |
MIN_RADIUS = 2.0 | |
MAX_RADIUS = 9.0 | |
def convert_float(value, places=2): | |
return float(round(float(value), places)) | |
class GeoVis: | |
def __init__(self, center_lat=23, center_lon=77, zoom=5, width='100%', height='100%'): | |
''' | |
This is constructor function for set center position of map | |
Parameters: | |
center_lat: default(23), | |
center_lon: default(77), | |
zoom: int default(5), | |
width: int default(100%), | |
height: int default(100%), | |
''' | |
self.m = folium.Map( | |
location=[center_lat, center_lon], | |
zoom_start=zoom, | |
width=width, | |
height=height | |
) | |
def make_html_for_tooltip(self, row, fields): | |
html = '' | |
for field in fields: | |
html += '<div><span><b>'+field.title()+'</b>: <label>'+str(row[field])+'</label></br></span></div>' | |
return html | |
def cal_radius(self, volume, max_volume): | |
try: | |
volume = float(volume) | |
max_volume = float(max_volume) | |
radius = float(volume/max_volume) * MAX_RADIUS | |
if radius < MIN_RADIUS: | |
radius = MIN_RADIUS | |
except Exception as e: | |
print(e) | |
radius = MIN_RADIUS | |
return float(round(float(radius), 2)) | |
# def mark_points(self, df, lat_col = 'latitude', lon_col = 'longitude', color = 'green'): | |
# df.apply(lambda row: self.mark_point(row[lat_col], row[lon_col], row['display_name'], color=color), axis=1) | |
# return self | |
def mark_points(self, df, lat_col = 'latitude', lon_col = 'longitude', color = 'green', label_fields=[]): | |
if not label_fields: | |
label_fields = list(df.columns) | |
df.apply(lambda row: self.mark_point(row[lat_col], row[lon_col], self.make_html_for_tooltip(row, label_fields), radius= 4.5, color=color), axis=1) | |
return self | |
def mark_point(self, lat, lon, label='DC', radius=1.5, color='blue', weight=0, opacity=0.7, point_type='circle_marker'): | |
if pd.isna(lat) or pd.isna(lon): | |
return | |
if point_type == 'circle': | |
folium.Circle( | |
radius=radius, | |
location=[lat, lon], | |
popup=label, | |
color=False, | |
fill=True, | |
fill_color=color, | |
tooltip=label | |
).add_to(self.m) | |
elif point_type == 'circle_marker': | |
folium.CircleMarker( | |
location=[lat, lon], | |
radius=radius, | |
popup=label, | |
tooltip=label, | |
color=color, | |
line_color=False, | |
fill=True, | |
fill_color=color, | |
fill_opacity=0.3, | |
weight=weight | |
).add_to(self.m) | |
elif point_type == 'marker': | |
folium.Marker( | |
location=[lat, lon], | |
radius=radius, | |
popup=label, | |
tooltip=label, | |
color=color, | |
weight = weight, | |
opacity = opacity, | |
fill=True, | |
fill_color=color | |
).add_to(self.m) | |
return self | |
def connection_establish(self, points, color="#FF0000", weight=5, opacity=0.5): | |
''' | |
This function connect one lat, long to other lat, long | |
Parameters : | |
points : [(lat, long), (lat2, long2)] | |
color : hexadecimal code(example: #CD5C5C), default: #FF0000 | |
''' | |
folium.PolyLine( | |
points, | |
color=color, | |
weight=weight, | |
opacity=opacity | |
).add_to(self.m) | |
return self | |
def draw_connection(self, lat1, lon1, lat2, lon2, color='blue', weight=1.5, opacity=0.5, | |
bin_col_params={}, bin_col_val=None, tooltip=[]): | |
if pd.isna(lat1) or pd.isna(lon1) or pd.isna(lat2) or pd.isna(lon2): | |
return | |
p1 = [lat1, lon1] | |
p2 = [lat2, lon2] | |
if bin_col_params: | |
bin_col_params['col_val'] = float(bin_col_val) | |
color = self.manage_color_for_connection(**bin_col_params) | |
folium.PolyLine( | |
[p1, p2], | |
color=color, | |
weight=weight, | |
opacity=opacity, | |
tooltip=tooltip | |
).add_to(self.m) | |
return self | |
def connections(self, df, lat_col1 = 'from_latitude', lon_col1 = 'from_longitude', lat_col2 = 'to_latitude', | |
lon_col2 = 'to_longitude', color = 'red', weight=2, opacity=0.3, bin_filters=[], bin_col=None,label_fields=[]): | |
col_max_val = 0 | |
bin_col_params = {} | |
if bin_col: | |
des_col = dict(df[bin_col].describe()) | |
col_max_val = des_col.get('max', '100') | |
bin_col_params = { | |
'col_max_val': col_max_val, | |
'bin_color_filter': bin_filters | |
} | |
if not label_fields: | |
label_fields = list(df.columns) | |
df.apply( | |
lambda row: self.draw_connection( | |
row[lat_col1], row[lon_col1], | |
row[lat_col2], row[lon_col2], | |
color = color, | |
weight=weight, | |
opacity=opacity, | |
bin_col_params=bin_col_params, | |
bin_col_val=row[bin_col], | |
tooltip=self.make_html_for_tooltip(row, label_fields) | |
), | |
axis = 1) | |
return self | |
def manage_color_for_connection(self, col_max_val, bin_color_filter, col_val): | |
color_code = '#a94442' | |
try: | |
x = convert_float(col_val*100/col_max_val) | |
for _filter in bin_color_filter: | |
if float(_filter.get('min_val', 0.0)) < x and float(_filter.get('max_val', 100.0)) >= x: | |
color_code = _filter.get('color_code') | |
break | |
except Exception as e: | |
print(e) | |
return color_code | |
def get_bearing(self, p1, p2): | |
''' | |
Returns compass bearing from p1 to p2 | |
Parameters | |
p1 : namedtuple with lat lon | |
p2 : namedtuple with lat lon | |
Return | |
compass bearing of type float | |
''' | |
long_diff = np.radians(p2.lon - p1.lon) | |
lat1 = np.radians(p1.lat) | |
lat2 = np.radians(p2.lat) | |
x = np.sin(long_diff) * np.cos(lat2) | |
y = (np.cos(lat1) * np.sin(lat2) - (np.sin(lat1) * np.cos(lat2) * np.cos(long_diff))) | |
bearing = np.degrees(np.arctan2(x, y)) | |
# adjusting for compass bearing | |
if bearing < 0: | |
return bearing + 360 | |
return bearing | |
def get_arrows(self, locations, color='blue', size=3, n_arrows=3): | |
''' | |
Get a list of correctly placed and rotated | |
arrows/markers to be plotted | |
Parameters | |
locations : list of lists of lat lons that represent the | |
start and end of the line. | |
eg [[41.1132, -96.1993],[41.3810, -95.8021]] | |
arrow_color : default is 'blue' | |
size : default is 6 | |
n_arrows : number of arrows to create. default is 3 | |
Return | |
list of arrows/markers | |
''' | |
Point = namedtuple('Point', field_names=['lat', 'lon']) | |
# creating point from our Point named tuple | |
p1 = Point(locations[0][0], locations[0][1]) | |
p2 = Point(locations[1][0], locations[1][1]) | |
# getting the rotation needed for our marker. | |
# Subtracting 90 to account for the marker's orientation | |
# of due East(get_bearing returns North) | |
# rotation = self.get_bearing(p1, p2) - 90 | |
# get an evenly space list of lats and lons for our arrows | |
# note that I'm discarding the first and last for aesthetics | |
# as I'm using markers to denote the start and end | |
arrow_lats = np.linspace(p1.lat, p2.lat, n_arrows + 2)[1:n_arrows+1] | |
arrow_lons = np.linspace(p1.lon, p2.lon, n_arrows + 2)[1:n_arrows+1] | |
arrows = [] | |
#creating each "arrow" and appending them to our arrows list | |
for points in zip(arrow_lats, arrow_lons): | |
arrows.append(folium.RegularPolygonMarker(location=points, | |
fill_color=color, number_of_sides=1, | |
radius=size, rotation=0, weight=1)) | |
return arrows | |
def manage_arrows(self, lat1, lon1, lat2, lon2): | |
if pd.isna(lat1) or pd.isna(lon1) or pd.isna(lat2) or pd.isna(lon2): | |
return | |
p1 = [lat1, lon1] | |
p2 = [lat2, lon2] | |
arrows = self.get_arrows([p1,p2]) | |
for arrow in arrows: | |
arrow.add_to(self.m) | |
return self | |
def connection_flow_arrow(self, df, lat_col1 = 'from_latitude', lon_col1 = 'from_longitude', lat_col2 = 'to_latitude', | |
lon_col2 = 'to_longitude'): | |
df.apply( | |
lambda row: self.manage_arrows( | |
row[lat_col1], row[lon_col1], | |
row[lat_col2], row[lon_col2] | |
), | |
axis = 1) | |
return self | |
def manage_arrows_without_df(self, points): | |
for i in range(len(points)-1): | |
arrows = self.get_arrows([points[i], points[i+1]]) | |
for arrow in arrows: | |
arrow.add_to(self.m) | |
return self |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment