I'm drawing colored regions on a folium
map using log scale shading. Using custom colormap, the region colors seem to be ok. But the colormap, when added to the map legend, still looks linear:
Is there any way to draw it as equal-width colored rectangles with text values underneath?
import numpy as np, branca, folium
m = folium.Map()
colormap = branca.colormap.LinearColormap(colors=['blue', 'green', 'yellow', 'orange', 'red'],
index = np.round(np.exp(np.linspace(0, 9, 5))),
vmin = 0, vmax = np.exp(9),
).to_step(n=6, index=np.round(np.exp(np.linspace(0, 9, 6))))
colormap.add_to(m)
There is no Folium-native way to do this, and branca legends seem to be resistant to custom scaling. A workaround I have found is to create the legend separately (I use matplotlib), then overlay it on the Folium map as a Custom Icon. Looks like this:
import matplotlib.pyplot as plt
import matplotlib.lines as mlines
import numpy as np
import folium
from folium.features import CustomIcon
import matplotlib.colors as mcolors
def generate_legend(num_colors):
# dynamically generate a color map
cmap = plt.get_cmap('viridis', num_colors)
colors = [cmap(i) for i in range(cmap.N)]
# generate labels based on how many colors there are
log_labels = np.logspace(0, num_colors, num=num_colors, base=10).astype(int)
fig, ax = plt.subplots(figsize=(6, 0.6))
font_size = 12
line_width = 30
# create colors
for i, color in enumerate(colors):
plt.plot([i, i+1], [1, 1], color=color, solid_capstyle='butt', linewidth=line_width)
plt.text(i+0.5, 0.5, f'{log_labels[i]}', ha='center', va='center', fontsize=font_size, transform=ax.transData)
ax.set_xlim(0, num_colors)
ax.set_ylim(0, 2)
ax.axis('off')
plt.subplots_adjust(left=0, right=1, top=1, bottom=0, wspace=0, hspace=0)
plt.savefig('dynamic_legend.png', dpi=300, transparent=True, bbox_inches='tight', pad_inches=0)
plt.close()
# add legend to map
m = folium.Map(location=[20, 0], zoom_start=2)
legend_img = 'dynamic_legend.png'
icon = CustomIcon(legend_img, icon_size=(600, 120)) # Adjust icon size as needed
marker = folium.Marker(location=[-25, 0], icon=icon, popup='Legend') # Adjust location as needed
m.add_child(marker)
m.save('map_with_dynamic_legend.html')
num_colors = 5
generate_legend(num_colors)