I'm learning Python applied to data science and I'm trying to create an interactive map of my city, Madrid (Spain), showing the last election results. All I'm doing is in this GitHub link:
https://github.com/BernardoJoseLlamasVerna/Madrid_Elections_2021
You will see draft operations and looking for the best way to represent my data on a map:
https://github.com/BernardoJoseLlamasVerna/Madrid_Elections_2021/blob/main/Madrid_Elections_2021.ipynb
I'm following an example found on Internet about Wisconsin elections and fixes perfectly with what I would like to do with my data. I have downloaded it and stored on my repo to show you what I'm trying:
https://github.com/BernardoJoseLlamasVerna/Madrid_Elections_2021/blob/main/maps.ipynb
I've tried to do the same with my data, but nothing appears (even errors). The code is as follows:
from bokeh.io import output_notebook
from bokeh.plotting import figure, ColumnDataSource
from bokeh.io import output_notebook, show, output_file
from bokeh.plotting import figure
from bokeh.models import GeoJSONDataSource, LinearColorMapper, ColorBar, HoverTool
from bokeh.palettes import brewer
output_notebook()
import json
# res_w_states["clinton_share"] = res_w_states["clinton"] / res_w_states["total"]
#Convert data to geojson for bokeh
wi_geojson=GeoJSONDataSource(geojson=data.to_json())
color_mapper = LinearColorMapper(palette = brewer['RdBu'][10], low = 0, high = 1)
color_bar = ColorBar(color_mapper=color_mapper, label_standoff=8,width = 500, height = 20,
border_line_color=None,location = (0,0), orientation = 'horizontal')
hover = HoverTool(tooltips = [ ('Municipio','#Municipio'),('P.P.', '#P.P.'),
('P.S.O.E.','#P.S.O.E.'),
('Votos Totales','#Votos Totales')])
p = figure(title="Elecciones Madrid 2021", tools=[hover])
p.patches("xs","ys",source=wi_geojson,
fill_color = {'field' :'P.P.', 'transform' : color_mapper})
p.add_layout(color_bar, 'below')
show(p)
I've been analysing wi_geojson comparing between mine and what I copied and they seem to follow the same structure.
**QUESTION: ** anyone could give me a hint about what is wrong with my code, data, etc?
Thank you for your help.
P.D.: if anyone could also post a link with better interactive mapping, I would be so glad.
Thanks to mosc9575 I could manage a solution...
The problem was the Bokeh version (1.3.4); once updated (2.3.2) I could figure out my map. Now I have to fix the municipalities names XDD.
Related
I need to plot the rivers in idaho from this website
When I load it into geopandas and try to plot it through altair.Chart().mark_geoshape() my graph comes up with a bunch of random lines and they aren't plotting as expected. I don't know what is going on because I am new when it comes to geospatial data.
I followed the pattern from this example https://altair-viz.github.io/gallery/london_tube.html but I wasn't able to plot the lines.
Any thoughts or how I can do this would be of great help! Below is the code I am using. Thank you!
import altair as alt
import geopandas as gpd
from vega_datasets import data
states = alt.topo_feature(data.us_10m.url,'states')
hydro = gpd.read_file('drive/MyDrive/data_cse350/hyd250/hyd250.shp')
rivers = hydro.loc[hydro.FEAT_NAME.isin(['Snake River','Henrys Fork'])]
rchart = alt.Chart(rivers).mark_geoshape().encode(color = 'FEAT_NAME')
idaho = alt.Chart(states).mark_geoshape(fill = 'white',stroke = 'black').project(
'albersUsa'
).transform_calculate(state_id = "(datum.id)"
).transform_filter((alt.datum.state_id)==16)
rchart+idaho```
If you can solve this, that would be great! Thank you for your help! I have already spent waaaayyy too many hours on getting this to work.
The reason it was not drawn was that the geopandas data coordinate system was different, so it needed to be converted to a format that represented latitude and longitude. My experience with this kind of thing is limited, so I had to figure it out by hand. I actually referenced a map of Idaho to make sure it matched.
import altair as alt
import geopandas as gpd
from vega_datasets import data
states = alt.topo_feature(data.us_10m.url,'states')
hydro = gpd.read_file('./data/hyd250/hyd250.shp')
hydro_trans = hydro.to_crs(epsg=4612)
rivers = hydro_trans.loc[hydro.FEAT_NAME.isin(['Snake River','Henrys Fork'])]
rchart = alt.Chart(rivers).mark_geoshape(
filled=False,
strokeWidth=2
).encode(
color='FEAT_NAME'
).properties(
width=600,
height=300
)
idaho = alt.Chart(states).mark_geoshape(
fill=None,
stroke='black'
).project(
'albersUsa'
).transform_calculate(
state_id = "(datum.id)"
).transform_filter(
(alt.datum.state_id)==16
)
rchart+idaho
I'm using Bokeh and Geopandas to plot an interactive map of Germany. Germany has total 16 states but the plot shows only 15. It does not display the map of Berlin, which is the capital city (Berlin is also a state). I'm using the shapefile as an input to plot the map. I have tried different shapefiles and looked for different solutions but I'm unable to find the root of the problem. Please have a look at the code and the output.
`
import pandas as pd
# Import geopandas package
import geopandas as gpd
# Read in shapefile and examine data
germany = gpd.read_file('Igismap/Germany_Polygon.shp')
pop_states = germany
vargeojson = pop_states.to_json()
import json
from bokeh.io import show, output_notebook
from bokeh.models import (ColumnDataSource,
GeoJSONDataSource, HoverTool,
LinearColorMapper)
from bokeh.layouts import column, row, widgetbox
from bokeh.plotting import figure
output_notebook()
# Input GeoJSON source that contains features for plotting
geosource = GeoJSONDataSource(geojson = vargeojson)
tools = "pan, wheel_zoom, box_zoom, reset"
p = figure(title = 'All states of Germany',
plot_height = 600 ,
plot_width = 600,
toolbar_location = 'right',
tools = tools)
p.xgrid.grid_line_color = None
p.ygrid.grid_line_color = None
# Add patch renderer to figure.
states = p.patches('xs','ys', source = geosource,
line_color = "grey",
line_width = 0.25,
fill_alpha = 1)
# Create hover tool
p.add_tools(HoverTool(renderers = [states],
tooltips = [('Lander','#name')]))
show(p)
`
Click here to see the output of above code.... and
Click here to see the desired output
I have a large dataset from which I am interested in this part:
temp lat long
7.1 47 13
19 49 16
I tried using folium:
import requests
from xml.etree import ElementTree
import folium
from folium.plugins import MarkerCluster
MarkerCluster()
map2 = folium.Map(location=[47.031, 13.001999], tiles='CartoDB dark_matter', zoom_start=11)
marker_cluster = folium.plugins.MarkerCluster().add_to(map2)
But I get SyntaxError: unexpected EOF while parsing.
Then I tried using bokeh by copy-pasting an Internet example just to see if it works:
from bokeh.io import output_file, output_notebook, show
from bokeh.models import (
GMapPlot, GMapOptions, ColumnDataSource, Circle, LogColorMapper, BasicTicker, ColorBar,
DataRange1d, PanTool, WheelZoomTool, BoxSelectTool
)
from bokeh.models.mappers import ColorMapper, LinearColorMapper
from bokeh.palettes import Viridis5
map_options = GMapOptions(lat=37.88, lng=-122.23, map_type="roadmap", zoom=6)
plot = GMapPlot(
x_range=bokeh.Range1d(), y_range=bokeh.Range1d(), map_options=map_options
)
plot.title.text = "Hey look! It's a scatter plot on a map!"
show(plot)
But I get NameError: name 'bokeh' is not defined.
Is there any other way to plot a point or to fix the errors?
I tried to reproduce your Folium example with the following code :
from folium.plugins import MarkerCluster
m = folium.Map(location=[47.031, 13.001999], zoom_start=5)
marker_cluster = MarkerCluster().add_to(m)
folium.Marker(
location=[47.031, 13.001999],
popup='Add popup text here.',
icon=folium.Icon(color='green', icon='ok-sign'),
).add_to(marker_cluster)
m
It works just well :
Maybe there is another part of your code which was triggering the EOS error. An EOS error usually occurs because of missing commas, parenthesis etc.
If you are interested in the different types of folium Markers, there is an official Notebook with interesting examples.
does anyone know if/how one can use a "custom" function to plot in Bokeh using the Bokeh server? For example, I know you can use something like
plot = figure(toolbar_location=None)
plot.vbar(x='x', width=0.5, bottom=0, top='y', source=source)
But how can you plot using something like
def mplot(source):
p = pd.DataFrame()
p['aspects'] = source.data['x']
p['importance'] = source.data['y']
plot = Bar(p, values='importance', label='aspects', legend=False)
return plot
My current attempt is, here:
http://pastebin.com/7Zk9ampq
but it doesn't run. I'm not worried about getting the function "update_samples_or_dataset" working yet, just the initial plot to show. Any help would be much appreciated. Thanks!
Is this what you want? Note that I did not use the Bar function imported from bokeh.charts as this does not update upon updating the data source.
If you want to stick with using Bar from bokeh.charts you need to recreate the plot each time.
Note: to run this and have updating work - you need to execute bokeh serve --show plotfilename.py from the command line.
from bokeh.io import curdoc
from bokeh.layouts import layout
from bokeh.models.widgets import Button
from bokeh.plotting import ColumnDataSource, figure
import random
def bar_plot(fig, source):
fig.vbar(x='x', width=0.5, bottom=0,top='y',source=source, color="firebrick")
return fig
def update_data():
data = source.data
data['y'] = random.sample(range(0,10),len(data['y']))
source.data =data
button = Button(label="Press here to update data", button_type="success")
button.on_click(update_data)
data = {'x':[0,1,2,3],'y':[10,20,30,40]}
source = ColumnDataSource(data)
fig = figure(plot_width=650,
plot_height=500,
x_axis_label='x',
y_axis_label='y')
fig = bar_plot(fig, source)
layout = layout([[button,fig]])
curdoc().add_root(layout)
EDIT: See below a method that plots a bokeh plot but uses data from a dataframe as you wanted. It also will update the plot on each button press. Still you need to use the command bokeh serve --show plotfilename.py
from bokeh.io import curdoc
from bokeh.layouts import layout
from bokeh.models.widgets import Button
from bokeh.plotting import ColumnDataSource
from bokeh.charts import Bar
import random
import pandas as pd
def bar_plot(source):
df = pd.DataFrame(source.data)
fig = Bar(df, values='y', color="firebrick")
return fig
def update_data():
data = {'x':[0,1,2,3],'y':random.sample(range(0,10),4)}
source2 = ColumnDataSource(data)
newfig = bar_plot(source2)
layout.children[0].children[1] = newfig
button = Button(label="Press here to update data", button_type="success")
button.on_click(update_data)
data = {'x':[0,1,2,3],'y':[10,20,30,40]}
source = ColumnDataSource(data)
fig = bar_plot(source)
layout = layout([[button,fig]])
curdoc().add_root(layout)
I think you still have to attach your Bar instance to a Figure instance; a Figure is a set of plots, essentially, with niceties like the toolbar.
How do you create a multiline plot title in bokeh?... same question as https://github.com/bokeh/bokeh/issues/994
Is this resolved yet?
import bokeh.plotting as plt
plt.output_file("test.html")
plt.text(x=[1,2,3], y = [0,0,0], text=['hello\nworld!', 'hello\nworld!', 'hello\nworld!'], angle = 0)
plt.show()
Additionally, can the title text string accept rich text?
In recent versions of Bokeh, labels and text glyphs can accept newlines in the text, and these will be rendered as expected. For multi-line titles, you will have to add explicit Title annotations for each line you want. Here is a complete example:
from bokeh.io import output_file, show
from bokeh.models import Title
from bokeh.plotting import figure
output_file("test.html")
p = figure(x_range=(0, 5))
p.text(x=[1,2,3], y = [0,0,0], text=['hello\nworld!', 'hello\nworld!', 'hello\nworld!'], angle = 0)
p.add_layout(Title(text="Sub-Title", text_font_style="italic"), 'above')
p.add_layout(Title(text="Title", text_font_size="16pt"), 'above')
show(p)
Which produces:
Note that you are limited to the standard "text properties" that Bokeh exposes, since the underlying HTML Canvas does not accept rich text. If you need something like that it might be possible with a custom extension
You can add a simple title to your plot with this:
from bokeh.plotting import figure, show, output_file
output_file("test.html")
p = figure(title="Your title")
p.text(x=[1,2,3], y = [0,0,0], text=['hello\nworld!', 'hello\nworld!', 'hello\nworld!'], angle = 0)
show(p)
Addendum
Here is a working example for plotting a pandas dataframe for you to copy/paste into a jupyter notebook. It's neither elegant nor pythonic. I got it a long time ago from various SO posts. Sorry, that I don't remember which ones anymore, so I can't cite them.
Code
# coding: utf-8
from bokeh.plotting import figure, show
from bokeh.io import output_notebook
import pandas as pd
import numpy as np
# Create some data
np_arr = np.array([[1,1,1], [2,2,2], [3,3,3], [4,4,4]])
pd_df = pd.DataFrame(data=np_arr)
pd_df
# Convert for multi-line plotting
data = [row[1].as_matrix() for row in pd_df.iterrows()]
num_lines = len(pd_df)
cols = [pd_df.columns.values] * num_lines
data
# Init bokeh output for jupyter notebook - Adjust this to your needs
output_notebook()
# Plot
p = figure(plot_width=600, plot_height=300)
p.multi_line(xs=cols, ys=data)
show(p)
Plot