I'm using rCharts Leaflet maps to display polygons on map on R.
Using the Leaflet's geoJson I created some polygons and added them to the map. However, those polygons are filled with a default blue color. I'm trying to give them a different color, but no success.
For an example, I used the folloeing JSON, tested it in geojson.io and it came up green, however the R package still plots it in blue, how can I enforce the color?
JSON:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"stroke": "#555555",
"stroke-width": 2,
"stroke-opacity": 1,
"fill": "#00f900",
"fill-opacity": 0.5
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-74.06982421875,
40.64730356252251
],
[
-74.06982421875,
40.79717741518769
],
[
-73.80615234375,
40.79717741518769
],
[
-73.80615234375,
40.64730356252251
],
[
-74.06982421875,
40.64730356252251
]
]
]
}
}
]
}
R:
jsonx <- (JSON above)
polys = RJSONIO::fromJSON(jsonX)
map.center <- c(38,-95)
myMap<-Leaflet$new()
myMap$setView(map.center, 4)
myMap$tileLayer(provider = "Esri.WorldGrayCanvas")
myMap$geoJson(polys)
myMap$set(dom = 'myChart2')
myMap
While the rCharts implementation was nice, RStudio's leaflet package based on htmlwidgets is much more full-featured and robust. If you can use it instead, here is an answer. Note, nothing needs to be done. leaflet will pick up the fill in your geoJSON.
# uncomment to install the most recent from github
# devtools::install_github("rstudio/leaflet")
# or older cran #install.packages("leaflet")
library(leaflet)
gj <- '
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"stroke": "#555555",
"stroke-width": 2,
"stroke-opacity": 1,
"fill": "#00f900",
"fill-opacity": 0.5
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-74.06982421875,
40.64730356252251
],
[
-74.06982421875,
40.79717741518769
],
[
-73.80615234375,
40.79717741518769
],
[
-73.80615234375,
40.64730356252251
],
[
-74.06982421875,
40.64730356252251
]
]
]
}
}
]
}
'
leaflet() %>%
addTiles() %>%
setView( -74.1, 40.7, zoom = 10) %>%
addGeoJSON( gj )
# to show fill works let's change it with gsub
leaflet() %>%
addTiles() %>%
setView( -74.1, 40.7, zoom = 10) %>%
addGeoJSON(
gsub(
x = gj
,pattern = '(\\"fill\": \\"#00f900\\",)'
,replacement = ""
)
# demo addGeoJSON fillColor argument
,fillColor = 'green'
)
Related
I'm just getting started with Dataweave and trying to figure out how to transform data from this particular JSON response. I'm stumped after fairly exhaustively reading documentation and searching for examples. Can't find anything quite like it. Below is the payload I'm working with:
[
{
"columnMetadata": [
{
"name": "shape",
"columnIndex": 0,
"dataType": "string",
"schemaType": "Static"
},
{
"name": "color",
"columnIndex": 1,
"dataType": "string",
"schemaType": "Static"
}
],
"rowData": [
[
"square",
"yellow"
],
[
"circle",
"green"
],
[
"star",
"blue"
]
]
}
]
The transformation I'm trying to achieve is as such:
[
{
"shape": "square",
"color": "yellow"
},
{
"shape": "circle",
"color": "green"
},
{
"shape": "star",
"color": "blue"
}
]
Any help much appreciated!
The way to resolve this problem is by using dynamic objects This feature allows to dynamically compose an object from other objects or array the objects in this case. It is similar to the spread operator in js.
%dw 2.0
output application/json
---
payload flatMap ((item, index) -> do {
var metadataNames = item.columnMetadata map ((metadata, index) -> metadata.name)
---
item.rowData map ((datas, index) ->
{
(
datas map ((data, index) ->
{
(metadataNames[index]):data
}
)
)
}
)
})
This transform should work to get your output
payload..rowData flatMap (v) -> (v map ({shape: $[0], color: $[1]}))
If my understanding is correct, you wanted to pick data from rowData following the information found in columnMetadata (specific information will be picked based on columnIndex and key will be based on name i.e. shape should come from rowData[0] as columnMetadata.columnIndex is 0 and columnMetada.name is shape). This will mean that whatever information in columnMetadata will impact how you read the rowData.
You can attain this using combination of map and reduce. Reduce to iterate values of your columnMetadata and accumulate the result, and map to perform reduce for each member of your rowData.
See below dataweave:
%dw 2.0
output application/json
---
using (columnMetadata = flatten(payload.columnMetadata))
flatten(payload.rowData) map (row) -> columnMetadata reduce ((item, acc={}) -> acc ++ {(item.name): row[item.columnIndex]})
This will result to:
[
{
"shape": "square",
"color": "yellow"
},
{
"shape": "circle",
"color": "green"
},
{
"shape": "star",
"color": "blue"
}
]
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
126.9823439963945,
37.56461982743129
]
}
},
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[
126.9823439963945,
37.56461982743129
],
[
126.98230789017299,
37.564453179812105
],
[
126.98210513804034,
37.563703265276516
],
[
126.98207180945346,
37.56352550784786
],
[
126.9817857308457,
37.56284502921221
],
[
126.98166907678578,
37.562633941789535
],
[
126.98157186492477,
37.56247284870586
],
[
126.98128300624569,
37.56205345097403
],
[
126.98124689891416,
37.56200067907546
]
],
"traffic": [0, 8, 4, 12]
}}
This is what I got.
And I don't have any idea to parse key "coordinates".
This type depends on type of geometry.
If type is "Point", type became [String].
If type is "LineString", type became [[String]].
How can I solve it?
You can use this cocoa pod: CodableGeoJSON.
It has the Codable structs written up for you. You seem to have a feature with an unknown geometry here, so you can do something like this:
let geoJSON = try JSONDecoder().decode(GeoJSON.self, from: geoJSONData)
guard case .feature(let feature) = geoJSON else {
// the GeoJSON does not contain a feature!
}
// handle each kind of geometry...
switch feature.geometry {
case .point(let coordinates): // coordinates is a GeoJSONPosition
// ...
case .multiPoint(let coordinates): // coordinates is a [GeoJSONPosition]
// ...
case .lineString(let coordinates): // coordinates is a [GeoJSONPosition]
// ...
case .multiLineString(let coordinates): // coordinates is a [[GeoJSONPosition]]
// ...
case .polygon(let coordinates): // coordinates is a [[GeoJSONPosition]]
// ...
case .multiPolygon(let coordinates): // coordinates is a [[[GeoJSONPosition]]]
// ...
case .geometryCollection(let geometries):
// ...
}
If you don't like using a library just for this, have a look at their source code and try to learn from it, specifically, GeoJSON.swift.
I'm a beginner in ReactJS, I use react-leaflet for map rendering,
On this map I put some marker with coordinates point.
Short story, I try to get some object from JSON files, containing values by area, and coordinates points for polygon render on the map, it looks like this:
{
"type": "FeatureCollection",
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
"features": [
{
"type": "Feature",
"id": 656,
"properties": {
"DCOMIRIS": "940180101",
"DEPCOM": "94018",
"NOM_COM": "Charenton-le-Pont",
"IRIS": "0101",
"TYP_IRIS": "H",
"DEP": "94",
"aire": 0.2069,
"population": 3974
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[2.4197, 48.8214],
[2.4196, 48.8205],
[2.4196, 48.8199],
[2.4196, 48.819],
[2.4196, 48.8181],
[2.4196, 48.8172],
[2.4196, 48.8169],
[2.4183, 48.8167],
[2.418, 48.8166],
[2.4166, 48.8164],
[2.4159, 48.8163],
[2.4159, 48.8163],
[2.4159, 48.8163],
[2.4155, 48.817],
[2.4152, 48.8175],
[2.4149, 48.8178],
[2.4148, 48.8181]
]
]
]
}
},
{
"type": "Feature",
"id": 657,
"properties": {
"DCOMIRIS": "940180109",
"DEPCOM": "94018",
"NOM_COM": "Charenton-le-Pont",
"IRIS": "0109",
"TYP_IRIS": "H",
"DEP": "94",
"aire": 0.4146,
"population": 3906
},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[2.4055, 48.8245],
[2.4053, 48.8244],
[2.4042, 48.8235],
[2.4032, 48.8226],
[2.4024, 48.8219],
[2.4014, 48.8211],
[2.4013, 48.821],
[2.4011, 48.8209],
[2.401, 48.8207],
[2.4009, 48.8207],
[2.4009, 48.8206],
[2.4007, 48.8207],
[2.3996, 48.8212]
]
]
]
}
}
With underscore I try to get some object with coordinates value, like this:
var find = _.findWhere(this.state.data, {coordinates: [2.4055, 48.8245]});
but I got nothing, I don't know how to search "deeper" in my json.
If I try:
var find = _.findWhere(this.state.data, {id: 656});
underscore get me the object...
Any advice?
The problem you are facing is that the find method is probably comparing each of the json coordinates object, like:
"coordinates": [
[
[
[2.4055, 48.8245],
[2.4053, 48.8244],
[2.4042, 48.8235],
[2.4032, 48.8226],
[2.4024, 48.8219],
[2.4014, 48.8211],
[2.4013, 48.821],
]
]
]
With the object you provide:
"coordinates":
[2.4055, 48.8245]
And this comparison returns false.
As far as I understood you're searching for a "feature" object inside a JSON that contains coordinates [2.4055, 48.8245].
You need to do several steps to search for an element:
Loop through the features property.
Find your coordinate inside geometry.coordinates array.
The problem here could be that the coordinates array could be nested because it is a MultiPolygon object. It may be a one level deep:
[ [ 1.1, 2.2 ], [ 3.3, 4.4 ] ]
... or two and more levels deep like in your example:
[ [ [ 5.1, 6.2 ], [ 7.3, 8.4 ] ] ]
In this case you need to do a search using recursion.
Here is how this could be done with lodash or underscore (I tested with lodash).
// Recursive search function.
function find(coords, items) {
var i = 0, found;
for (; i < items.length; i++) {
if (_.isArray(items[i])) {
if (items[i].length === 2 && _.isNumber(items[i][0]) && _.isNumber(items[i][1]) && _.isEqual(items[i], coords)) {
return items[i];
} else {
found = find(coords, items[i]);
if (found) {
return found;
}
}
}
}
}
// Coordinates you're looking for
var coords = [2.4055, 48.8245];
// Loop through the features and find coordinates.
var result = _.find(_.get(data, 'features'), function (feature) {
return find(coords, _.get(feature, 'geometry.coordinates'));
});
The result is a "feature" object that contains coordinate that you're looking for.
What I'm trying to do is to find places which are inside or with 10 meters distance of a street.
My streets table has a geometry column which coordinates are saved from.
A sample coordinate looks like
{ "type": "Feature", "properties": { "id": 4.000000, "osm_id": 69551269.000000, "type": "tertiary", "name": "Street name", "tunnel": 0, "bridge": 0, "oneway": 1, "ref": null, "z_order": 4.000000, "access": null, "service": null, "class": "highway" },
"geometry": { "type": "LineString",
"coordinates": [ [ 45.055701068545773, 37.537045660463036 ], [ 45.055566036085651, 37.536995369044007 ], [ 45.054243455583901, 37.536797891405229 ], [ 45.053941120336447, 37.536756233346466 ], [ 45.053692177812167, 37.536712228354787 ], [ 45.052483758831642, 37.536435290273943 ], [ 45.052157870436275, 37.536344765719662 ], [ 45.051875819394468, 37.536229430731993 ], [ 45.05173206975504, 37.536151395213466 ], [ 45.051607347035826, 37.536067827638817 ], [ 45.051492766419436, 37.535979063284202 ], [ 45.050636052096081, 37.535314881276747 ], [ 45.050383253896371, 37.535111536305749 ], [ 45.050164989137727, 37.534882458892014 ], [ 45.050017048546714, 37.534692692604175 ], [ 45.049976061040212, 37.534639970433204 ], [ 45.049796436855189, 37.534394380670221 ], [ 45.049439032503869, 37.533859196152598 ], [ 45.049149186292141, 37.533424929749174 ], [ 45.048739143588875, 37.532811039160741 ], [ 45.048373357334377, 37.532213577102539 ], [ 45.048231284075598, 37.531903279047071 ], [ 45.048143022635173, 37.531710579093094 ], [ 45.047949568309946, 37.531336494754463 ], [ 45.047873628267183, 37.531189895267971 ], [ 45.047984772303266, 37.53111303321586 ] ] } },
My question is that should the coordinates be saved as polygon or LineString.
GeoJson authoritive indicates that LineString has no inside or outside but the data which I've got from openstreet(above is a sample) has a type of LineString.
So Which one should I use?
Edit:
A sample LineString from openstreetmap looks like this:
I drew them by drawing a polygon with coordinates.
Either of the two of geometry types, linestrings and polygon would work for you in your case. But i think it is quite straightforward to convert the linestrings to polygon and just use ST_Buffer the polygon with 20m...
SET #line = ST_GeomFromText('LINESTRING(44.9894318 37.496227, 44.9901579 37.4964403)',4326); SET #pt = ST_GeomFromText('POINT(45.00 37.4964)',4326); SET #buffer=st_buffer(#line,0.0124274); SELECT ST_WITHIN(#pt,#buffer)
20 meters = 0.0124274 mile,
Difference between Geography coordinate system and geometry coordinate system: https://en.wikipedia.org/wiki/Geographic_coordinate_system
JSON newbie here. Could you please help with parsing JSON files using R. I did try jsonlite & rjson, but keep getting errors.
Below is the data retrieved via the api.
data <- GET("http://svcs.ebay.com/services/search/FindingService/v1?OPERATION-NAME=findItemsByKeywords&SERVICE-VERSION=1.0.0&SECURITY-APPNAME=GLOBAL-ID=EBAY-US&RESPONSE-DATA-FORMAT=JSON&callback=_cb_findItemsByKeywords&REST-PAYLOAD&keywords=harry%20potter&paginationInput.entriesPerPage=10")
The JSON looks like this:
/**/_cb_findItemsByKeywords({
"findItemsByKeywordsResponse":[
{
"ack":[
"Success"
],
"version":[
"1.13.0"
],
"timestamp":[
"2016-01-29T16:36:25.984Z"
],
"searchResult":[
{
"#count":"1",
"item":[
{
"itemId":[
"371533364795"
],
"title":[
"Harry Potter: Complete 8-Film Collection (DVD, 2011, 8-Disc Set)"
],
"globalId":[
"EBAY-US"
],
"primaryCategory":[
{
"categoryId":[
"617"
],
"categoryName":[
"DVDs & Blu-ray Discs"
]
}
],
"galleryURL":[
"http:\/\/thumbs4.ebaystatic.com\/m\/mn5Agt0HFD89L7_-lqfrZZw\/140.jpg"
],
"viewItemURL":[
"http:\/\/www.ebay.com\/itm\/Harry-Potter-Complete-8-Film-Collection-DVD-2011-8-Disc-Set-\/371533364795"
],
"productId":[
{
"#type":"ReferenceID",
"__value__":"110258144"
}
],
"paymentMethod":[
"PayPal"
],
"autoPay":[
"false"
],
"postalCode":[
"60131"
],
"location":[
"Franklin Park,IL,USA"
],
"country":[
"US"
],
"shippingInfo":[
{
"shippingServiceCost":[
{
"#currencyId":"USD",
"__value__":"0.0"
}
],
"shippingType":[
"FlatDomesticCalculatedInternational"
],
"shipToLocations":[
"US",
"CA",
"GB",
"AU",
"AT",
"BE",
"FR",
"DE",
"IT",
"JP",
"ES",
"TW",
"NL",
"CN",
"HK",
"MX",
"DK",
"RO",
"SK",
"BG",
"CZ",
"FI",
"HU",
"LV",
"LT",
"MT",
"EE",
"GR",
"PT",
"CY",
"SI",
"SE",
"KR",
"ID",
"ZA",
"TH",
"IE",
"PL",
"RU",
"IL"
],
"expeditedShipping":[
"false"
],
"oneDayShippingAvailable":[
"false"
],
"handlingTime":[
"1"
]
}
],
"sellingStatus":[
{
"currentPrice":[
{
"#currencyId":"USD",
"__value__":"26.95"
}
],
"convertedCurrentPrice":[
{
"#currencyId":"USD",
"__value__":"26.95"
}
],
"sellingState":[
"Active"
],
"timeLeft":[
"P16DT3H12M6S"
]
}
],
"listingInfo":[
{
"bestOfferEnabled":[
"false"
],
"buyItNowAvailable":[
"false"
],
"startTime":[
"2016-01-15T19:43:31.000Z"
],
"endTime":[
"2016-02-14T19:48:31.000Z"
],
"listingType":[
"StoreInventory"
],
"gift":[
"false"
]
}
],
"returnsAccepted":[
"true"
],
"condition":[
{
"conditionId":[
"1000"
],
"conditionDisplayName":[
"Brand New"
]
}
],
"isMultiVariationListing":[
"false"
],
"topRatedListing":[
"true"
]
}
]
}
],
"paginationOutput":[
{
"pageNumber":[
"1"
],
"entriesPerPage":[
"1"
],
"totalPages":[
"138112"
],
"totalEntries":[
"138112"
]
}
],
"itemSearchURL":[
"http:\/\/www.ebay.com\/sch\/i.html?_nkw=harry+potter&_ddo=1&_ipg=1&_pgn=1"
]
}
]
})
The problem is that your data is not json, but it is JavaScript, jsonp to be exactly. If you just want to parse the JSON data you have to strip off the padding callback function.
req <- httr::GET("http://svcs.ebay.com/services/search/FindingService/v1?OPERATION-NAME=findItemsByKeywords&SERVICE-VERSION=1.0.0&SECURITY-APPNAME=YOUR-APP-123456&GLOBAL-ID=EBAY-US&RESPONSE-DATA-FORMAT=JSON&callback=_cb_findItemsByKeywords&REST-PAYLOAD&keywords=harry%20potter&paginationInput.entriesPerPage=10")
txt <- content(req, "text")
json <- sub("/**/_cb_findItemsByKeywords(", "", txt, fixed = TRUE)
json <- sub(")$", "", json)
mydata <- jsonlite::fromJSON(json)
Extra credit: alternatively you could use an actual JavaScript engine to parse the JavaScript:
library(V8)
ctx <- V8::v8()
ctx$eval("var out;")
ctx$eval("function _cb_findItemsByKeywords(x){out = x;}")
ctx$source("http://svcs.ebay.com/services/search/FindingService/v1?OPERATION-NAME=findItemsByKeywords&SERVICE-VERSION=1.0.0&SECURITY-APPNAME=YOUR-APP-123456&GLOBAL-ID=EBAY-US&RESPONSE-DATA-FORMAT=JSON&callback=_cb_findItemsByKeywords&REST-PAYLOAD&keywords=harry%20potter&paginationInput.entriesPerPage=10")
mydata <- ctx$get("out")
First, your json file seems to have a little issue. It should have started in the opening bracket "[".
I removed the text before it and I've tried this code, which worked perfectly:
library(rjson)
obj <- fromJSON(file = "v2.json")
That returned a list in obj with the contents of v2.json.
EDITED: Including a full functional soltion:
library(rjson)
library(stringr)
obj <- read.table("v2.json", sep = "\n", stringsAsFactors = FALSE, quote = "")
# Gets the first line with the string "[" ("\\" for scape)
firstline <- grep("\\[", obj[,1])[1]
# Gets the position of the string "[" in the line
fpos <- which(strsplit(obj[firstline, 1], "")[[1]] == "[")
# Gets the last line with the string "]"
lastline <- grep("\\]", obj[,1])
lastline <- lastline[length(lastline)]
# Gets the position of the string "]" in the line
lpos <- which(strsplit(obj[lastline, 1], "")[[1]] == "]")
# Changes the lines with the first "[" and the last "]" to keep the text
# between both (after "[" and before "]") if there is any.
obj[firstline, 1] <- str_sub(obj[firstline, 1], fpos)
obj[lastline, 1] <- str_sub(obj[lastline, 1], 1, lpos)
obj2 <- data.frame(obj[firstline:lastline, 1])
write.table(obj2, "v3.json", row.names = FALSE, col.names = FALSE, quote = FALSE)
obj3 <- fromJSON(file = "v3.json")