Hello,
I was asking myself if it was possible to put annotation (Label) in the center of glyph Patches. I know that hovertool find the centroid of polygon. I would like to label each polygon in an easy way.
Thank you
Hello,
I was asking myself if it was possible to put annotation (Label) in the center of glyph Patches. I know that hovertool find the centroid of polygon. I would like to label each polygon in an easy way.
Thank you
The centroid is the geometric center, which is the mean position of the points. numpy
has a built-in mean()
function for numpy arrays. As does Pandas for its Series and DataFrames.
The bokeh Patches
use lists of lists to plot the glyphs so you’ll need to coerce your data differently to generate the plots and annotations, but the calculations are easy.
Also, if you’re plotting a number of shapes, and not just one, use the LabelSet
to add annotations as it is more efficient than calling Label
once for each shape. Depending on where you want to place the labels relative to the centroid, set the text_align
and text_baseline
properties to adjust left/right and up/down respectively.
I would actually like to expose the “center” coordinates for glyphs to be available for use in hover tools, transforms, etc. but it’s only ever been an idea in the back of my mind so far. AFAIK there is not an issue, so if you want to submit an issue that would be helpful (a concrete use case always helps when prioritizing)
Thank you for all your responses. I wrote this code (maybe not the best) that compute the centroid of patches. The result is not bad but sometimes, label is outside of the patches. Maybe i miss a fonctionnality of patches that permit to know where is the area of patches. In fact, Hovertool knows if your cursor is in or out of the patch.
import json
from bokeh.models.tools import BoxZoomTool,WheelZoomTool
from bokeh.io import output_file, show, output_notebook
from bokeh.models import GeoJSONDataSource, ColumnDataSource
from bokeh.plotting import figure
from bokeh.sampledata.sample_geojson import geojson
from bokeh.plotting import figure
from bokeh.models import BBoxTileSource, WMTSTileSource, TileRenderer, HoverTool
from bokeh.io import show
from bokeh.io import output_file
from bokeh.layouts import column, row, gridplot
from bokeh.models import LabelSet
import requests
import pandas as pd
RADIUS=6378137.0
import math
def lat2y(a):
if (type(a)==int) or (type(a)==float):
return math.log(math.tan(math.pi / 4 + math.radians(a) / 2)) * RADIUS
if type(a)==list or type(a)==tuple:
re=[]
for i in a:
re.append(math.log(math.tan(math.pi / 4 + math.radians(i) / 2)) * RADIUS)
return re
def lon2x(a):
if type(a)==int or (type(a)==float):
return math.radians(a) * RADIUS
if type(a)==list or type(a)==tuple:
re=[]
for i in a:
re.append(math.radians(i) * RADIUS)
return re
rawdata = requests.get('https://cadastre.data.gouv.fr/bundler/cadastre-etalab/communes/83047/geojson/parcelles')
alldata = rawdata.json()
dfLabel=pd.DataFrame(columns=['Longitude','Latitude','numero'])
for i,feature in enumerate(alldata['features']):
new_coords = []
for ring in feature['geometry']['coordinates']:
X=lon2x(list(list(zip(*ring))[0]))
Y=lat2y(list(list(zip(*ring))[1]))
new_coords.append([[i,j] for i,j in (zip(X,Y))])
alldata['features'][i]['geometry']['coordinates'] = new_coords
for k,l in enumerate(alldata['features']):
Lon=0
La=0
for i,j in enumerate(alldata['features'][k]['geometry']['coordinates'][0]):
Lon+=alldata['features'][k]['geometry']['coordinates'][0][i][0]
La+=alldata['features'][k]['geometry']['coordinates'][0][i][1]
La=La/(i+1)
Lon=Lon/(i+1)
dfLabel.loc[k,'Longitude']=Lon
dfLabel.loc[k,'Latitude']=La
dfLabel.loc[k,'numero']= alldata['features'][k]['properties']['section'] + alldata['features'][k]['properties']['numero']
TOOLS = "pan,wheel_zoom,reset,hover,save"
geosource = WMTSTileSource(url='https://tile.openstreetmap.org/{Z}/{X}/{Y}.png',max_zoom=25,min_zoom=0)
p = figure(x_range=(lon2x(6.05), lon2x(6.15)), y_range=(lat2y(43.1), lat2y(43.24)),
x_axis_type="mercator", y_axis_type="mercator",output_backend='webgl', tools=["pan,wheel_zoom,reset,hover,save"],tooltips=[
("Name", "@numero"), ("(Long, Lat)", "($x, $y)")
],active_scroll="wheel_zoom",active_drag="pan")
p.add_tile(geosource)
geo_source = GeoJSONDataSource(geojson=json.dumps(alldata))
p.patches(xs="xs", ys="ys", line_width=1.5, line_color='black',color= None, source=geo_source,alpha=0.5)
source2=ColumnDataSource(dfLabel)
labels = LabelSet(
x='Longitude',
y='Latitude',
text='numero',
source=source2,render_mode='canvas' ,text_font_size='10px')
p.add_layout(labels)
show(p)
I welcome criticism of my code.
@Bryan P.S : Your Library is awesome. When 3d plotting will be integrate, everyone would use your library. Thanks