我有一个数据集,我想通过 python 的 folium 模块将其放在传单地图上。
这是我的代码:
import xyzservices.providers as xyz
TONER_URL = xyz["Stamen"]["Toner"].url
print(TONER_URL)
ATTRIB = xyz.Stamen.Toner.attribution
import folium
#xyz.Stamen.Toner.requires_token() Doesn't require token
import pandas as pd
#Set up details
centre_of_map = [54.16481107197051, -1.9009676842692447]
mgd_dict = """{'surname': {0: 'Peach', 1: 'Lewis', 2: 'Price', 3: 'Purslow', 4: 'Stringer'},
'forename': {0: '', 1: '', 2: '', 3: 'Benjamin Thomas', 4: 'Thomas'},
'initials': {0: 'H', 1: 'H', 2: 'W T', 3: 'B T', 4: 'T'},
'age_text': {0: '0', 1: '28', 2: '0', 3: '21', 4: '29'},
'honours_awards': {0: nan, 1: nan, 2: nan, 3: nan, 4: nan},
'date_of_death': {0: 'August 29th, 1914',
1: 'September 02th, 1914',
2: 'September 03th, 1914',
3: 'September 10th, 1914',
4: 'September 11th, 1914'},
'date_of_death2': {0: NaT, 1: NaT, 2: NaT, 3: NaT, 4: NaT},
'rank': {0: 'Private',
1: 'Private',
2: 'Private',
3: 'Private',
4: 'Private'},
'regiment': {0: 'North Staffordshire Regiment',
1: 'South Staffordshire Regiment',
2: 'South Staffordshire Regiment',
3: 'South Staffordshire Regiment',
4: 'South Staffordshire Regiment'},
'unitshipsquadron': {0: '1st Bn.',
1: '2nd Bn.',
2: '2nd Bn.',
3: '2nd Bn.',
4: '2nd Bn.'},
'country': {0: 'United Kingdom',
1: 'France',
2: 'France',
3: 'France',
4: 'France'},
'servicenumberExport': {0: "'7610'",
1: "'7409'",
2: "'7944'",
3: "'9325'",
4: "'6875'"},
'cemeterymemorial': {0: 'CAMBRIDGE CITY CEMETERY',
1: 'PERREUSE CHATEAU FRANCO BRITISH NATIONAL CEMETERY',
2: 'ROYALLIEU FRENCH NATIONAL CEMETERY, COMPIEGNE',
3: 'LA FERTE-SOUS-JOUARRE MEMORIAL',
4: 'LA FERTE-SOUS-JOUARRE MEMORIAL'},
'gravereference': {0: 'D. 2596.',
1: '1. B. 18.',
2: 'Sp. Mem. 4.',
3: nan,
4: nan},
'additionalinformation': {0: '',
1: 'Son of William Lewis, of Edgbaston, Birmingham.',
2: '',
3: 'Son of Thomas Purslow, of 42, Church Lane, Wolverhampton.',
4: 'Son of Mrs. Mary Jane Stringer, of 37, Blue Lane, West, Walsall, Staffs.'},
'name': {0: 'Cambridge City Cemetery',
1: 'Perreuse Chateau Franco British National Cemetery',
2: 'Royallieu French National Cemetery, Compiegne',
3: 'La Ferte-Sous-Jouarre Memorial',
4: 'La Ferte-Sous-Jouarre Memorial'},
'Longitude': {0: 0.16699, 1: 3.08655, 2: 2.81353, 3: 3.12415, 4: 3.12415},
'Latitude': {0: 52.21324, 1: 48.91742, 2: 49.40332, 3: 48.94338, 4: 48.94338}}"""
mgd_dict = mgd_dict.replace("nan", "'Nothing to see'")
mgd_dict = mgd_dict.replace("NaT", "'Nothing to see'")
import ast
mgd_dict = mgd_dict.replace("pd.NaT", "Nothing to see")
mgd_dict = ast.literal_eval(mgd_dict)
mgd = pd.DataFrame(mgd_dict)
mgd = mgd.drop(columns=['date_of_death2', 'servicenumberExport', 'gravereference', 'honours_awards', 'initials'])
mgd = mgd.fillna("")
#Clean up data
#Title case
mgd['additionalinformation'] = mgd.additionalinformation.str.title()
mgd.additionalinformation = mgd.additionalinformation.str.replace("And ", "and ")
mgd.additionalinformation = mgd.additionalinformation.str.replace("Of ", "of ")
mgd.additionalinformation = mgd.additionalinformation.fillna("")
#Set the location of missing values of soldiers not attached to specific memorial to the National Memorial Arboretum at Alrewas at 52.726 -1.728
mgd.Latitude = mgd.Latitude.fillna(52.726)
mgd.Longitude = mgd.Longitude.fillna(-1.728)
mgd['name'] = mgd['name'].fillna("National Memorial Arboretum ")
mgd['name'] = mgd['name'].str.title()
mgd['forename'] = mgd['forename'].fillna("")
mgd['age_text'] = mgd['age_text'].fillna(0)
mgd['age_text'] = mgd['age_text'].astype("int")
mgd['age_text'] = mgd['age_text'].astype("str")
mgd['date_of_death'] = pd.to_datetime(mgd['date_of_death'], errors='coerce')
mgd['date_of_death'] = mgd['date_of_death'].dt.strftime('%B %dth, %Y')
# Create a function to format each biography
def format_biography(group):
# Calculate the count of men at the memorial site
count = group['name'].size
# Calculate the latitude and longitude for the site
latitude = group['Latitude'].mean()
longitude = group['Longitude'].mean()
# Construct the header for each memorial site
header = f"<h3>{group['name'].iloc[0]}</h3>\n<p>There are {count} men commemorated here.</p>\n"
# Construct the formatted biographies
biographies = group.apply(
lambda row: f"<p>{row['rank']} <b>{row['forename']} {row['surname']}</b>, died on {row['date_of_death']}" +
(f" aged {row['age_text']}" if row['age_text'] != 0 else '') +
f". He served with {row['unitshipsquadron']} of the {row['regiment']}. {row['additionalinformation']}</p>\n",
axis=1
)
# Concatenate header and biographies
return pd.Series({
'biography': header + "<p>-------</p>\n".join(biographies),
'count': count,
'Latitude': latitude,
'Longitude': longitude
})
# Group by 'memorial_site' and aggregate with the custom function
condensed_df = mgd.groupby('name').apply(format_biography).reset_index()
condensed_df
m = folium.Map(location=centre_of_map, zoom_start=5, tiles=TONER_URL, attr=ATTRIB)
for index, row in condensed_df.iterrows():
popup_content = f"<div style='max-height: 200px; overflow-y: auto;'>{row['biography']}</div>"
popup = folium.Popup(popup_content, max_width=300)
folium.Circle(
location=[row['Latitude'], row['Longitude']], # Latitude and longitude columns
radius=row['count'] * 2.5, # Define your radius
color='red', # Define circle color
fill=True,
fill_color='red', # Define fill color
fill_opacity=0.6,
popup=popup # Customize your info window content
).add_to(m)
m
如果我取出图块和 attr 参数,它就可以工作,但我想要 Stamen Toner。
自 2023 年 11 月起,Stamen 不再托管地图。请参阅https://maps.stamen.com/stadia-partnership/。如果他们删除常见问题解答,则实质上是说由于成本原因,他们不再托管地图图块,但用户可以使用以下约定下载图块:
每个图块都可以通过以下格式的 S3 URL 访问:
s3://{bucket}{prefix}/{z}/{x}/{y}.{extension}
例如,要获取缩放 2、x 3 和 y 1 的水彩图块,您可以使用:
s3://long-term.cache.maps.stamen.com/watercolor/2/3/1.jpg