Get the number of features displayed on a map after a filter (with featuresIn) - mapbox-gl-js

First of all, I'm aware that querySourceFeatures could fix that. But unfortunately the new version is effective with all types but not with symbols, which I'm using. So I'm still coding under version 0.14.x.
That said, I filter my map with the setFilter function and I need to catch back the number of features displayed once the filter is done.
I thought about transform the whole world (-90,-180,90,180) map coordinates into pixels and then pass it into a featuresIn function.
With fiddle below, featuresIn returns nothing [EDIT : that was due to not setting interacive : true, now it's done but issue is still here]. Do you have any idea how to get the number of features displayed on my map?
EDIT : Please find my jsFiddle : https://jsfiddle.net/y7hoa0gy/7/

No features are being returned from featuresIn because you did not set "interactive": true on the "route" layer, as specified in the documentation (but no longer on our official docs page because we have changed this API).
/*Now I want to know how many features are still displayed after that filter
My thought was to get the bbox of the whole map (-180,-90,180,90) and make a featuresIn of that bbox.*/
More fundamentally, this approach will not work. featuresIn only returns features in the current viewport. It does not return all features.

Related

Open Street Map tag to grab all emerged land

I'm looking to download the geometries of all emerged land (everything within the coastal line) in Python using OSMNX, but can't seem to find a general tag that would do it.
Right now, I'm using:
t = {'landuse':['commercial', 'industrial', 'residential', 'farmland', 'construction', 'education', 'retail', 'cemetery', 'grass', 'garages', 'depot', 'port', 'railway', 'recreation_ground', 'religious', 'yes', '*'], 'leisure':['park']}
land = ox.geometries_from_polygon(bbox, tags=t)
But I still have many holes...
So, in short, is there an OSM tag to grab all emerged land?
The additive approach, i.e. combining all sorts of landuses, won't get you all the way to the result you want. As you've noticed, you'll end up with white spots. You could get closer by considering even more tags, such as some values of the natural=* key, but ultimately there simply is land that is not covered by any such polygon in OSM.
Instead, you should look at OSM coastline data. As this can be tricky to process, you might want to get pre-processed data from osmdata.openstreetmap.de, such as their land polygons.

osmnx boundaries and admin_level

I hope someone here can help me to retrieve the correct administration level(s) from OSM. I am using the following code, but admin_level seems to be ignored:
tags = {"boundary":"administrative","admin_level":"4" }
gdf =ox.geometries.geometries_from_bbox(51.5, 51.0, 11.7, 11.2, tags)
gdf.shape
The bounding box seems to be used as a polygon to create an intersection with all the boundaries in the OSM database, the first tag is working because only administrative boundaries are returned, but the filter on level is ignored (gdf["admin_level"].head() shows level 6).
I would like to understand what I am doing wrong, and how I can use this package better; it seems like a very useful library.
Thanks,
Gijs
Result using the bounding box:
OK, rereading the documentation again made me realize that osmnx is using [OR] statements and not [AND] statements as I was presuming; removing the boundary request from the query is indeed giving only admin_level:4 results.
tags (dict) – Dict of tags used for finding objects in the selected area. Results returned are the union, not the intersection of each individual tag.
Some additional code: https://i.stack.imgur.com/Fw840.png

How to query points with a polygon layer using Bootleaf / esri-leaflet?

I am using the Bootleaf IAG framework.
I can not figure out how to get the bounding coordinates of a filtered layer.
I am modifying the bootleaf code to query points with a polygon layer. The Query Widget already allows users to draw a polygon, but I want to select a polygon from a layer hosted on my arcgis server. I modified the filter widget by removing the text field and allowing my users to select polygon layers and values from a dropdown menu. This works fine.
Now I need to take the result of the layer.setWhere(where, handleError); code and merry it with the query below. I need selectedPolygon to equal the result of layer.setWhere(where, handleError); and use the bounding coordinates in the .within section of the query.
I have tried a number of things, L.latLngBounds, getBounds(), and toGeoJSON().features[0].geometry.coordinates to name a few, but but I can not figure out how to pull out the bounds. What is the correct code?
const query = L.esri.query({ url: pointInPolygonUrl })
.token(pointInPolygonData.token)
.within(selectedPolygon)
query.run(function (error, data, response) {
if (error) {
console.log(error);
return;
}
6/8/2021 Edit (based on Seth Lutske's comment:
I did not provide a code sandbox for two reasons: 1 - bootleaf has a lot of files, 2 - all of my layers require secure sign in to arcgis. Hopefully I can provide enough information to get assistance without it.
Is selectedPolygon changing the way I am expecting? Currently there
is no variable called selectedPolygon because I can not figure out
the correct way to format it. selectedPolygon is what I want to
call the filter result layer.setWhere(where, handleError);. I set
the polygon layer up to filter on the map as the value changes. I
can verify it is filtering as expected.
selectedPolygon format - This is where my problem lies. I can not
seem to find the correct format based on how bootleaf layers are
configured. I started with var selectedPolygon =
layer.features.geometry.coordinates; and got a geometry undefined
error. I proceeded to try every other code I could think of to get
the bounds.
Bounding coordinates may not be the proper terminology. I want to
run a query to find all of the points within the filtered polygon.
To achieve this, it is my understanding that I need to use the
bounds of the filtered polygon in the within section of the query.
6/8/2021 Edit #2
This link may be most beneficial to show how the layer is constructed. I modified this code to remove the text input and add a dropdown, but the basic definition should be the same.
Line 1605 is function addFilter()
Line 1804 is function applyFilter()
Line 1927 is layer.setWhere(where, handleFilterError);
Photo 1: console.log("polygon layer", layer)
Photo 1
Photo 2: Expanded _layers
Photo 2
Photo 3: Expanded _rings (I did not find ToGetJSON, but I found ToGeoJSON in this section.
Photo 3
It looks like if I can get to _rings then I should be fine, but that is where my knowledge is lacking.
I don't know much about bootleaf, but here are some tips to get you started. Based on your question and comments, this will hopefully clear things up and instruct you on how to apply what you need in your scenario.
Hook UI to setWhere
When the user selects an option from the UI, you can call setWhere on the layer you're providing from the arcgis server. Let's say there's a polygon layer, in my example, called statesFeatureLayer, which is an L.esri.featureLayer
// Create polygon layer of states
const statesFeatureLayer = EL.featureLayer({
url: "polygon_featurelayer_url_from_arcgis_server"
}).addTo(map);
And there's a point layer:
// Create points layer
const pointsFeatureLayer = EL.featureLayer({
url: "points_featurelayer_url"
}).addTo(map);
Now there is some UI, which has to trigger setWhere to be called on this layer. So anywhere in the UI where you want to run this functionality of setting the filter on the layer, and then querying the other layer based on the results, we'll run a function call runQuery:
function runQuery(){
statesFeatureLayer.setWhere(querystring, callback)
}
Run callback after setWhere fires
It sounds like you've already got this part figured out, and that your setWhere function is running properly. However, setWhere also takes an optional callback function as its second argument, which runs after the where has been set and the layer refreshed. Let's dig into that. In the callback, we're going to want to get all the features that are currently active on the map:
function runQuery(){
statesFeatureLayer.setWhere(querystring, () => {
statesFeatureLayer.eachActiveFeature(feature => {
// do something with features
})
})
}
Run query to test points layer against active features of polygon layer
Within eachActiveFeature, we can run a query on the pointsFeatureLayer:
function runQuery(){
statesFeatureLayer.setWhere(querystring, () => {
statesFeatureLayer.eachActiveFeature(feature => {
pointsFeatureLayer
.query()
.within(feature.toGeoJSON())
.run((error, data) => {
console.log(data);
});
})
})
}
So now were are running a query which asks for any points in the pointsFeatureLayer that are in the geometry of each active feature of the statesFeatureLayer.
The downside of this is that we can't run a query against all the active features as a group. The within query method (along with most of the other query methods) can accept singular features, whether in the form of an L.Polygon, L.Polyline, or an L.GeoJSON. While I had tried creating an L.featureGroup and calling .toGeoJSON on that, within seems to require a GeoJSON that describes only a single shape. So if you have multiple features, you'll have to conglomerate them. For example, you may have some variable results = [] at the global scope level, then within the callback of run, you can push the results to results, which will give you all results in one variable. This may take some massaging in js to get it right.
Working Codesandbox
Here you have 2 UI elements which cause runQuery to run. Either the dropdown, or the checkbox. You'll see that on every UI change, setWhere is called with a querystring constructed from the UI (setWhere for a state, and setwhere for that state and california if the checkbox is checked). When setWhere is called, its callback then runs a query against the point layer just for the currently active features, and then returns whatever points from the pointlayer are within each of the active features.

Projection anomaly between function vs string projection definition

We recently switched our definitions from the first to the second format, because OpenLayers threw exceptions on the first one.
The used definitions:
Old:
proj4.defs["EPSG:28992"] = "+proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel +towgs84=565.417,50.3319,465.552,-0.398957,0.343988,-1.8774,4.0725 +units=m +no_defs";
New:
proj4.defs("EPSG:28992", "+proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel +towgs84=565.040,49.910,465.840,-0.40939,0.35971,-1.86849,4.0772 +units=m +no_defs")
Strange enough, the latter one does correctly transform points. Our points seem to be misaligned, and not by a specific offset, they seem to be just wrong positioned at all. We think this is due to the towgs84 property. Question now is, how is the first format parsed/ handled differently than the secondly? What are the differences? (I am using the same code and newest version of proj4js in both occasions).
I was accidentally loading pro4j twice, once trough potree, and once manually (for openlayers). Turned out one of the two was still on version 2.2.1...

Remove Matlab r2014b Plot Browser limit

Among many distressing graphics changes to r2014b, the Plot Browser now only displays a certain number of lines per plot (looks like the limit is 50). Any number of plots above this limit are not displayed in the Plot Browser - it just says "and 78 more..."
Is there anyway to remove the limit? I want to see all my lines in the plot browser.
Unfortunately the answer is currenty:
No you cannot remove this limit
This was already reported to mathworks a while ago, and here is the reply:
I am writing in reference to your Technical Support Case #01143663
regarding 'plot browser with "and xxxx more...." indication'.
Really interesting question (and even a bit surprising). Basically
this limitation has been introduced with MATLAB 2014b!
Our developers are aware of that, and they are working to solve it. An
enhancement/bug request has been already submitted, and I am going to
add this case to the list. However, I cannot guarantee you a release
date.
If you think this limitation is crucial for your work, I would
strongly suggest you to contact your account manager, which will have
a bit more influence on the developers than a simple engineer :).
Of course, if there is anything else I can do for you, please let me
know
So it seems that you will have to deal with this limitation if you keep using 2014b.
This was also an issue for me; in particular I wanted to see the DisplayName property of the graphics object in the list. I used a workaround where I created a callback function, so that when clicking on a data point, the DisplayName would be shown. This can be helpful if you have a plot of many lines and want to see the DisplayName of a particular one. You would first need to set the DisplayName property of the graphics objects for this to work, as it's empty by default. You could also use this to show other properties, such as Color or LineStyle, that are shown in the plot browser:
%Based on
%http://www.mathworks.com/help/matlab/ref/datacursormode.html
%'fig_h' is the figure handle
dcm_obj = datacursormode(fig_h);
set(dcm_obj,'UpdateFcn',#myupdatefcn)
And then include this function as a separate file on the Matlab path, or paste into the function you're currently writing, and include an extra 'end' at the end of that function:
function name = myupdatefcn(empt,event_obj)
% Customizes text of data tips
tar = get(event_obj,'Target');
name = get(tar,'DisplayName');
end