Search code examples
pythonpandasfolium

Plotting Pandas Dataframe data using Folium GeoJson


I am trying to plot the amount of times a satellite goes over a certain location using Python and a heatmap. I easily generate the satellite data, but I am having issues with displaying it in a nice manner. I am trying to follow this example, as I can use the style function to lower the opacity. I am having some issues replicating this though as it seems that the GeoJson version they were using no longer accepts the same inputs. This is the dataframe I am using:

print(df.head())
     latitude  longitude  countSp                     geometry
0     -57.9      151.1      1.0  POLYGON ((151.05 -57.95, 151.15 -57.95, 151.15...
1     -57.9      151.2      2.0  POLYGON ((151.15 -57.95, 151.25 -57.95, 151.25...
2     -57.8      151.2      1.0  POLYGON ((151.15 -57.84999999999999, 151.25 -5...
3     -57.8      151.3      3.0  POLYGON ((151.25 -57.84999999999999, 151.35 -5...
4     -57.8      151.4      2.0  POLYGON ((151.35 -57.84999999999999, 151.45 -5...

I then call folium through:

hmap = folium.Map(location=[42.5, -80], zoom_start=7, )
colormap_dept = branca.colormap.StepColormap(
        colors=['#00ae53', '#86dc76', '#daf8aa',
            '#ffe6a4', '#ff9a61', '#ee0028'],
        vmin=0,
        vmax=max_amt,
        index=[0, 2, 4, 6, 8, 10, 12])
    
style_func = lambda x: {
        'fillColor': colormap_dept(x['countSp']),
        'color': '',
        'weight': 0.0001,
        'fillOpacity': 0.1
    }

folium.GeoJson(
    df,
    style_function=style_func,
).add_to(hmap)

This is the error I get when I run my code:

ValueError: Cannot render objects with any missing geometries: latitude  longitude  countSp  geometry

I know that I can use the HeatMap plugin from folium in order to get most of this done, but I have found a couple of issues with doing that. First is that I cannot easily generate a legend (though I have been able to work around this). Second is that it is way too opaque, and I am not finding any ways of reducing that. I have tried playing around with the radius, and blur parameters for HeatMap without much change. I think that the fillOpacity of the style_func above is a much better way of making my data translucent.

By the way, I generate the polygon in my df by the following command. So in my dataframe all I need folium to know about is the geometry and countSp (which is the number of times a satellite goes over a certain area - ~10kmx10km square).

    df['geometry'] = df.apply(lambda row: Polygon([(row.longitude-0.05, row.latitude-0.05), 
                                               (row.longitude+0.05, row.latitude-0.05),
                                               (row.longitude+0.05, row.latitude+0.05),
                                               (row.longitude-0.05, row.latitude+0.05)]), axis=1)

Is there a good way of going about this issue?


Solution

  • Once again, they were looking for a way to express the purpose in a heat map, so I used Plotly's data on airline arrivals and departures to visualize it.

    enter image description here

    The number of flights to and from the U.S. mainland only was used for the data.

    Excluded IATA codes['LIH','HNL','STT','STX','SJU','OGG','KOA']

    • Draw a straight line on the map from the latitude and longitude of the departure airport to the latitude and longitude of the arrival airport.

    • Draw a heat map with data on the number of arrivals and departures by airport.

    • Since we cannot use a discrete colormap, we will create a linear colormap and add it.

    • Embed the heatmap as a layer named Traffic

    import pandas as pd
    
    df_airports = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/2011_february_us_airport_traffic.csv')
    df_airports.sort_values('cnt', ascending=False)
    df_air = df_airports[['lat','long','cnt']]
    
    df_flight_paths = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/2011_february_aa_flight_paths.csv')
    
    df_flight_paths = df_flight_paths[~df_flight_paths['airport1'].isin(['HNL','STT','SJU','OGG','KOA'])]
    df_flight_paths = df_flight_paths[~df_flight_paths['airport2'].isin(['LIH','HNL','STT','STX','SJU'])]
    
    df_flight_paths = df_flight_paths[['start_lat', 'start_lon', 'end_lat', 'end_lon', 'cnt']]
    
    import folium
    from folium.plugins import HeatMap
    import branca.colormap as cm
    from collections import defaultdict
    
    steps=10
    colormap = cm.linear.YlGnBu_09.scale(0, 1).to_step(steps)
    gradient_map=defaultdict(dict)
    
    for i in range(steps):
        gradient_map[1/steps*i] = colormap.rgb_hex_str(1/steps*i)
        
    m = folium.Map(location=[32.500, -97.500], zoom_start=4, tiles="cartodbpositron")
    
    data = []
    for idx,row in df_flight_paths.iterrows():
        folium.PolyLine([[row.start_lat, row.start_lon], [row.end_lat, row.end_lon]], weight=2, color="red", opacity=0.4
    ).add_to(m)
        
    HeatMap(
        df_air.values,
        gradient=gradient_map,
        name='Traffic',
        mini_opacity=0.1,
        radius=15,
        blur=5
    ).add_to(m)
    
    folium.LayerControl().add_to(m)
    colormap.add_to(m)
    m
    

    enter image description here

    enter image description here