Folium markers with numbers inside - python

I would like to make some markers on the map using Folium with some numbers inside the markers.
The markers I want to look like the standard inverted drop shapes that Google Maps is using.
I saw that for folium.Marker you can use the parameter icon=folium.DivIcon("html code here"), but I don't know how I could make the html code so the marker looks like an inverted drop standard marker.
I saw a nice example here, using leaflet.js: https://github.com/iatkin/leaflet-svgicon, and here is their demo: http://iatkin.github.io/leaflet-svgicon/.
I just don't know how to implement that in Python.
The numbers that I would like to place inside the markers are some kind of rating numbers that have 3 characters (1 digit, a dot, and a decimal), for example 3.4, 4.8, 2.5, etc. the values are from 0.0 to 5.0.
This type of marker shape is fine too:
I saw some other solutions like this example, that show circles and showing the numbers inside, but it doesn't looks as nice as the regular pointy pushpin kinf of marker:
Numbers in map marker in Folium
Thanks,
Steven

Hello I did something similar, the result is the following:
The code is:
import folium
import folium.plugins as plugins
# BASE MAP
n = folium.Map(location=[20.299172882895903,-103.18423327532622], zoom_start = 10)
for i in range(0,len(DF)):
html=f"""
<h2> InformaciĆ³n de la ruta </h2>
<p> Ruta: {DF.iloc[i]['route_id']} </p>
<p> Secuencia de visita: {DF.iloc[i]['sequencia']} </p>
"""
iframe = folium.IFrame(html=html, width=200, height=150)
popup = folium.Popup(iframe, max_width=650)
folium.Marker(
location=[DF.iloc[i]['latitude'], DF.iloc[i]['longitude']], popup=popup,
icon=plugins.BeautifyIcon(
icon="arrow-down", icon_shape="marker",
number=DF.iloc[i]['sequencia'],
border_color= itinerario_lunes.iloc[i]['hex_code'],
background_color=itinerario_lunes.iloc[i]['hex_code']
)
).add_to(n)
# Show the map again
n

Related

Customize PyGal WorldMap chart's tooltip

I'm using pygal for generate a world map chart in Google Colab.
The problem I'm facing is with the tooltip. I want to show only in the tooltip the name of the country and the number of videos found.
The result so far I've managed to get is as follows:
Worldmap chart current output:
You can see there that the tooltip is composed as follows:
Country name
Number of videos
Country name: 1
Example:
United States
73 videos
Unites States: 1
Using the sample shown in the screenshot and in the sample above, what I want to get is
Example:
United States
73 videos
OR:
Example:
Unites States: 73 videos
Here is the Google Colab notebook sample I've created, so anyone can reproduce this issue.
This is the Worldmap chart settings:
# Save chart as svg:
worldmap_chart.render_to_file('worldmap_result.svg',
show_legend=True,
human_readable=True,
fill=True,
print_labels=True,
no_data_text="No data available",
legend_at_bottom=True,
pretty_print=True,
x_title="Hover the cursor on the country's name bellow or the map above:",
print_values=True,
force_uri_protocol='https')
I've readed the documentation and searched, but, I'm not been able to find the correct configuration (if possible) for generate the expected tooltip.
Does anyone knows what I'm missing?
After testing for a few more hours, I finally decided to follow these steps:
Generate/render the world chart in a file - in this case, a .svg file.
Read the generated file in the previous step, find and replace certain svg tags - those that contains the data I don't want in the final chart.
Download the modified file.
The said svg tags are as follows:
Example:
<desc class="value">Russian Federation: 1</desc>
Thanks to this answer, I was able to replace the svg tags and leave them empty. With that change, I was able to generate the world map chart as I required.
This is the full, modified and working code:
import types
# Library import:
from pygal_maps_world.maps import World
from pygal.style import DefaultStyle
worldmap_chart = World()
worldmap_chart.title = 'Channels distribution per country'
#list - source: https://stackoverflow.com/a/26716774/12511801
# Excludes "N/A" values:
countriesData = df_countries.loc[df_countries['Country (channel)'] != "N/A"].to_dict('split')["data"]
# Loop the "countriesData" and replace the name of the country
# with is ISO code - lowercase - in order to render the world map:
for x in countriesData:
countryName = x[0]
countryName = [x["id"].lower() for x in all_countries if x["name"] == countryName][0]
x[0] = countryName
# Strings to replace:
js_strings = []
# Generate world map chart:
#worldmap_chart.add('Countries', dict(countriesData))
for data in countriesData:
countryFound = [x["name"] for x in all_countries if x["id"].lower() == data[0]]
if (len(countryFound) > 0):
countryFound = countryFound[0]
worldmap_chart.add(countryFound, [{"value": data[0], "label" : (str(data[1]) + " video" + ("s" if data[1] != 1 else ""))}])
js_strings.append('<desc class="value">{0}: 1</desc>'.format(countryFound))
# Save chart as svg - comment this line for print the chart in this notebook:
worldmap_chart.render_to_file('chart_final_4.svg',
show_legend=True,
human_readable=True,
fill=True,
print_labels=True,
no_data_text="No data available",
legend_at_bottom=True,
pretty_print=True,
x_title="Hover the cursor on the country's name bellow or the map above:",
print_values=True)
print("Chart saved in local storage - see file (chart_final_4.svg).")
# Render the chart in the notebook:
HTML_worldChart = str(worldmap_chart.render(show_legend=True, human_readable=True,
fill=True, print_labels=True,
no_data_text="No data available",
legend_at_bottom=True,
print_values=True, style=DefaultStyle(value_font_family='googlefont:Raleway',
value_font_size=30,
value_colors=('white',))))
# Source: https://stackoverflow.com/a/62008698/12511801
from pathlib import Path
file = Path("chart_final_4.svg")
# Replace specific, conflicting countries by name:
file.write_text(file.read_text().replace('<desc class="value">Korea, Republic of: 1</desc>', '<desc class="value"></desc>'))
file.write_text(file.read_text().replace('<desc class="value">Russian Federation: 1</desc>', '<desc class="value"></desc>'))
file.write_text(file.read_text().replace('<desc class="value">Viet Nam: 1</desc>', '<desc class="value"></desc>'))
## This is due those countries are arranged as follows:
##--country (<desc class="value">Russia: 1</desc>) no detected
##--country (<desc class="value">Vietnam: 1</desc>) no detected
##--country (<desc class="value">South Korea: 1</desc>) no detected
# Loop the strings to replace:
for country in js_strings:
file.write_text(file.read_text().replace(country, '<desc class="value"></desc>'))
print("(chart_final_4.svg) has been modified.")
Output: world map chart modified - I'm modified the screenshot for include two tooltips at the same time.
Side note: it might not be the best way, but, for a lack of time and knowledge, I've decided to leave it as is. I'm open to any, better suggestions.

Getting ipywidgets to update a folium heatmap?

Beginner python user, having some success with heatmaps using Folium. I am experimenting with using the Global Terrorism Database as a source for some visualizations but I really wanted to use ipywidgets to select a specific terrorist group from a list to update my heatmap. I've already constructed a heatmap for ISIS, created an ipyvuetify button containing the groups I want to compare, but am having trouble figuring out the function and widgets.link syntax. I'd really appreciate some help because there don't seem to be any good guides (for my skill level) on how to do what I'm trying to do here.
import ipyvuetify as v
import ipywidgets as widgets
import folium
from folium import plugins
from folium.plugins import HeatMap as hm
map = folium.Map(location = [25,15], tiles = "cartodbdark_matter", zoom_start = 2)
selected = gtd.loc[gtd['Group'] == 'Islamic State of Iraq and the Levant (ISIL)']
coords = selected[['Latitude','Longitude']]
hm(coords).add_to(map)
terrorists = [
'Taliban',
'Shining Path (SL)',
'Islamic State of Iraq and the Levant (ISIL)',
'Farabundo Marti National Liberation Front (FMLN)',
'Al-Shabaab',
'Irish Republican Army (IRA)',
'Revolutionary Armed Forces of Colombia (FARC)',
'New Peoples Army (NPA)',
'Kurdistan Workers Party (PKK)',
'Boko Haram']
# This is where things go off the rails for me, not exactly sure how to arrange this function
def update(x):
if widget_terrorist_selector.selected is not None:
xmin, xmax = widget_terrorist_selector.selected
widget_terrorist_selector.observe(update,'widget_terrorist_selector')
# The selector here works but I can't figure out how to link it to my map so that it pushes a new set of heatmap coordinates
widget_terrorist_selector = v.Select(label='Choose Option', items=terrorists, v_model=terrorists[0])
widget_terrorist_selector
# This bit keeps throwing a "TypeError: Each object must be HasTraits, not <class 'pandas.core.frame.DataFrame'>"
widgets.link((widget_terrorist_selector,'v_model'),(selected, 'Group'))
Thanks in advance!
widgets.link is used for keeping two ipywidgets in sync. I'm not sure that's what you're trying to achieve here, it can probably be achieved with plain old observe.
I think in your update function you need to make the necessary change to your map, something like
def update(x):
new_choice = widget_terrorist_selector.selected
selected = gtd.loc[gtd['Group'] == new_choice]
coords = selected[['Latitude','Longitude']]
hm(coords).add_to(map)

How can I highlight multiple search results in Python folium/leaflet?

I have plotted graph in Python using folium/Leaflet with search. Problem I am facing is that it highlights only one result on map even if there are multiple results.
For example if I search by name then it works fine as mostly there is only 1 person with that full name.
But if I search on a city for example 'Delhi' then it results in highlighting only 1 marker instead of 7 or 10.
In the image below: There is only 1 marker circled in red which it is pointing as result but there others from same city which are not highlighted.
And how can I change highlighting properties to something more noticeable?
Image:
Here is the code:
######################################################################
# Part 1 - Creating map
m_search = folium.Map(location=[28.6003435, 77.21952300000001],zoom_start=11
)
#######################################################################
# Part 2 - Creating folium markers on map with html text, images
# etc dynamically for multiple points using for-loop
for plot_numb in range(gdf.shape[0]):
icon = folium.Icon(color="blue", icon="cloud", icon_color='white')
tooltip = 'Click to view more about: '+gdf.iloc[plot_numb,0]
var_name = gdf.iloc[plot_numb,0]
var_loc = gdf.iloc[plot_numb,2]
pic = base64.b64encode(open('Images/'+gdf.iloc[plot_numb,5],'rb').read()).decode()
html = f'''<img ALIGN="Right" src="data:image/png;base64,{pic}">\
<strong>Name: </strong>{var_name}<br /><br />\
<strong>Location: </strong>{var_loc}<br /><br />\
'''
html
iframe = IFrame(html, width=300+180, height=300)
popup = folium.Popup(iframe, max_width=650)
marker = folium.Marker(location=gdf.iloc[plot_numb,1], popup=popup, tooltip=tooltip, icon=icon).add_to(m_search)
########################################################################
# Part 3 - Creating Markers using GeoJson, creating search
# creating folium GeoJson objects from out GeoDataFrames
pointgeo = folium.GeoJson(gdf,name='group on map', show=False,
tooltip=folium.GeoJsonTooltip(fields=['Name', 'Relation', 'City'], aliases=['Name','Relation', 'City'],
localize=True)).add_to(m_search)
# Add some Search boxes to the map that reference the GeoDataFrames with some different parameters passed to the
# arguments.
pointsearch = Search(layer=pointgeo, geom_type='Point',
placeholder='Search for contacts', collapsed=False,
search_label='Name').add_to(m_search)
# To Add a LayerControl add below line
folium.LayerControl().add_to(m_search)
m_search
Below is the example of the gdf Data Frame:
Name Location City Relation Relation Detail Image Lat Lon geometry
0 abc [28.562193, 77.387073] Noida Cousin Cousin 1.png 28.562193 77.387073 POINT (77.387073 28.562193)
1 def [28.565282027743955, 77.44913935661314] Noida Cousin Cousin Brother 2.png 28.565282 77.449139 POINT (77.44913935661314 28.56528202774395)
3 ghi [28.6206996683473, 77.42576122283936] Noida Cousin Cousin Brother 4.png 28.620700 77.425761 POINT (77.42576122283936 28.6206996683473)
Need some help here as I am new to coding and unable to figure out.

list of string to list of colorlover

I have a list of 100 strings and I would like to convert them to a list of colorlover colors to be able to use them in plot.py. I have tried multiple options but it always gives me a different color for the same string. The function should work like:
hash(string) - > colorlover
Any ideas. ?
Here the list of Strings:
XIC-FWHM-Q1
XIC-FWHM-Q2
XIC-FWHM-Q3
XIC-Height-Q2
XIC-Height-Q3
RT-Duration
RT-TIC-Q1
...
colorlover scale [RdYlBu] would be good.
ryb = cl.scales['3']['div']['RdYlBu']; ryb
['rgb(252,141,89)', 'rgb(255,255,191)', 'rgb(145,191,219)']
I want to implement a PCA analysis like this https://plot.ly/ipython-notebooks/principal-component-analysis/ But I have 100's of columns with classes category (Strings) that I need to associate with colors. Then I can't add the colors manually like in the example.
Looks like colorlover is actually a python library. It does the string conversion and you don't need to create separate logic for that.
Here is a link to the documentation and here is a link showing examples of the strings used for generating colour scales.
UPDATE
If you want to define your own colours, this may be a good starting point. Others may have more experience in this.
UPDATE 2
If you need to generate many colours, check link which walks you through setting colorscales for your variables in Python and Plotly. The colorscale for Scatter Plots section may be a good starting point.
I managed to generate a large list of rgb values using the following code:
import colorlover as cl
import pprint
pprint.pprint(cl.scales["3"])
This produced the following list, from which you can select the rgb values you wish to use:
{'div': {'BrBG': ['rgb(216,179,101)', 'rgb(245,245,245)', 'rgb(90,180,172)'],
'PRGn': ['rgb(175,141,195)', 'rgb(247,247,247)', 'rgb(127,191,123)'],
'PiYG': ['rgb(233,163,201)', 'rgb(247,247,247)', 'rgb(161,215,106)'],
'PuOr': ['rgb(241,163,64)', 'rgb(247,247,247)', 'rgb(153,142,195)'],
'RdBu': ['rgb(239,138,98)', 'rgb(247,247,247)', 'rgb(103,169,207)'],
'RdGy': ['rgb(239,138,98)', 'rgb(255,255,255)', 'rgb(153,153,153)'],
'RdYlBu': ['rgb(252,141,89)', 'rgb(255,255,191)', 'rgb(145,191,219)'],
'RdYlGn': ['rgb(252,141,89)', 'rgb(255,255,191)', 'rgb(145,207,96)'],
'Spectral': ['rgb(252,141,89)',
'rgb(255,255,191)',
'rgb(153,213,148)']},
'qual': {'Accent': ['rgb(127,201,127)',
'rgb(190,174,212)',
'rgb(253,192,134)'],
'Dark2': ['rgb(27,158,119)', 'rgb(217,95,2)', 'rgb(117,112,179)'],
'Paired': ['rgb(166,206,227)', 'rgb(31,120,180)', 'rgb(178,223,138)'],
'Pastel1': ['rgb(251,180,174)',
'rgb(179,205,227)',
'rgb(204,235,197)'],
'Pastel2': ['rgb(179,226,205)',
'rgb(253,205,172)',
'rgb(203,213,232)'],
'Set1': ['rgb(228,26,28)', 'rgb(55,126,184)', 'rgb(77,175,74)'],
'Set2': ['rgb(102,194,165)', 'rgb(252,141,98)', 'rgb(141,160,203)'],
'Set3': ['rgb(141,211,199)', 'rgb(255,255,179)', 'rgb(190,186,218)']},
'seq': {'Blues': ['rgb(222,235,247)', 'rgb(158,202,225)', 'rgb(49,130,189)'],
'BuGn': ['rgb(229,245,249)', 'rgb(153,216,201)', 'rgb(44,162,95)'],
'BuPu': ['rgb(224,236,244)', 'rgb(158,188,218)', 'rgb(136,86,167)'],
'GnBu': ['rgb(224,243,219)', 'rgb(168,221,181)', 'rgb(67,162,202)'],
'Greens': ['rgb(229,245,224)', 'rgb(161,217,155)', 'rgb(49,163,84)'],
'Greys': ['rgb(240,240,240)', 'rgb(189,189,189)', 'rgb(99,99,99)'],
'OrRd': ['rgb(254,232,200)', 'rgb(253,187,132)', 'rgb(227,74,51)'],
'Oranges': ['rgb(254,230,206)', 'rgb(253,174,107)', 'rgb(230,85,13)'],
'PuBu': ['rgb(236,231,242)', 'rgb(166,189,219)', 'rgb(43,140,190)'],
'PuBuGn': ['rgb(236,226,240)', 'rgb(166,189,219)', 'rgb(28,144,153)'],
'PuRd': ['rgb(231,225,239)', 'rgb(201,148,199)', 'rgb(221,28,119)'],
'Purples': ['rgb(239,237,245)',
'rgb(188,189,220)',
'rgb(117,107,177)'],
'RdPu': ['rgb(253,224,221)', 'rgb(250,159,181)', 'rgb(197,27,138)'],
'Reds': ['rgb(254,224,210)', 'rgb(252,146,114)', 'rgb(222,45,38)'],
'YlGn': ['rgb(247,252,185)', 'rgb(173,221,142)', 'rgb(49,163,84)'],
'YlGnBu': ['rgb(237,248,177)', 'rgb(127,205,187)', 'rgb(44,127,184)'],
'YlOrBr': ['rgb(255,247,188)', 'rgb(254,196,79)', 'rgb(217,95,14)'],
'YlOrRd': ['rgb(255,237,160)', 'rgb(254,178,76)', 'rgb(240,59,32)']}}
If you just wanted to generate colours in the RdYlBu spectrum, use the following code:
print(cl.scales["11"]["div"]["RdYlBu"])
this gives:
['rgb(165,0,38)',
'rgb(215,48,39)',
'rgb(244,109,67)',
'rgb(253,174,97)',
'rgb(254,224,144)',
'rgb(255,255,191)',
'rgb(224,243,248)',
'rgb(171,217,233)',
'rgb(116,173,209)',
'rgb(69,117,180)',
'rgb(49,54,149)']
The only problem i found was that the highest number i could use was 11, and got an error message for any value above that.I'm guessing that is the entire colour spectrum for RdYlBu.
Good luck with your project.

Defining our own colors (RGB ?) for Intra-paragraph markup color in reportlab

For generating PDF files with reportlab / python, it is possible to define very easily the color of a text (and lot other things) by using the so called "Paragraph XML Markup Tags". For example a green text:
rapport.append(Paragraph('<font size = 14 color = "green" > <b> Toto is a naugthy boy </b></font>', styles['Left']))
But, is it possible to define our own color (for example by using RGB code) ?
It is actually really straightforward, you can just replace green with any hex RGB color like #424242. So in your example it will look like this:
rapport.append(Paragraph('<font size=14 color="#424242"><b>Toto is a naugthy boy</b></font>', styles['Left']))
But it is also possible to use most of the HTML colors like:
rapport.append(Paragraph('<font size=14 color="rgb(191, 255, 0)"><b>Toto is a naugthy boy</b></font>', styles['Left']))
rapport.append(Paragraph('<font size=14 color="hsl(75, 100%, 50%)"><b>Toto is a naugthy boy</b></font>', styles['Left']))

Categories

Resources