I've been able to understand how to display long/lat from a map, as well as x/y on a plot, on a label in NiceGUI with a click on a Plotly map with the help of this forum, but now I would like to display attributes from a dataframe object that contains multiple attributes. Sample code is below, dataframe is made up for simplicity.
import pandas as pd
import plotly.graph_objects as go
from nicegui import ui, events
df = pd.DataFrame([
[12345, -95, 45, 'Cross River'],
[12346, -94, 43, 'Snake River'],
[12347, -92, 45, 'Temple River'],
[12348, -96, 46, 'Gold River'],
[12349, -95.5, 44.5, '#FT Ty7']],
columns=['site', 'long', 'lat', 'name']
)
fig = go.Figure(go.Scattermap(
mode='markers',
lon=df['long'],
lat=df['lat'],
)
)
fig.update_layout(margin=dict(l=0,r=0,t=0,b=0), width=400, showlegend=False,
map = {
'style': 'satellite-streets',
'center': {'lon': sum(df['long']/len(df)), 'lat': sum(df['lat']/len(df)) },
'zoom':5})
plot = ui.plotly(fig)
label = ui.label("Click on a point for more information.")
def handle_click(e: events.GenericEventArguments):
index = e.args
label.text = f'Name: {name}, Site number: {site}.'
plot.on('plotly_click', handle_click)
ui.run()
This code doesn't work to display the attribute "name" from the df, and I would like to include all the attributes in a label as well.
If you print e.args
you will see what you can get when you click item on map.
It is some dictionary with list of points and every point is a dictionary with lat
,lon
but also pointIndex
, pointNumber
.
If you use json.dumps
then you can display it in more readable way.
import json
print(json.dumps(e.args, indent=2))
example result
{
"points": [
{
"data": {
"lat": {
"dtype": "f8",
"bdata": "AAAAAACARkAAAAAAAIBFQAAAAAAAgEZAAAAAAAAAR0AAAAAAAEBGQA==",
"_inputArray": {
"0": 45,
"1": 43,
"2": 45,
"3": 46,
"4": 44.5,
"bdata": "AAAAAACARkAAAAAAAIBFQAAAAAAAgEZAAAAAAAAAR0AAAAAAAEBGQA==",
"dtype": "f8",
"shape": "5"
}
},
"lon": {
"dtype": "f8",
"bdata": "AAAAAADAV8AAAAAAAIBXwAAAAAAAAFfAAAAAAAAAWMAAAAAAAOBXwA==",
"_inputArray": {
"0": -95,
"1": -94,
"2": -92,
"3": -96,
"4": -95.5,
"bdata": "AAAAAADAV8AAAAAAAIBXwAAAAAAAAFfAAAAAAAAAWMAAAAAAAOBXwA==",
"dtype": "f8",
"shape": "5"
}
},
"mode": "markers",
"type": "scattermap"
},
"curveNumber": 0,
"pointNumber": 1,
"pointIndex": 1,
"lon": -94,
"lat": 43,
"bbox": {
"x0": 237.75555555555556,
"x1": 239.75555555555556,
"y0": 347.2957478845692,
"y1": 349.2957478845692
}
}
],
"event": {
"isTrusted": true
}
}
You can get index using
index = e.args['points'][0]['pointIndex']
and you can get row from dataframe
data = df.iloc[index]
and you can display it
label.text = f'Name: {data['name']}, Site number: {data['site']}.'
def handle_click(e: events.GenericEventArguments):
# use json.dumps to display data with indentations - to make it more readable
#import json
#print(json.dumps(e.args, indent=2))
index = e.args['points'][0]['pointIndex']
data = df.iloc[index]
label.text = f'Name: {data['name']}, Site number: {data['site']}.'
To make sure you may check if points
exists and if it has any item
def handle_click(e: events.GenericEventArguments):
# use json.dumps to display data with indentations - to make it more readable
#import json
#print(json.dumps(e.args, indent=2))
if 'points' in e.args and len(e.args['points']) > 0 and 'pointIndex' in e.args['points'][0]:
index = e.args['points'][0]['pointIndex']
data = df.iloc[index]
label.text = f'Name: {data['name']}, Site number: {data['site']}.'
else:
label.text = 'Wrong point'
Other idea:
It seems Scattermap() can use customdata=
to keep extra information and you can assign full df or only some columns
fig = go.Figure(go.Scattermap(
mode='markers',
lon=df['long'],
lat=df['lat'],
customdata=df[['site','name']],
)
)
And later you can access it directly in e.args
as list without column names
site, name = e.args['points'][0]['customdata']
label.text = f'Name: {name}, Site number: {site}.'
You can even display custom data when you hover point on map
fig = go.Figure(go.Scattermap(
mode='markers',
lon=df['long'],
lat=df['lat'],
customdata=df[['site','name']],
hovertemplate="Name: %{customdata[1]}, Site number: %{customdata[0]}<extra>lat: %{lat}, lon: %{lon}</extra>"
)
)