Python error when adding a add_child in folium - python
I have the following script. However, I'm getting an error that points are the data I'm passing to the location parameter. When printing this, I'm getting what location generally receives.
Here is an example of the txt info: VOLCANX020,NUMBER,NAME,LOCATION,STATUS,ELEV,TYPE,TIMEFRAME,LAT,LON
509.000000000000000,1201-01=,Baker,US-Washington,Historical,3285.000000000000000,Stratovolcanoes,D3,48.7767982,-121.8109970
import folium
import pandas as pd
map = folium.Map(location=[38.58, -99.09], zoom_start=4, tiles = "Stamen Terrain")
# Reads the data
df_volcanos = pd.read_csv('Volcanoes.txt')
fg_volcanoes=folium.FeatureGroup(name="Volcanos Map")
fg_population=folium.FeatureGroup(name='Populations')
for index, data in df_volcanos.head(1).iterrows():
fg_volcanoes.add_child(folium.CircleMarker(location=data[['LAT','LON']].values,
radius=6,
popup=f"{data['ELEV']} mts",
fill_color='green' if data['ELEV'] < 1000 else 'orange' if data['ELEV'] < 3000 else 'red',
color="grey",
fill_opacity=1))
map.add_child(folium.LayerControl())
map.save('Map2.html')
My modification is to make the circle marker itself belong to a group and add that group to the map. Also, in the sequential processing of the data frame, I did not use indexes to specify rows, so I used .loc to limit the rows. At the same time, I also modified the row specification in the popup.
import folium
m = folium.Map(location=[38.58, -99.09], zoom_start=4, tiles="Stamen Terrain")
fg_volcanoes=folium.FeatureGroup(name="Volcanos Map")
fg_population=folium.FeatureGroup(name='Populations')
for index, data in df_volcanos.head(1).iterrows():
color = 'green' if df_volcanos.loc[index,'ELEV'] < 1000 else 'orange' if df_volcanos.loc[index, 'ELEV'] > 3000 else 'red'
#fg_volcanoes.add_child(
folium.CircleMarker(
location=df_volcanos[['LAT','LON']].values[0].tolist(),
radius=6,
popup=f"{df_volcanos.loc[index,'ELEV']} mts",
fill_color=color,
color="grey",
fill_opacity=1
).add_to(fg_volcanoes)
#)
fg_volcanoes.add_to(m)
m.add_child(folium.LayerControl())
#m.save('Map2.html')
m
Related
python folium polygons map color categories
I have a dataframe in Python containing zipcodes (4 digits), pologyons, and would like to create maps with colored zipcodes based on a column value. I tried this with the geopandas and folium packages but it seems to be not working. The shapefigures I downloaded from this website https://www.cbs.nl/nl-nl/dossier/nederland-regionaal/geografische-data/gegevens-per-postcode . The shapefile seems to work when I use this code: file_path = r'C:\xxxx\CBS_pc4_2020_v1.shp' gdf_zipcodes = gpd.read_file(file_path) fig, ax = plt.subplots(figsize=(8,8)) gdf_zipcodes.plot(ax=ax, facecolor='none', edgecolor='gray') plt.show() Currently, this is (part of) my dataframe zipcodes = Zipcode Var Location Allocation 9941 o Polygon 7023 7023 o Polygon 7023 6321 o Multipolygon 4020 I also have a location dataframe containing zipcodes and specific lon & latitudes like this: loc_df = Zipcode lat lon 9941 xxx yyy 7231 xxx yyy What does work is creating a map with these specific coordinates, this is the code I used: map = folium.Map(location =[loc_df['lat'].mean(),loc_df['lon'].mean()], zoom_start=12) step = cm.StepColormap(colors, vmin = 0, vmax = 9999, index = [], caption = 'step') color_pallete = sns.color_palette() color_pallete = sns.color_palette("Set2", 99999) color_pallete = color_pallete.as_hex() for index, row in results_1.iterrows(): if row['Var'] == 'o': folium.Marker([row['lat'], row['lon']], popup = row['Variable Name']).add_to(map) if row['Var'] == 'x': c = color_pallete[int(row['Allocation'])] folium.CircleMarker([row['lat'], row['lon']],radius=5, color = c).add_to(map) else: continue folium.CircleMarker( location=[row['lon'], row['lat']], radius=12, weight=2, fill=True, fill_color=colors[int(row['cluster'])], color=colors[int(row['cluster'])] ).add_to(map) map.save('map1.html') Then, I thought this code would work to use the pologyons instead of specific lat and lon values to create the map but unfortunately it does not: for _, r in zipcodes.iterrows(): # Without simplifying the representation of each borough, # the map might not be displayed sim_geo = gpd.GeoSeries(r['geometry']).simplify(tolerance=0.001) geo_j = sim_geo.to_json() geo_j = folium.GeoJson(data=geo_j, style_function=lambda x: {'fillColor': 'blue'}) folium.Popup(r['Location']).add_to(geo_j) geo_j.add_to(map) In the end I would like to color based on the allocation of the dataframe and create markers such as in the first folium map but for now I would really like to visualize the polygons (and hopefully I can find out how I create the colors after that).
How to add Cluster markers to Choropleth with Folium
I've been working for a while with Choropleth and Cluster marker maps in Folium (which are great). My question is whether it is possible to combine them in one map, which is so that I can see how much one variable affects another. I can get both map types to work individually so no problems there. This is my attempted code to combine the two so far: import pandas as pd import folium from folium.plugins import MarkerCluster input_filename="input_filename.csv" df = pd.read_csv(input_filename,encoding='utf8') geo = 'blah.json' comparison = 'comparison.csv' comparison_data = pd.read_csv(comparison) m = folium.Map(location=[Lat,Lon], zoom_start=12) folium.Choropleth( geo_data=geo, name='choropleth', data=comparison_data, columns=['col1','col2'], key_on='feature.properties.ID', fill_color='OrRd', fill_opacity=0.5, line_opacity=0.5, legend_name='Blah (%)' ).add_to(m) folium.LayerControl().add_to(m) marker_cluster = MarkerCluster().add_to(m) for row in df.itertuples(): folium.Marker(location=[row.Lat,row.Lon],popup=row.Postcode).add_to(marker_cluster) m It produces the choropleth but won't layer the cluster markers as well. Worth noting that I've had a problem with cluster markers separately where they wouldn't display in Jupyter notebook, but I got around it by saving the file as an html, which was then viewable.
Ok so I've solved it, really pleased!! The solution was to do the marker cluster first, and then follow-up with the Choropleth: import pandas as pd import folium from folium.plugins import MarkerCluster m = folium.Map(location=[Lat,Lon], zoom_start=12) input_filename="input_filename.csv" df = pd.read_csv(input_filename,encoding='utf8') geo = 'blah.json' comparison = 'comparison.csv' comparison_data = pd.read_csv(comparison) folium.LayerControl().add_to(m) marker_cluster = MarkerCluster().add_to(m) for row in df.itertuples(): folium.Marker(location=[row.Lat,row.Lon],popup=row.Postcode).add_to(marker_cluster) folium.Choropleth( geo_data=geo, name='choropleth', data=comparison_data, columns=['col1','col2'], key_on='feature.properties.ID', fill_color='OrRd', fill_opacity=0.5, line_opacity=0.5, legend_name='Blah (%)' ).add_to(m) m
from random import randint import folium def rgb_to_hex(rgb): return '#%02x%02x%02x' % rgb mp = folium.Map(location=[40.6, -73.7], scale = 10) colors = [] while len(colors) != 50: r = randint(0, 255) g = randint(0, 255) b = randint(0, 255) if rgb_to_hex((r, g, b)) not in colors: colors.append(rgb_to_hex((r, g, b))) for j in range(df.shape[0]): lat = df.iloc[j]['latitude'] lon = df.iloc[j]['longitude'] color = colors[int(df.iloc[j]['clust'])] folium.Circle(location=[lat, lon], radius=8, color = color).add_to(mp)
How to highlight multiline graph in Altair python
I'm trying to create an interactive timeseries chart with more than 20 lines of data using the Altair module in Python. The code to create the dataframe of the shape I'm looking at is here: import numpy as np import altair as alt year = np.arange(1995, 2020) day = np.arange(1, 91) def gen_next_number(previous, limit, max_reached): if max_reached: return np.NAN, True increment = np.random.randint(0, 10) output = previous + increment if output >= 100: output = 100 max_reached = True return output, max_reached def gen_list(): output_list = [] initial = 0 limit = 100 max_reached = False value = 0 for i in range(1, 91): value, max_reached = gen_next_number(value, limit, max_reached) if max_reached: value = np.NAN output_list.append(value) return output_list df = pd.DataFrame(index = day, columns=year ) for y in year: data = gen_list() df[y] = data df['day'] = df.index df = df.melt("day") df = df.dropna(subset=["value"]) I can use the following Altair code to produce the initial plot, but it's not pretty: alt.Chart(df).mark_line().encode( x='day:N', color="variable:N", y='value:Q', tooltip=["variable:N", "value"] ) But when I've tried this code to create something interactive, it fails: highlight = alt.selection(type='single', on='mouseover', fields='variable', nearest=True, empty="none") alt.Chart(plottable).mark_line().encode( x='day:N', color="variable:N", y=alt.condition(highlight, 'value:Q', alt.value("lightgray")), tooltip=["variable:N", "value"] ).add_selection( highlight ) It fails with the error: TypeError: sequence item 1: expected str instance, int found Can someone help me out? Also, is it possible to make the legend interactive? So a hover over a year highlights a line?
Two issues: In alt.condition, you need to provide a list of fields rather than a single field The y encoding does not accept a condition. I suspect you meant to put the condition on color. With these two fixes, your chart works: highlight = alt.selection(type='single', on='mouseover', fields=['variable'], nearest=True, empty="none") alt.Chart(df).mark_line().encode( x='day:N', y='value:Q', color=alt.condition(highlight, 'variable:N', alt.value("lightgray")), tooltip=["variable:N", "value"] ).add_selection( highlight ) Because the selection doesn't change z-order, you'll find that the highlighted line is often hidden behind other gray lines. If you want it to pop out in front, you could use an approach similar to the one in https://stackoverflow.com/a/55796860/2937831
I would like to create a multi-line plot similar to the one above without a legend without hovering or mouseover. Would simply like to pass a highlighted_value and have a single line be highlighted. I have modified the code because I am not terribly familiar with the proper use of "selection" and recognize that it is somewhat kludgy to get the result that I want. Is there a cleaner way to do this? highlight = alt.selection(type='single', on='mouseover', fields=['variable'], nearest=True, empty="none") background = alt.Chart(df[df['variable'] != 1995]).mark_line().encode( x='day:N', y='value:Q', color=alt.condition( highlight, 'variable:N', alt.value("lightgray")), tooltip=["variable:N", "value"], ).add_selection( highlight ) foreground = alt.Chart(df[df['variable'] == 1995]).mark_line(color= "blue").encode( x='day:N', y='value:Q', color=alt.Color('variable',legend=None) ) foreground + background
How Can I Render More Than 1000 Points in Folium
I am trying to render 15,000 points in folium. When I have less than 1000 points I get a map that renders as the attached image (example map). When I include over 1000 my code returns an item void of either a map or points. The following is my code: z230['marker_color'] = pd.cut(z230['ClosePrice'], bins=5, labels=['blue','green','yellow','orange','red']) m = folium.Map(location=[39.2904, -76.6122], zoom_start=12) for index, row in z230.iterrows(): folium.CircleMarker([row['Latitude'], row['Longitude']], radius=15, color=row['marker_color']).add_to(m) m
The only useful workaround I could find was to include cluster markers. from folium.plugins import FastMarkerCluster x = #your centering coordinates here LAT y = #your centering coordinates here LONG z = #your zoomlevel here your_map = folium.Map(location=[x, y], tiles="OpenStreetMap", zoom_start=z) callback = ('function (row) {' 'var circle = L.circle(new L.LatLng(row[0], row[1]), {color: "red", radius: 10000});' 'return circle};') your_map.add_child(FastMarkerCluster(your_df[['your_LAT_col', 'your_LONG_col']].values.tolist(), callback=callback)) your_map
Adding a single label to the legend for a series of different data points plotted inside a designated bin in Python using matplotlib.pyplot.plot()
I have a script for plotting astronomical data of redmapping clusters using a csv file. I could get the data points in it and want to plot them using different colors depending on their redshift values: I am binning the dataset into 3 bins (0.1-0.2, 0.2-0.25, 0.25,0.31) based on the redshift. The problem arises with my code after I distinguish to what bin the datapoint belongs: I want to have 3 labels in the legend corresponding to red, green and blue data points, but this is not happening and I don't know why. I am using plot() instead of scatter() as I also had to do the best fit from the data in the same figure. So everything needs to be in 1 figure. import numpy as np import matplotlib.pyplot as py import csv z = open("Sheet4CSV.csv","rU") data = csv.reader(z) x = [] y = [] ylow = [] yupp = [] xlow = [] xupp = [] redshift = [] for r in data: x.append(float(r[2])) y.append(float(r[5])) xlow.append(float(r[3])) xupp.append(float(r[4])) ylow.append(float(r[6])) yupp.append(float(r[7])) redshift.append(float(r[1])) from operator import sub xerr_l = map(sub,x,xlow) xerr_u = map(sub,xupp,x) yerr_l = map(sub,y,ylow) yerr_u = map(sub,yupp,y) py.xlabel("$Original\ Tx\ XCS\ pipeline\ Tx\ keV$") py.ylabel("$Iterative\ Tx\ pipeline\ keV$") py.xlim(0,12) py.ylim(0,12) py.title("Redmapper Clusters comparison of Tx pipelines") ax1 = py.subplot(111) ##Problem starts here after the previous line## for p in redshift: for i in xrange(84): p=redshift[i] if 0.1<=p<0.2: ax1.plot(x[i],y[i],color="b", marker='.', linestyle = " ")#, label = "$z < 0.2$") exit if 0.2<=p<0.25: ax1.plot(x[i],y[i],color="g", marker='.', linestyle = " ")#, label="$0.2 \leq z < 0.25$") exit if 0.25<=p<=0.3: ax1.plot(x[i],y[i],color="r", marker='.', linestyle = " ")#, label="$z \geq 0.25$") exit ##There seems nothing wrong after this point## py.errorbar(x,y,yerr=[yerr_l,yerr_u],xerr=[xerr_l,xerr_u], fmt= " ",ecolor='magenta', label="Error bars") cof = np.polyfit(x,y,1) p = np.poly1d(cof) l = np.linspace(0,12,100) py.plot(l,p(l),"black",label="Best fit") py.plot([0,15],[0,15],"black", linestyle="dotted", linewidth=2.0, label="line $y=x$") py.grid() box = ax1.get_position() ax1.set_position([box.x1,box.y1,box.width, box.height]) py.legend(loc='center left',bbox_to_anchor=(1,0.5)) py.show() In the 1st 'for' loop, I have indexed every value 'p' in the list 'redshift' so that bins can be created using 'if' statement. But if I add the labels that are hashed out against each py.plot() inside the 'if' statements, each data point 'i' that gets plotted in the figure as an intersection of (x[i],y[i]) takes the label and my entire legend attains in total 87 labels (including the 3 mentioned in the code at other places)!!!!!! I essentially need 1 label for each bin... Please tell me what needs to done after the bins are created and py.plot() commands used...Thanks in advance :-) Sorry I cannot post my image here due to low reputation! The data 'appended' for x, y and redshift lists from the csv file are as follows: x=[5.031,10.599,10.589,8.548,9.089,8.675,3.588,1.244,3.023,8.632,8.953,7.603,7.513,2.917,7.344,7.106,3.889,7.287,3.367,6.839,2.801,2.316,1.328,6.31,6.19,6.329,6.025,5.629,6.123,5.892,5.438,4.398,4.542,4.624,4.501,4.504,5.033,5.068,4.197,2.854,4.784,2.158,4.054,3.124,3.961,4.42,3.853,3.658,1.858,4.537,2.072,3.573,3.041,5.837,3.652,3.209,2.742,2.732,1.312,3.635,2.69,3.32,2.488,2.996,2.269,1.701,3.935,2.015,0.798,2.212,1.672,1.925,3.21,1.979,1.794,2.624,2.027,3.66,1.073,1.007,1.57,0.854,0.619,0.547] y=[5.255,10.897,11.045,9.125,9.387,17.719,4.025,1.389,4.152,8.703,9.051,8.02,7.774,3.139,7.543,7.224,4.155,7.416,3.905,6.868,2.909,2.658,1.651,6.454,6.252,6.541,6.152,5.647,6.285,6.079,5.489,4.541,4.634,8.851,4.554,4.555,5.559,5.144,5.311,5.839,5.364,3.18,4.352,3.379,4.059,4.575,3.914,5.736,2.304,4.68,3.187,3.756,3.419,9.118,4.595,3.346,3.603,6.313,1.816,4.34,2.732,4.978,2.719,3.761,2.623,2.1,4.956,2.316,4.231,2.831,1.954,2.248,6.573,2.276,2.627,3.85,3.545,25.405,3.996,1.347,1.679,1.435,0.759,0.677] redshift = [0.12,0.25,0.23,0.23,0.27,0.26,0.12,0.27,0.17,0.18,0.17,0.3,0.23,0.1,0.23,0.29,0.29,0.12,0.13,0.26,0.11,0.24,0.13,0.21,0.17,0.2,0.3,0.29,0.23,0.27,0.25,0.21,0.11,0.15,0.1,0.26,0.23,0.12,0.23,0.26,0.2,0.17,0.22,0.26,0.25,0.12,0.19,0.24,0.18,0.15,0.27,0.14,0.14,0.29,0.29,0.26,0.15,0.29,0.24,0.24,0.23,0.26,0.29,0.22,0.13,0.18,0.24,0.14,0.24,0.24,0.17,0.26,0.29,0.11,0.14,0.26,0.28,0.26,0.28,0.27,0.23,0.26,0.23,0.19]
Working with numerical data like this, you should really consider using a numerical library, like numpy. The problem in your code arises from processing each record (a coordinate (x,y) and the corresponding value redshift) one at a time. You are calling plot for each point, thereby creating legends for each of those 84 datapoints. You should consider your "bins" as groups of data that belong to the same dataset and process them as such. You could use "logical masks" to distinguish between your "bins", as shown below. It's also not clear why you call exit after each plotting action. import numpy as np import matplotlib.pyplot as plt x = np.array([5.031,10.599,10.589,8.548,9.089,8.675,3.588,1.244,3.023,8.632,8.953,7.603,7.513,2.917,7.344,7.106,3.889,7.287,3.367,6.839,2.801,2.316,1.328,6.31,6.19,6.329,6.025,5.629,6.123,5.892,5.438,4.398,4.542,4.624,4.501,4.504,5.033,5.068,4.197,2.854,4.784,2.158,4.054,3.124,3.961,4.42,3.853,3.658,1.858,4.537,2.072,3.573,3.041,5.837,3.652,3.209,2.742,2.732,1.312,3.635,2.69,3.32,2.488,2.996,2.269,1.701,3.935,2.015,0.798,2.212,1.672,1.925,3.21,1.979,1.794,2.624,2.027,3.66,1.073,1.007,1.57,0.854,0.619,0.547]) y = np.array([5.255,10.897,11.045,9.125,9.387,17.719,4.025,1.389,4.152,8.703,9.051,8.02,7.774,3.139,7.543,7.224,4.155,7.416,3.905,6.868,2.909,2.658,1.651,6.454,6.252,6.541,6.152,5.647,6.285,6.079,5.489,4.541,4.634,8.851,4.554,4.555,5.559,5.144,5.311,5.839,5.364,3.18,4.352,3.379,4.059,4.575,3.914,5.736,2.304,4.68,3.187,3.756,3.419,9.118,4.595,3.346,3.603,6.313,1.816,4.34,2.732,4.978,2.719,3.761,2.623,2.1,4.956,2.316,4.231,2.831,1.954,2.248,6.573,2.276,2.627,3.85,3.545,25.405,3.996,1.347,1.679,1.435,0.759,0.677]) redshift = np.array([0.12,0.25,0.23,0.23,0.27,0.26,0.12,0.27,0.17,0.18,0.17,0.3,0.23,0.1,0.23,0.29,0.29,0.12,0.13,0.26,0.11,0.24,0.13,0.21,0.17,0.2,0.3,0.29,0.23,0.27,0.25,0.21,0.11,0.15,0.1,0.26,0.23,0.12,0.23,0.26,0.2,0.17,0.22,0.26,0.25,0.12,0.19,0.24,0.18,0.15,0.27,0.14,0.14,0.29,0.29,0.26,0.15,0.29,0.24,0.24,0.23,0.26,0.29,0.22,0.13,0.18,0.24,0.14,0.24,0.24,0.17,0.26,0.29,0.11,0.14,0.26,0.28,0.26,0.28,0.27,0.23,0.26,0.23,0.19]) bin3 = 0.25 <= redshift bin2 = np.logical_and(0.2 <= redshift, redshift < 0.25) bin1 = np.logical_and(0.1 <= redshift, redshift < 0.2) plt.ion() labels = ("$z < 0.2$", "$0.2 \leq z < 0.25$", "$z \geq 0.25$") colors = ('r', 'g', 'b') for bin, label, co in zip( (bin1, bin2, bin3), labels, colors): plt.plot(x[bin], y[bin], color=co, ls='none', marker='o', label=label) plt.legend() plt.show()