When I attempt to convert a GeoJSON to an ArchGDAL geometry like seen below, I end up with a NULL Geometry. How would one convert a String GeoJSON notation to a geometry object?
using ArchGDAL
test = """{ "type": "FeatureCollection",
"features": [
{ "type": "Feature",
"geometry": {"type": "Point", "coordinates": [102.0, 0.5]},
"properties": {"prop0": "value0"}
}
]
}"""
ArchGDAL.fromJSON(test)
# NULL Geometry
Turns out the GeoJSON can be read by simply using ArchGDAL.read(), (and, in this example extracting the first layer using ArchGDAL.getlayer())
ArchGDAL.getlayer(ArchGDAL.read(test), 0)
# Layer: OGRGeoJSON
# Geometry 0 (): [wkbPoint], POINT (102.0 0.5)
# Field 0 (prop0): [OFTString], value0
Related
I am trying to pass the following JSON into a function in R.
The raw JSON
{
"type": "Polygon",
"coordinates": [
[
[-122.68,42.77],
[-116.53,42.77],
[-116.53,44.30],
[-122.68,44.30],
[-122.68,42.77]
]
]
}
And here's the call to an R function:
myfunction(api_endpoint="my_api_endpoint", args=list(arg1 = 2000, arg2=MY_JSON_HERE)
I have tried escaping quotes, wrapping in single quotes and I keep getting errors about curly braces etc.
How do I take that literal JSON string and send it into an R function please?
With R>4.0 the new raw string syntax r"(...)" avoids the quotes / double quotes hassle:
json <- r"(
{
"type": "Polygon",
"coordinates": [
[
[-122.68,42.77],
[-116.53,42.77],
[-116.53,44.30],
[-122.68,44.30],
[-122.68,42.77]
]
]
}
)"
f <- function(json) {jsonlite::fromJSON(json)}
f(json)
$type
[1] "Polygon"
$coordinates
, , 1
[,1] [,2] [,3] [,4] [,5]
[1,] -122.68 -116.53 -116.53 -122.68 -122.68
, , 2
[,1] [,2] [,3] [,4] [,5]
[1,] 42.77 42.77 44.3 44.3 42.77
Otherwise, in this case, you could also pass json as string with simple quotes :
json <- '{
"type": "Polygon",
"coordinates": [
[
[-122.68,42.77],
[-116.53,42.77],
[-116.53,44.30],
[-122.68,44.30],
[-122.68,42.77]
]
]
}
'
The simple trick that helped me was to transform the json string, that is input into the function, via fromJSON:
myfunction <- function(json){
jsonlite::fromJSON(json)
}
That way the string is no longer interpreted as a character string, which messes things up with backslashes etc., but as an atomic list object with json structure.
I am working with a pre-specified API definition, which I need to adhere to:
"myTable": {
"split": [
{
"total": 0,
"perItem": [
0,
0,
0
]
}
]
the results from my function are a list (since I am using an apply):
Export
[[1]]
[[1]]$total
[1] 13
[[1]]$perItem
1 2 3
5 7 0
but when I convert this to .json, it is not the same format as the predefined API definition:
toJSON(Export)
[{"total":[13],"perPlan":[5,7,0]}]
I was wondering how I can convert the output of the apply to have the predefined API?
I tried converting this to array:
toJSON(array(Export), simplify = TRUE)
[{"total":[13],"perPlan":[5,7,0]}]
but this still has the additional [] around the content of total.
According to the API specification your input should also "embed" your data into this split and mytable list, which can be done with:
Export <- list(list(total = 13,
perItem = c(5, 7, 0)))
for_JSON <- list(mytable = list(split = Export))
toJSON(for_JSON, simplify = TRUE, pretty = TRUE)
which gives:
{
"mytable": {
"split": [
{
"total": 13,
"perItem": [5, 7, 0]
}
]
}
}
This looks like what the API wants.
I have a CosmosDB container with 10000 documents. Every document contains a random (geography) Point that is within a specific bounds.
I am using the CosmosDB emulator and Azure Cosmos DB .NET SDK (v3) to perform some geo-spatial queries. however, queries using ST_INTERSECTS and ST_WITHIN are giving different results than a query using latitude and longitude min/max values, as illustrated below:
1 - Query using explicit latitude / longitude minimum and maximum values - gives the correct result:
SELECT r.id FROM testcontainer r
WHERE r.lat >= 53.393183 AND r.lat <= 53.657421
AND r.lon >= -113.733431 AND r.lon <= -113.247049
Query Total time: 00:00:00.1293465
Total Request Units consumed: 244.15
Documents found: 10000
2 - Query using ST_INTERSECTS - should have the same result as query #1?
SELECT r.id FROM testcontainer r
WHERE ST_INTERSECTS( r.geopoint, {'type':'Polygon','coordinates':[[[-113.247049,53.657421],[-113.733431,53.657421],[-113.733431,53.393183],[-113.247049,53.393183],[-113.247049,53.657421]]]})
Query Total time: 00:00:00.3134729
Total Request Units consumed: 226.17000000000002
Documents found: 9994
3 - Query using ST_WITHIN - should have the same result as query #1?
SELECT r.id FROM testcontainer r
WHERE ST_WITHIN( r.geopoint, {'type':'Polygon','coordinates':[[[-113.247049,53.657421],[-113.733431,53.657421],[-113.733431,53.393183],[-113.247049,53.393183],[-113.247049,53.657421]]]})
Query Total time: 00:00:00.3107136
Total Request Units consumed: 962.91
Documents found: 9994
All of the queries above should have returned 10000 documents -- but the ST_INTERSECTS and ST_WITHIN seem to fall short and only query #1 gives the correct result - I cannot explain why.
Does anyone have any insights as to why ST_WITHIN and ST_INTERSECTS would not give the same result as the query with explicit latitude / longitude values?
Additional Information:
When I do the following query:
SELECT r.id, r.geopoint FROM testcontainer r
WHERE NOT ST_INTERSECTS( r.geopoint, {'type':'Polygon','coordinates':[[[-113.247049,53.657421],[-113.733431,53.657421],[-113.733431,53.393183],[-113.247049,53.393183],[-113.247049,53.657421]]]})
The query result is the missing 6 documents - but looking at the results, there is only one result with a longitude value of -113.247049 that matches a longitude value specified in the bounds.
[
{
"id": "6892de3d-4b8a-42c6-8421-18b65a70146f",
"geopoint": {
"type": "Point",
"coordinates": [
-113.465305,
53.393386
]
}
},
{
"id": "6b89e0fc-7f65-4f75-90db-63dc599b98dd",
"geopoint": {
"type": "Point",
"coordinates": [
-113.247049,
53.623584
]
}
},
{
"id": "467a388a-f0fd-4717-9eb5-3a8f538df38b",
"geopoint": {
"type": "Point",
"coordinates": [
-113.302698,
53.393212
]
}
},
{
"id": "ada61462-5131-4e25-b0be-3bee42fcde05",
"geopoint": {
"type": "Point",
"coordinates": [
-113.362105,
53.393276
]
}
},
{
"id": "3bfd30a7-abcd-4216-905f-5a3831869626",
"geopoint": {
"type": "Point",
"coordinates": [
-113.340676,
53.393227
]
}
},
{
"id": "c259a408-e6f0-4050-b7ad-6f55d9a614da",
"geopoint": {
"type": "Point",
"coordinates": [
-113.400457,
53.393275
]
}
}
]
Below is an Excel (screen snapshot) that shows the delta (difference) between the bounds lat/lon values and those from the "missing" documents:
Looking at the differences, a small deviation will exclude some points when using ST_WITHIN / ST_INTERSECTS as per the answer given by Michael Entin.
Thanks.
That's the difference between geography (shapes on a sphere with geodesic edges) and geometry (shapes on a flat map with edges that look straight on that map).
If you work with geography, the "horizonal" edges of your GeoJson "rectangle" follow geodesics and thus bend a bit towards poles. Thus the rectangle describes a slightly different shape from what you expect.
If the min/max results in your first query are what you want - switch to geometry.
I'd like to plot progress versus timeline on a 2 x-axis bullet chart.
See this JSFiddle for what I currently have: http://jsfiddle.net/ejhnnbk0/
Highcharts.chart('container3', {
xAxis: [{
type: 'linear',
},{
type: 'datetime',
opposite: true
}],
yAxis: {
plotBands: [{
from: 0,
to: 14,
color: '#f00'
}, {
from: 14,
to: 20,
color: '#ff0'
}, {
from: 20,
to: 29,
color: '#0f0'
}],
labels: {
format: '{value}'
},
title: null
},
series: [{
data: [{
y: 16,
target: 21
}]
}],
tooltip: {
pointFormat: '<b>{point.y}</b> (with target at {point.target})'
}
});
What I am looking to implement is something like this, where a date range is on the top x-axis, and a numeric range is on the bottom x-axis. I'd like the bullet to represent progress (in this case, 16 out of 24), and I'd like the target line to indicate the current date in the date range (in this case, somewhere before 02/12/2018).
Any thoughts would be appreciated.
Yes, it's possible.
Fist of all notice that your chart is inverted so you need to add another y axis (not x).
There're going to be 2 series: first that displays column (associated with first y axis) and second that displays target (associated with second y axis). In this case grouping has to be disabled (otherwise column and target won't be aligned properly).
Since there's no need to show target for the first series it's type can be changed to column:
series: [{
type: 'column',
data: [{
y: 16,
}]
}, {
yAxis: 1,
data: [{
target: Date.UTC(2018, 0, 7)
}]
}]
Live demo: http://jsfiddle.net/BlackLabel/e847jztb/
I'm using the leafletR package (http://cran.r-project.org/web/packages/leafletR/index.html) to make a leaflet webmap applet, but having trouble loading 2 sets of features onto the same map.
As I understand it, the leaflet() function will only accept GeoJSON files of one geometry type.
I therefore have 2 separate GeoJSON files, one with MultiPolygons and another with Points.
I'm able to get the MultiPolygons to render as a choropleth with this code:
#Load LeafletR
require(leafletR)
#Create quantiles
cuts <- round(quantile(UKpostcode_areas$data, probs = seq(0, 1, 0.20), na.rm = FALSE), 0)
cuts[1] <- 0 #We don't want any negative values, so let's make the first cut zero
#Fields to include in the popup
popup.1 <- c("name", "data")
#Graduated style based on an attribute
sty.1 <- styleGrad(prop = "data", breaks=cuts, right=FALSE, style.par="col", style.val=rev(heat.colors(6)), leg="Data", lwd=1)
#Create the map and load into browser
map <- leaflet(data = "map/UKpostcode_areas.geojson", dest = "map", style = sty.1, title = "UKpostcode_areas_choropleth", base.map= "osm", incl.data=TRUE, popup = popup.1)
I'm also able to get the Points to render:
#Create new style and popup details for the 2nd layer
sty.2 <- styleSingle(col = "white", fill = "#2b83ba", fill.alpha = 1, rad = 3)
popup.2 <- c("name", "trust")
#Let's take a look at the map of hospitals
map2 <- leaflet(data="map/hospitals.geojson", dest = "map", style = sty.2, popup = popup.2, title = "hospitals", base.map = "osm", incl.data=TRUE, controls = "all")
browseURL(map2)
However, when I try to render both on the same Leaflet map, it just gives me a blank screen:
#Now we can combine the 2 into 1 map, this is problematic, can't get it to work!
map3 <- leaflet(data = list("map/UKpostcode_areas.geojson", "map/hospitals.geojson"), style = list(sty.1, sty.2), dest = "map", title = "index", base.map= "osm", incl.data=TRUE, controls = "all")
browseURL(map)
I suspect there's something wrong with the last couple of lines of code. But I can't figure out what.
I believe LeafletR can only handle multiple layers when there is a single style for each layer.
Example from the leaflet() documentation page:
# more than one data set
park <- toGeoJSON(data=system.file(package="leafletR", "files",
"park_sk.zip"), dest=tempdir())
peak <- toGeoJSON(system.file(package="leafletR", "files", "peak_sk.kml"),
dest=tempdir()) # httr package required
sty.1 <- styleSingle(col="green", fill="green")
sty.2 <- styleSingle(col="brown", fill="brown", rad=3)
map <- leaflet(data=list(park, peak), dest=tempdir(),
style=list(sty.1, sty.2))
browseURL(map)
This works as expected, but if you change sty.2 to a graduated style, eg:
sty.2 <- styleGrad(prop="Name", col="brown", fill="brown", style.par="rad",
style.val=c(1,10), breaks=breaks, right=TRUE, out=1)
it gives the same blank screen you described (though it works fine if peak is the only layer). I'm not sure how crucial it is that your map has a graduated style, but if you use styleSingle(), both layers should appear.
What i'm thinking (guessing actually, i'm by no means familiar with R) is that combining those two GeoJSON files won't work if they're actually FeatureCollections. A FeatureCollection would look something like this:
{
"type": "FeatureCollection",
"features": [{
// Feature
}, {
// Another feature
}]
}
Now if you combine two of those you'll end up with something like this:
[{
"type": "FeatureCollection",
"features": [{
// Feature
}, {
// Another feature
}]
}, {
"type": "FeatureCollection",
"features": [{
// Feature
}, {
// Another feature
}]
}]
Leaflet's L.GeoJSON layer won't take that. What you want to do is merge the embedded feature arrays, and embed that into a new FeatureCollection object or just merge the two feature arrays into one new array and use that. L.GeoJSON can use a FeatureCollection or an array of features. But it won't take an array of FeatureCollections and thats what i think you are doing now.
In JS i would do something like this:
var collectionA = { //FeatureCollection };
var collectionB = { //FeatureCollection };
var features = collectionA.features.concat(collectionB.features);
var collection = {
"type": "FeatureCollection",
"features": features
}
// Now you can use:
new L.GeoJSON(features);
// Or you can use:
new L.GeoJSON(collection);
Another way is to use the addData method of L.GeoJSON but i wouldn't know if that's available to you when using LeafletR, but in JS we can do:
var collectionA = { //FeatureCollection };
var collectionB = { //FeatureCollection };
var layer = new L.GeoJSON();
layer.addData(collectionA);
layer.addData(collectionB);
Hope that helps.