MATLAB how to detect double click on tree node - matlab

I have the MATLAB code which deals with a uitree structure. I want to detect when the user double clicks a node, now I managed to make it work only on node click :(
% Tree
function test()
clc;
set(groot,'Units','characters')
figure('Position',[200,200,400,400]);
root = uitreenode('v0', 'Datatypes', 'Datatypes', [], false);
root.add(uitreenode('v0', 'Potato', 'Potato', [], true));
root.add(uitreenode('v0', 'Tomato', 'Tomato', [], true));
root.add(uitreenode('v0', 'Carrot', 'Carrot', [], true));
[mtree,container] = uitree('v0', 'Root', root,'Position',[50,50,150,150],SelectionChangeFcn, #callback);
uiwait(gcf,2);
root2 = uitreenode('v0', 'Datatypes2', 'Datatypes2', [], false);
root2.add(uitreenode('v0', 'Carrot2', 'Carrot2', [], true));
root2.add(uitreenode('v0', 'Tomato2', 'Tomato2', [], true));
mtree.setRoot(root2);
%displ tthe root and its children
root=mtree.getRoot();
rootName = root.getName();
for i=0:root.getChildCount()-1
childNode = root.getChildAt(i);
childName = childNode.getName();
disp(childName);
end
end
function callback(src, data)
persistent x;
if isempty(x)
x=0;
end
x=x+1;
disp([num2str(x) ' tree_Datatypes_Selection_Callback called']);
end
How do I make the callback be called on mouse double click? Now it works only on mouse node select click :(

I found the solution by own experimenting :
% Tree
function test()
clc;
global jtree;
set(groot,'Units','characters')
figure('Position',[200,200,400,400]);
root = uitreenode('v0', 'Datatypes', 'Datatypes', [], false);
root.add(uitreenode('v0', 'Potato', 'Potato', [], true));
root.add(uitreenode('v0', 'Tomato', 'Tomato', [], true));
root.add(uitreenode('v0', 'Carrot', 'Carrot', [], true));
[mtree,container] = uitree('v0', 'Root', root,'Position',[50,50,150,150]);
jtree = mtree.getTree;
% MousePressedCallback is not supported by the uitree, but by jtree
set(jtree, 'MousePressedCallback', #mousePressedCallback);
uiwait(gcf,2);
root2 = uitreenode('v0', 'Datatypes2', 'Datatypes2', [], false);
root2.add(uitreenode('v0', 'Carrot2', 'Carrot2', [], true));
root2.add(uitreenode('v0', 'Tomato2', 'Tomato2', [], true));
mtree.setRoot(root2);
%displ tthe root and its children
root=mtree.getRoot();
rootName = root.getName();
for i=0:root.getChildCount()-1
childNode = root.getChildAt(i);
childName = childNode.getName();
disp(childName);
end
end
function mousePressedCallback(hTree, eventData) %,additionalVar)
% if eventData.isMetaDown % right-click is like a Meta-button
% if eventData.getClickCount==2 % how to detect double clicks
persistent x;
global jtree;
if isempty(x)
x=0;
end
x=x+1;
clickX = eventData.getX;
clickY = eventData.getY;
treePath = jtree.getPathForLocation(clickX, clickY);
if ~isempty(treePath)
nr=eventData.getClickCount();
disp([num2str(x) ': click count:' num2str(nr)]);
% check if the checkbox was clicked
node = treePath.getLastPathComponent;
nodeValue = node.getValue;
else
disp('you clicked outside the tree')
end
end % function mousePressedCallback

Related

Leaflet JS- Highlight on hover

I created a simple web map and now I am stacked on how to use the highlight function on hover. I tried to use the tutorial on the Leaf js site, but when I am trying to call the highlight function under geoJason variable, it is not working. Basically I want the polygon to be highlighted when hovered. The popup is working just fine.
Here is my script, without the highlight function.
ar map = L.map('map').setView([43.0982, -89.3811], 12);
var googleSat = L.tileLayer('http://{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}',{
minZoom: 1,
maxZoom: 20,
subdomains:['mt0','mt1','mt2','mt3'],
attribution: '<a href="https://www.google.com/maps" target=_blank> Google Sattellite Map</a>' }).addTo(map);
// Adding the geoJason file and styling it.
var myStyle = {
fillColor: "#2c7fb8",
color: "#f20b0b",
weight: 1,
opacity: 1,
fillOpacity: 0.55
};
// Alder district was a geoJason file and now it saved as js file.
var geojason = L.geoJSON(alderdstricts, {
style:myStyle,
onEachFeature:districtdata,
}).addTo(map);
// Function to bind popup to the geoJason data.
function districtdata(feature, layer){
layer.bindPopup("<span class='headings'>District: </span>" + feature.properties.ALD_DIST + "<br>" +
"<span class='headings'>Representative: </span>" + feature.properties.Representa + "<br>"
+ "<span class='headings'>Contact Representative: </span>" + feature.properties.ContactRep + "<br>"
+ "<span class='headings'>District Population: </span>" + feature.properties.DistrictPo
+ "<span class='headings'></span>" + feature.properties.Image)
};
I added all of my script above except the highlight function and that is where I am stacked.
var map = L.map('map').setView([43.0982, -89.3811], 12);
var googleSat = L.tileLayer('http://{s}.google.com/vt/lyrs=s&x={x}&y={y}&z={z}',{ minZoom: 1, maxZoom: 20, subdomains:['mt0','mt1','mt2','mt3'], attribution: ' Google Sattellite Map' }).addTo(map);
// Adding the geoJason file and styling it.
var myStyle = {
fillColor: "#2c7fb8",
color: "#f20b0b",
weight: 1,
opacity: 1,
fillOpacity: 0.55
};
// Alder district was a geoJason file and now it saved as js file.
var geojason = L.geoJSON(alderdstricts, { style:myStyle, onEachFeature:districtdata,
}).addTo(map);
// Function to bind popup to the geoJason data.
function districtdata(feature, layer){
layer.bindPopup("District: " + feature.properties.ALD_DIST + "
" + "Representative: " + feature.properties.Representa + "
" + "Contact Representative: " + feature.properties.ContactRep + "
" + "District Population: " + feature.properties.DistrictPo + "" + feature.properties.Image)
layer.on('mouseover', function(e) {
e.target.setStyle({
fillOpacity: 0.8
});
});
layer.on('mouseout', function(e) {
e.target.setStyle({
fillOpacity: 0.55
});
});
};
I'm not sure what you tried, but this should work. It simply adds a "mouseover" and "mouseout" event handler for each polygon, as well as your pop-up. If this doesn't work, please let me know what errors/behaviour you get.
In general, it's best to provide details on what solutions you have already tried in your question. Also, just FYI, JSON is not a contraction of Jason, it stands for JavaScript Object Notation.

Plotly Dash - Python - Issue with callback function

Please bare with my limited experience in programming. At least, I will elaborate.
My task is to create a Dropdown for a number of launch sites, and then plot the success rate in a pie chart. The user can also select a range of payloads with a RangeSlider, that will be used to create a scatter plot.
This is how the result should look like:
enter image description here
Here is the code:
from dash import Dash, dcc, html, Input, Output
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
URL = 'https://cf-courses-data.s3.us.cloud-object-storage.appdomain.cloud/IBM-DS0321EN-SkillsNetwork/datasets/spacex_launch_geo.csv'
df_spacex = pd.read_csv(URL)
df_spacex.head()
# dropdown menu to choose from the various sites:
app = Dash(__name__)
app.layout = html.Div(children = [
html.Div([
html.H1('SpaceX Launch Records Dashboard',
style = {'textAlign': 'center',
'color': 'black',
'font-size': 24}
),
html.Label('Dropdown:',
style = {'color': 'black',
'font-size': 18}
),
dcc.Dropdown(id = 'site-dropdown',
options = [{'label': 'All Sites', 'value': 'ALL'},
{'label': 'CCAFS SCL-40', 'value': 'CCAFS SLC-40'},
{'label': 'CCAFS LC-40', 'value': 'CCAFS LC-40'},
{'label': 'VAFB SLC-4E', 'value': 'VAFB SLC-4E'},
{'label': 'KSC LC-39A', 'value': 'KSC LC-39A'}],
value = 'ALL',
placeholder = 'Select a site',
searchable = True,
style = {'width': '80%', 'height': '3px',
'textAlign': 'left', 'font-size': '16px'}
),
]),
html.Div([
html.Br(),
html.Br(),
dcc.Graph(id = 'success-pie-chart'),
html.Br(),
html.Label('Payload range slider (kg):',
style = {'color': 'black',
'font-size': 18}
),
dcc.RangeSlider(id = 'payload-slider',
min = df_spacex['Payload Mass (kg)'].min(),
max = df_spacex['Payload Mass (kg)'].max(),
step = 1000,
marks = {0: '0',
100: '100'},
value = [2000, 8000]
),
html.Br(),
dcc.Graph(id = 'success-payload-scatter-chart')
])
])
# function decorator to specify function input and output
#app.callback(Output('success-pie-chart', 'figure'),
Output('success-payload-scatter-chart', 'figure'),
Input('site-dropdown', 'value'),
Input('payload-slider', 'value'))
def get_pie_chart(entered_site, payload):
if entered_site == 'ALL':
fig = px.pie(df_spacex, values = 'class', names = 'Launch Site',
title = 'Successful Launch Distribution by Site')
else:
# choose the rows that have the same launch site as the one entered
df_filtered = df_spacex.loc[df_spacex['Launch Site'] == entered_site]
fig = px.pie(df_filtered, names = 'class',
title = 'Launch Distribution for ' + entered_site)
return fig
def get_scatter_chart(entered_site, payload):
# expand equals True to return a data frame
# with seperated strings in different columns
df_split = df_spacex['Booster Version'].str.split(' ', expand = True)
# save the modified data frame
df_mod = df_spacex.drop(columns = ['Booster Version'], inplace = False)
df_mod['Booster Version'] = df_split[1]
print(payload)
# based on the input payload range choose the corresponding rows
df_mod = df_mod.loc[(df_mod['Payload Mass (kg)'] >= payload[0]) & (df_mod['Payload Mass (kg)'] <= payload[1])]
if entered_site == 'ALL':
fig = px.scatter(df_mod,
x = 'Payload Mass (kg)',
y = 'class',
color = 'Booster Version',
hover_data = ['Booster Version'])
else:
df_filtered = df_mod.loc[df_mod['Launch Site'] == entered_site]
fig = px.scatter(df_filtered,
x = 'Payload Mass (kg)',
y = 'class',
color = 'Booster Version',
hover_data = ['Booster Version'])
return fig
if __name__ == '__main__':
app.run_server(debug = True, use_reloader = False)
Finally, the error that I get is the following:
dash._grouping.SchemaTypeValidationError: Schema: [<Output `success-pie-chart.figure`>, <Output `success-payload-scatter-chart.figure`>]
Path: ()
Expected type: (<class 'tuple'>, <class 'list'>)
Received value of type <class 'plotly.graph_objs._figure.Figure'>:
I really appreciate your time guys.
Please let me know if I can provide any more info or help clarify.
I've tested the functions that take the user's input and produce the pie and scatter charts outside Dash, and they worked fine. So, the error is arising from Dash.

How to find google charts (Sankey) select events selection data - including tooltip column

I am creating a Sankey chart via react-google-charts. Each time when clicked on the link between the nodes I am printing the data which has been working fine until recently.
Assume my Sankey diagram to be like this and I clicked on the link between A & P:
[A] ----> [P] ------> [X]
[B] ----> [Q] ------> [Y]
[C] ----> [R] ------> [Z]
let myOptions = {
sankey: {
link: {
interactivity: true
}
}
}
...
...
<Chart
chartType='Sankey'
data={
[
['From', 'To', 'Weight', {role: 'tooltip', type: 'string'}],
['A', 'P', 1, 'i111'],
['B', 'Q', 1, 'j333'],
['C', 'R', 1, 'k444'],
['P', 'X', 1, 'l555'],
['Q', 'Y', 1, 'l666'],
['R', 'Z', 1, 'n999']
]
}
columns
options={myOptions}
chartEvents={[
{
eventName: 'select',
callback: ({chartWrapper}) => {
const chart = chartWrapper.getChart()
const selection = chart.getSelection()
if (selection.length === 1) {
const [selectedItem] = selection
const {row} = selectedItem
// below line was working until recently, but not anymore
console.log(chartWrapper.getDataTable().Vf[row].c)
// updated the property key after which it works
console.log(chartWrapper.getDataTable().Wf[row].c)
// returns [{v: 'A'}, {v: 'P'}, {v: 1}, {v: 'i111'}]
}
}
}
]}
/>
I can also get the selection data like this but it does not give me the final column value i.e., tooltip in this case.
console.log(chartWrapper.getDataTable().cache[row])
// returns [{Me: 'A'}, {Me: 'P'}, {Me: '1'}]
Is there any other way for me to get the data apart from what I have done above? Especially the line
chartWrapper.getDataTable().Wf[row].c
Having a property value hardcoded has broken my UI thrice in recent times and I would like to avoid doing so.
to my knowledge, the sankey chart will only allow you to select the nodes,
not the links between the nodes.
and this is only allowed after setting the interactivity option.
options: {
sankey: {
node: {
interactivity: true
}
}
}
the selection returns the name of the node selected,
which can appear in the data table multiple times.
in the following example, I've added an additional "P" node to demonstrate.
when the select event fires, you can get the name of the node selected from the chart's selection.
then you must search through the rows in the data table to find the row with the matching node name.
once you've found the data table row for the selected node name,
you can use data table method getValue to retrieve the values for that row.
see following working snippet...
google.charts.load('current', {
packages: ['controls', 'sankey']
}).then(function () {
var chartWrapper = new google.visualization.ChartWrapper({
chartType: 'Sankey',
containerId: 'chart',
dataTable: google.visualization.arrayToDataTable([
['From', 'To', 'Weight', {role: 'tooltip', type: 'string'}],
['A', 'P', 1, 'i111'],
['B', 'Q', 1, 'j333'],
['C', 'R', 1, 'k444'],
['P', 'X', 1, 'l555'],
['P', 'Y', 2, 'l555'],
['Q', 'Y', 1, 'l666'],
['R', 'Z', 1, 'n999']
]),
options: {
sankey: {
node: {
interactivity: true
}
}
}
});
google.visualization.events.addListener(chartWrapper, 'ready', function () {
google.visualization.events.addListener(chartWrapper.getChart(), 'select', selectEvent);
});
chartWrapper.draw();
function selectEvent() {
var chart = chartWrapper.getChart();
var data = chartWrapper.getDataTable();
var selection = chart.getSelection();
if (selection.length > 0) {
// find data table rows for selected node name
var nodeName = selection[0].name;
var nodeRows = data.getFilteredRows([{
column: 0,
value: nodeName
}]);
// find row values for selected node name
nodeRows.forEach(function (row) {
var valFrom = data.getValue(row, 0);
var valTo = data.getValue(row, 1);
var valWeight = data.getValue(row, 2);
var valTooltip = data.getValue(row, 3);
console.log(valFrom, valTo, valWeight, valTooltip);
});
}
}
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart"></div>

SVG Path length in Leaflet Routing Machine

I am using Leaflet Routing Machine to create map route.
My requirement is, if there are multiple locations like A, B, C, D, E. I am getting the length of svg path from A to E. But i need length form A to B, B to C, C to D, D to E. Please help someone.
click to see image
Red color line is svg path. So, when i click on any marker then i need length from basel to that marker. i mean, i need to get length from basel to neuchatel or basel to bern or neuchatel to bern, etc.
var routeControl = L.Routing.control({
waypoints: waypoints,
reverseWaypoints: false,
lineOptions: {
styles: [{color: 'red', opacity: 1, weight: 3}]
},
geocoder: L.Control.Geocoder.nominatim({
serviceUrl: 'http://localhost:8084/'
}),
createMarker: function(i, wp, nWps) {
console.log(wp)
let custom_icon = L.divIcon({
iconSize: [100, 20],
popupAnchor: [-30, -18],
shadowUrl: '',
html: '<div class="notification '+wp.name+'" data-pathid="'+(i+1)+'" style="color: #000;background-color: transparent;"><img src="img/blue.png"><span class="city-name">' + latlng[i].name + '</span></div>'
})
marker = L.marker(
[wp.latLng.lat, wp.latLng.lng],
{
icon: custom_icon
})
.bindPopup(latlng[i].name)
.openPopup()
.addTo(map);
// marker.on('click', onMarkerClick);
}
}).addTo(map);

How can I change the behaviour of bindPopup

Good day everybody.
I bought a nice template and leaftlet is used to show maker.
Here is the demo . Actually when you clik on a marker, it open a widnows with a picture and some température value.
I would like to have all of the windows open. Of course, I am going to modify the html, to remove the picture and some information as GPS, and only keep the temperatue value. The goal is to be able to immediately see the temperature boxes below the markers. Optionaly, when I click on the marker it redirect to another page, same you click on the picture.
My first problem, I can not find the jacasvript script which work with the link of marker. The idea would be to cancel the effect of the click, or as I wrote, after we click it open the graph page instead of opening the windows.
My first question: how can I find a do to change the action of the click, on the marker
My second question (may be it be cancel the 1st question :) ), how can I change the behaviour of the bindpopup? Is there way "to tell" to the bindpopup, stay always open?
My thirst question: Or can we add one or two additional nice boxes, which show always the temperature below the marker, and keep the bindPopup, as it is? That would be nice as well
Here is the code of the map line 215
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// OpenStreetMap - Homepage
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function createHomepageOSM(_latitude,_longitude,_nbField){
setMapHeight();
if( document.getElementById('map') != null ){
var map = L.map('map', {
center: [_latitude,_longitude],
zoom: 18,
scrollWheelZoom: false
});
//L.tileLayer('http://openmapsurfer.uni-hd.de/tiles/roadsg/x={x}&y={y}&z={z}', {
L.tileLayer('http://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', {
//subdomains: '0123',
maxZoom: 20,
attribution: 'OpenStreetMap contributors, CC-BY-SA'
}).addTo(map);
var markers = L.markerClusterGroup({
showCoverageOnHover: false
});
function locateUser() {
$('#map').addClass('fade-map');
map.locate({setView : true})
}
$('.geo-location').on("click", function() {
locateUser();
});
$.ajax({
type: "POST",
url: "sql/get_map.mysql.php",
//data:'node=node1',
//data:{node_id:"firstnode", node2:"secondnode", node3:"thirdnode", from:"from", to:"to"}, // Send parameter to get.php
success: result,
error: error,
dataType: "json"
});
function error(data)
{
$('body').addClass('loaded');
alert("Error getting datas from DB");
console.log("Error getting datas from DB");
console.log(data);
}
function result(data){
console.info("data:",data);
var allMarkers=[];
var nhtml = '<img src="assets/img/property-types/vineyard.png">';
for (var i = 0; i < data.properties.length; i++) {
allMarkers.push(L.latLng(data.properties[i]['la'], data.properties[i]['lo']));
//data.properties[i]['b2'] = 0;
if((data.properties[i]['b1']>=data.properties[i]['se'] && data.properties[i]['b1'] < data.properties[i]['se']+1) ||
(data.properties[i]['b2']>=data.properties[i]['se'] && data.properties[i]['b2'] < data.properties[i]['se']+1) ||
(data.properties[i]['b3']>=data.properties[i]['se'] && data.properties[i]['b3'] < data.properties[i]['se']+1) ||
(data.properties[i]['b4']>=data.properties[i]['se'] && data.properties[i]['b4'] < data.properties[i]['se']+1)
)
{
nhtml = '<img src="assets/img/property-types/vineyard-orange.png">';
}
if(((data.properties[i]['b1'] < data.properties[i]['se']) && data.properties[i]['b1'] != null) ||
((data.properties[i]['b2'] < data.properties[i]['se']) && data.properties[i]['b2'] != null) ||
((data.properties[i]['b3'] < data.properties[i]['se']) && data.properties[i]['b3'] != null) ||
((data.properties[i]['b4'] < data.properties[i]['se']) && data.properties[i]['b4'] != null)
)
{
nhtml = '<img src="assets/img/property-types/vineyard-red.png">';
}
else{
nhtml = '<img src="assets/img/property-types/vineyard.png">';
}
var _icon = L.divIcon({
//html: '<img src="' + locations[i][7] +'">',
html: nhtml,
iconSize: [40, 48],
iconAnchor: [20, 48],
popupAnchor: [0, -48]
});
var title = data.properties[i]['station'];
var marker = L.marker(new L.LatLng(data.properties[i]['la'],data.properties[i]['lo']), {
title: title,
icon: _icon
});
var str ='';
if(data.properties[i]['b1'] != null)
{
str = str.concat('<div class="tag price"> ' + data.properties[i]['b1'] + '°C</div>');
}
if(data.properties[i]['b2'] != null)
{
str = str.concat('<div class="tag price"> ' + data.properties[i]['b2'] + '°C</div>');
}
if(data.properties[i]['b3'] != null)
{
str = str.concat('<div class="tag price"> ' + data.properties[i]['b3'] + '°C</div>');
}
if(data.properties[i]['b4'] != null)
{
str = str.concat('<div class="tag price"> ' + data.properties[i]['b4'] + '°C</div>');
}
marker.bindPopup(
'<div class="property">' +
'<a data-field=' + data.properties[i]['id_field'] +'" data-station=' + data.properties[i]['id_station'] +'" href="charts.php?field='+ data.properties[i]['id_field'] +'">' +
'<div class="property-image">' +
'<img src="img/stations/station-' + data.properties[i]['id_station'] + '.jpg">' +
'</div>' +
'<div class="overlay">' +
'<div class="info">' +
'<h3>' + data.properties[i]['station'] + '</h3>' +
'<figure>' + data.properties[i]['da'] + '</figure>' +
'<figure>' + data.properties[i]['la'] + ' ' + data.properties[i]['lo'] +'</figure>' +
str +
'<div class="tag"> ' + data.properties[i]['se'] + '°C</div>' +
'</div>' +
'</div>' +
'</a>' +
'</div>'
);
markers.addLayer(marker);
}
if(_nbField>1){
bounds = L.latLngBounds(allMarkers);
map.fitBounds(bounds,{ padding: [10, 10] });
}
map.addLayer(markers);
map.on('locationfound', onLocationFound);
function onLocationFound(){
$('#map').removeClass('fade-map');
}
$('body').addClass('loaded');
setTimeout(function() {
$('body').removeClass('has-fullscreen-map');
}, 1000);
$('#map').removeClass('fade-map');
}
}
}
My last question, with firefox, id possible "to track" the javascript action?
Feel free to aks complementary question to better understand and help, if I missed to provide information.
Many thanks
You can add a click event to the marker:
marker.on('click',(e)=>{
console.log(e);
});
Show all Popups:
You need to set the options autoClose and closeOnClick to false:
marker.bindPopup(content,{autoClose: false, closeOnClick: false});
You can use Tooltips:
marker.bindTooltip('5.3°C', {direction: 'bottom', permanent: true});
I don't know exactly what do you mean, but it sounds like debugging. Use the developer console with the Debugger.
Thanks for your reply and help
Unfortunately 2. does not work. There is no differences. I added closeButton:true, and that works, but it's not what I need.
marker.bindPopup(
'<div class="property">' +
'<a data-field=' + data.properties[i]['id_field'] +'" data-station=' + data.properties[i]['id_station'] +'" href="charts.php?field='+ data.properties[i]['id_field'] +'#st-'+ data.properties[i]['id_station'] +'">' +
'<div class="property-image">' +
'<img src="img/stations/station-' + data.properties[i]['id_station'] + '.jpg">' +
'</div>' +
'<div class="overlay">' +
'<div class="info">' +
'<h3>' + data.properties[i]['station'] + '</h3>' +
'<figure>' + data.properties[i]['da'] + '</figure>' +
'<figure>' + data.properties[i]['la'] + ' ' + data.properties[i]['lo'] +'</figure>' +
str +
'<div class="tag"> ' + data.properties[i]['se'] + '°C</div>' +
'</div>' +
'</div>' +
'</a>' +
'</div>',{autoClose: true, closeOnClick: false, closeButton: true}
);
I also tried the interesting option with tooltip. Bellow the above code I added
marker.bindTooltip('5.3°C', {direction: 'bottom', permanent: true});
But that print an error message
marker.bindTooltip is not a function
Is there additionally library I have to add for tooltop, or is inlcuded into leafet.
(bindTootip would be great and enough for my need)
Thanks for helping
Cheers