Search code examples
pythonmatplotlibcolorsgeopandasfolium

Can I make a colour gradient or color change base on the number of visit to some specific country?


i have been trying with geopandas and folium and other common libraries of python. I create myself a little challenge, I make a map and highlight the countries I have been to with a single colour. However, I would like to add more features into it, I want to present a different color of the country if I have been there more than once. For example, taiwan, i have been there once, so it is a orange color, japan, twice, so is a red colur, korea, 3 times, so is a purple color etc... I took reference from matplotlib recently but the code isnt working, is it possible to give me some advice?

here is my code the excel file has 2 columns Column A called 'Country', consists of the name of country like china, japan, germany etc, Column B called 'Visits', consists of how many times I have travelled to a corresponding country.

from google.colab import files
import pandas as pd
import geopandas as gpd
import folium
import matplotlib.cm as cm
import matplotlib.colors as colors

# Uploads file
uploaded = files.upload()


filename = next(iter(uploaded))

# Read  Excel file to a pandas DataFrame
df = pd.read_excel(filename)

# world geometry 
world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))

# Merge data with the world data
visited = world.merge(df, left_on='name', right_on='Country')

# map createw
m = folium.Map(location=[0, 0], zoom_start=2)

# boundaries 
for _, r in world.iterrows():
    sim_geo = gpd.GeoSeries(r['geometry']).simplify(tolerance=0.001)
    geo_j = folium.GeoJson(data=sim_geo.to_json(), style_function=lambda x: {'color': 'black'})
    folium.Popup(r['name']).add_to(geo_j)
    geo_j.add_to(m)

# Function to set the color based on the number of visits
def color(visits):
    # Create a colormap for 4+ visits
    colormap = cm.get_cmap('YlOrRd')

    # Normalize the visits to 0-1
    norm = colors.Normalize(vmin=1, vmax=4)

    # Get the color from the colormap and convert to hex
    rgba = colormap(norm(visits), bytes=True)
    return '#{:02x}{:02x}{:02x}'.format(rgba[0], rgba[1], rgba[2])

for _, r in visited.iterrows():
    sim_geo = gpd.GeoSeries(r['geometry']).simplify(tolerance=0.001)
    geo_j = folium.GeoJson(data=sim_geo.to_json(), style_function=lambda x: {'fillColor':                     color(r['Visits'])})
    folium.Popup(r['name']).add_to(geo_j)
    geo_j.add_to(m)

#  map
m

Solution

  • It looks like you could make such a map in a simpler way, just with GeoPandas plotting tools, i.e. without using folium. Say you have these data:

    Country Visits
    China 1
    Iran 3
    Japan 2
    North Korea 3
    South Africa 2
    Venezuela 4

    If you store it in a CSV-file, you can extract and show it like this:

    import pandas as pd
    import geopandas
    import matplotlib.pyplot as plt
    import matplotlib.cm as cm
    import matplotlib.colors as colors
    
    
    # read a CSV file to a pandas DataFrame
    df = pd.read_csv('visited_countries.csv', delimiter='\t')
    
    visited = list(df['Country'])  # countries visited
    num = list(df['Visits'])  # number of visits
    
    # get the countries dataset from Natural Earth
    file_with_all_countries = geopandas.datasets.get_path('naturalearth_lowres')
    all_gdf = geopandas.read_file(file_with_all_countries)
    # set the names of the countries as the index
    all_gdf = all_gdf.set_index("name")
    # get the data for the visited countries
    visited_gdf = all_gdf.loc[visited]
    # create a column for the number of visits
    visited_gdf["num"] = num
    cmap = cm.YlOrRd
    # show all the countries with the minimum color from the cmap, indicating 0 visits by default 
    ax = all_gdf.plot(facecolor=cmap(0), edgecolor='grey')
    # paint the visited countries
    norm = colors.BoundaryNorm(sorted(set(num)), ncolors=cmap.N, extend='both')
    visited_gdf.plot(ax=ax, column='num', legend=True, vmin=min(num), vmax=max(num), cmap=cmap, norm=norm)
    plt.title('Country Visits')
    plt.show()
    

    Here is the result: enter image description here