Related
I have wkt data and I am trying to create a JSON output in PostgreSQL.
I know that there is a function ST_AsGeoJSON (https://postgis.net/docs/ST_AsGeoJSON.html) which creates for example:
SELECT ST_AsGeoJSON('LINESTRING(77.29 29.07,77.42 29.26,77.27 29.31,77.29 29.07)');
Output:
{"type":"LineString","coordinates":[[77.29,29.07],[77.42,29.26],[77.27,29.31],[77.29,29.07]]}
But, I am looking to create an ouput as shown below:
{"type":"LineString","coordinates":[{"x":77.29,"y":29.07},{"x":77.42,"y":29.26},{"x":77.27,"y":29.31},{"x":77.29,"y":29.07}]}
Please note that I am looking for a generic solution for all types of geometry objects.
Thank you
You could use regex to replace the [a,b] with {"x":a,"y":b} with something like this:
CREATE OR REPLACE FUNCTION ST_AsCustomGeoJson(geom geometry)
RETURNS TEXT
AS
$$
-- Look for each coordinate and replace [number_a,number_b] with {"x":number_a,"y":number_b}
SELECT REGEXP_REPLACE(
ST_AsGeoJSON(geom),
'\[(-?[0-9]+\.?[0-9]*)(e\+[0-9]+)?,(-?[0-9]+\.?[0-9]*)(e\+[0-9]+)?\]',
'{"x":\1\2,"y":\3\4}',
'g');
$$
LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE;
Using the new function, you get the expected response:
# Select ST_AsCustomGeoJson('LINESTRING(77.29 29.07,77.42 29.26,77.27 29.31,77.29 29.07)'::geometry); st_ascustomgeojson
---------------------------------------------------------------------------------------------------------------
{"type":"LineString","coordinates":[{x:77.29,y:29.07},{x:77.42,y:29.26},{x:77.27,y:29.31},{x:77.29,y:29.07}]}
(1 row)
And it should work with other geometry types too:
# Select ST_AsCustomGeoJson('POLYGON((0 0, 0 10, 10 10, 10 0, 0 0),(1 1, 1 9, 9 9, 9 1, 1 1))'::geometry);
st_ascustomgeojson
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
{"type":"Polygon","coordinates":[[{"x":0,"y":0},{"x":0,"y":10},{"x":10,"y":10},{"x":10,"y":0},{"x":0,"y":0}],[{"x":1,"y":1},{"x":1,"y":9},{"x":9,"y":9},{"x":9,"y":1},{"x":1,"y":1}]]}
(1 row)
# Select ST_AsCustomGeoJson('LINESTRING(3e20 3e20, 1e100 40)'::geometry);
st_ascustomgeojson
---------------------------------------------------------------------------------
{"type":"LineString","coordinates":[{"x":3e+20,"y":3e+20},{"x":1e+100,"y":40}]}
(1 row)
Even geometry collections:
# Select ST_AsCustomGeoJson('GEOMETRYCOLLECTION (POINT(-1 0), LINESTRING(4 4,5 5))');
st_ascustomgeojson
-----------------------------------------------------------------------------------------------------------------------------
---------------------------------
{"type":"GeometryCollection","geometries":[{"type":"Point","coordinates":{"x":-1,"y":0}},{"type":"LineString","coordinates":
[{"x":4,"y":4},{"x":5,"y":5}]}]}
I believe a simple loop with jsonb_build_obejct over a result set from ST_DumpPoints would suffice. If you also want to apply this function in multipart geometries, you have to build another loop to extract all geometries beforehand using ST_Dump:
CREATE OR REPLACE FUNCTION generate_custom_geojson(g GEOMETRY)
RETURNS json AS $$
DECLARE
j geometry;
i geometry;
coords jsonb[] := '{}';
coords_multi jsonb[] := '{}';
BEGIN
FOR j IN SELECT (ST_Dump(g)).geom LOOP
FOR i IN SELECT (ST_DumpPoints(j)).geom LOOP
coords := coords || jsonb_build_object('x',ST_X(i),'y',ST_Y(i));
END LOOP;
IF ST_NumGeometries(g)=1 THEN
coords_multi := coords;
ELSE
coords_multi := coords_multi || jsonb_agg(coords);
END IF;
END LOOP;
RETURN json_build_object('type',replace(ST_GeometryType(g),'ST_',''),
'coordinates',coords_multi);
END;
$$ LANGUAGE plpgsql;
This function simply extracts all points of a given geometry and puts them into an array - appended using ||. This array is later on used to create the coordinates set of x,y pairs. The geometry type is extracted using ST_GeometryType.
Test:
WITH j (g) AS (
VALUES ('LINESTRING(77.29 29.07,77.42 29.26,77.27 29.31,77.29 29.07)'),
('POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10))'),
('MULTILINESTRING ((10 10, 20 20, 10 40),(40 40, 30 30, 40 20, 30 10))'),
('MULTIPOLYGON (((30 20, 45 40, 10 40, 30 20)),((15 5, 40 10, 10 20, 5 10, 15 5)))'),
('MULTIPOINT (10 40, 40 30, 20 20, 30 10)')
)
SELECT generate_custom_geojson(g) FROM j;
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
{"type" : "LineString", "coordinates" : [{"x": 77.29, "y": 29.07},{"x": 77.42, "y": 29.26},{"x": 77.27, "y": 29.31},{"x": 77.29, "y": 29.07}]}
{"type" : "Polygon", "coordinates" : [{"x": 30, "y": 10},{"x": 40, "y": 40},{"x": 20, "y": 40},{"x": 10, "y": 20},{"x": 30, "y": 10}]}
{"type" : "MultiLineString", "coordinates" : [[[{"x": 10, "y": 10}, {"x": 20, "y": 20}, {"x": 10, "y": 40}]],[[{"x": 10, "y": 10}, {"x": 20, "y": 20}, {"x": 10, "y": 40}, {"x": 40, "y": 40}, {"x": 30, "y": 30}, {"x": 40, "y": 20}, {"x": 30, "y": 10}]]]}
{"type" : "MultiPolygon", "coordinates" : [[[{"x": 30, "y": 20}, {"x": 45, "y": 40}, {"x": 10, "y": 40}, {"x": 30, "y": 20}]],[[{"x": 30, "y": 20}, {"x": 45, "y": 40}, {"x": 10, "y": 40}, {"x": 30, "y": 20}, {"x": 15, "y": 5}, {"x": 40, "y": 10}, {"x": 10, "y": 20}, {"x": 5, "y": 10}, {"x": 15, "y": 5}]]]}
{"type" : "MultiPoint", "coordinates" : [[[{"x": 10, "y": 40}]],[[{"x": 10, "y": 40}, {"x": 40, "y": 30}]],[[{"x": 10, "y": 40}, {"x": 40, "y": 30}, {"x": 20, "y": 20}]],[[{"x": 10, "y": 40}, {"x": 40, "y": 30}, {"x": 20, "y": 20}, {"x": 30, "y": 10}]]]}
(5 Zeilen)
How can I get region from the selected result from autocomplete?
From the result I am getting, there is 3rd object named region but actually it is department not region.
Here is the example address:
54b route de brie, 91800 Brunoy, France
Mapbox is giving me: Essonne // Its department not region
But actually its: Ile-de-France
How do I get the correct region?
Here is my working demo:
https://jsfiddle.net/rv085oL1/
That information isn't included. But if you just need your site to work in France, it would be straightforward to include a lookup table mapping from département to région, using the last two characters of the short_code. Here's one: https://gist.github.com/SiamKreative/f1074ed95507e69d08a0
"regions": {
"alsace": [67, 68],
"aquitaine": [40, 47, 33, 24, 64],
"auvergne": [43, 3, 15, 63],
"basse-normandie": [14, 61, 50],
"bourgogne": [21, 58, 71, 89],
"bretagne": [29, 35, 22, 56],
"centre": [45, 37, 41, 28, 36, 18],
"champagne-ardenne": [10, 8, 52, 51],
"corse": ["2b", "2a"],
"franche-compte": [39, 25, 70, 90],
"haute-normandie": [27, 76],
"languedoc-roussillon": [48, 30, 34, 11, 66],
"limousin": [19, 23, 87],
"lorraine": [55, 54, 57, 88],
"midi-pyrennees": [46, 32, 31, 12, 9, 65, 81, 82],
"nord-pas-de-calais": [62, 59],
"pays-de-la-loire": [49, 44, 72, 53, 85],
"picardie": [2, 60, 80],
"poitou-charentes": [17, 16, 86, 79],
"provences-alpes-cote-dazur": [4, 5, 6, 13, 84, 83],
"rhones-alpes": [38, 42, 26, 7, 1, 74, 73, 69],
"ile-de-france": [77, 75, 78, 93, 92, 91, 95, 94]
},
I'm trying to impliment a google chart like the no dependancies one shown here
To get this to work with my data I'm importing the data for the rows like so..
$.get('http://104.12.156.29:8011/java/servlet/UTRICKC5.I00120s', function (data2) {
console.log(data2);});
This pulls what I need... but how can I replace the data.addrows block with what I'm pulling in?
For reference, what I'm getting shown in the console is this;
['Task 1', 'Task 1','Team 1',new Date(2014 , 02, 01), new Date(2014 , 02, 10), null, 50, null],
['Task 2', 'Task 2','Team 2',new Date(2014 , 03, 01), new Date(2014 , 04, 01), null, 1, null]
So I pretty just need to find a way of getting this to "render" as part of my javascript.
<script type="text/javascript">
google.charts.load('current', {'packages':['gantt']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Task ID');
data.addColumn('string', 'Task Name');
data.addColumn('string', 'Resource');
data.addColumn('date', 'Start Date');
data.addColumn('date', 'End Date');
data.addColumn('number', 'Duration');
data.addColumn('number', 'Percent Complete');
data.addColumn('string', 'Dependencies');
$.get('http://http://104.12.156.29:8011/java/servlet/UTRICKC5.I00120s', function (data2) {
console.log(data2);});
data.addRows([
['2014Spring', 'Spring 2014', 'spring',
new Date(2014, 2, 22), new Date(2014, 5, 20), null, 100, null],
['2014Summer', 'Summer 2014', 'summer',
new Date(2014, 5, 21), new Date(2014, 8, 20), null, 100, null],
['2014Autumn', 'Autumn 2014', 'autumn',
new Date(2014, 8, 21), new Date(2014, 11, 20), null, 100, null],
['2014Winter', 'Winter 2014', 'winter',
new Date(2014, 11, 21), new Date(2015, 2, 21), null, 100, null],
['2015Spring', 'Spring 2015', 'spring',
new Date(2015, 2, 22), new Date(2015, 5, 20), null, 50, null],
['2015Summer', 'Summer 2015', 'summer',
new Date(2015, 5, 21), new Date(2015, 8, 20), null, 0, null],
['2015Autumn', 'Autumn 2015', 'autumn',
new Date(2015, 8, 21), new Date(2015, 11, 20), null, 0, null],
['2015Winter', 'Winter 2015', 'winter',
new Date(2015, 11, 21), new Date(2016, 2, 21), null, 0, null],
['Football', 'Football Season', 'sports',
new Date(2014, 8, 4), new Date(2015, 1, 1), null, 100, null],
['Baseball', 'Baseball Season', 'sports',
new Date(2015, 2, 31), new Date(2015, 9, 20), null, 14, null],
['Basketball', 'Basketball Season', 'sports',
new Date(2014, 9, 28), new Date(2015, 5, 20), null, 86, null],
['Hockey', 'Hockey Season', 'sports',
new Date(2014, 9, 8), new Date(2015, 5, 21), null, 89, null]
]);
var options = {
height: 400,
gantt: {
trackHeight: 30
}
};
var chart = new google.visualization.Gantt(document.getElementById('chart_div'));
chart.draw(data, options);
}
</script>
first, recommend formatting the data as json, as found here...
{
"cols": [
{"label": "Task ID", "type": "string"},
{"label": "Task Name", "type": "string"},
{"label": "Resource", "type": "string"},
{"label": "Start Date", "type": "date"},
{"label": "End Date", "type": "date"},
{"label": "Duration", "type": "number"},
{"label": "Percent Complete", "type": "number"},
{"label": "Dependencies", "type": "string"}
],
"rows": [
{"c":[{"v": "Task 1"}, {"v": "Task 1"}, {"v": "Team 1"}, {"v": "Date(2014, 2, 1)"}, {"v": "Date(2014, 2, 10)"}, {"v": null}, {"v": 50}, {"v": null}]},
{"c":[{"v": "Task 2"}, {"v": "Task 2"}, {"v": "Team 2"}, {"v": "Date(2014, 3, 1)"}, {"v": "Date(2014, 4, 1)"}, {"v": null}, {"v": 1}, {"v": null}]}
]
}
this will allow you to create the data table directly, without client-side manipulation.
and it is the fastest way to load the data table.
next, both $.get and $.ajax are asynchronous,
which means you will need to wait until the data is received,
before trying to create the data table and draw the chart.
recommend using $.ajax so you can specify the dataType as json.
see following working snippet,
here, I use the fail promise method so the snippet will work,
you can remove on your server and just keep the done method.
google.charts.load('current', {
packages: ['gantt']
}).then(function () {
var chart = new google.visualization.Gantt(document.getElementById('chart_div'));
var options = {
height: 400,
gantt: {
trackHeight: 30
}
};
$.ajax({
url: 'http://104.12.156.29:8011/java/servlet/UTRICKC5.I00120s',
dataType: 'json'
}).done(drawChart).fail(function () {
var chartData = {
"cols": [
{"label": "Task ID", "type": "string"},
{"label": "Task Name", "type": "string"},
{"label": "Resource", "type": "string"},
{"label": "Start Date", "type": "date"},
{"label": "End Date", "type": "date"},
{"label": "Duration", "type": "number"},
{"label": "Percent Complete", "type": "number"},
{"label": "Dependencies", "type": "string"}
],
"rows": [
{"c":[{"v": "Task 1"}, {"v": "Task 1"}, {"v": "Team 1"}, {"v": "Date(2014, 2, 1)"}, {"v": "Date(2014, 2, 10)"}, {"v": null}, {"v": 50}, {"v": null}]},
{"c":[{"v": "Task 2"}, {"v": "Task 2"}, {"v": "Team 2"}, {"v": "Date(2014, 3, 1)"}, {"v": "Date(2014, 4, 1)"}, {"v": null}, {"v": 1}, {"v": null}]}
]
};
drawChart(chartData);
});
function drawChart(chartData) {
var data = new google.visualization.DataTable(chartData);
chart.draw(data, options);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
When requesting ad stat for an add that is running longer than 1 day I recieve unique_imperssion = 0.
However when requesting stats for a day the unique_impression is populated.
Is it a bug or intentional? is there a workaround to get unique impressions for more than 1 day?
Querying for one day:
https://graph.facebook.com/<ad_group_id>/stats/1362787200/1362873600
I get:
{
"id": "<ad_group_id>/stats/1362787200/1362873600",
"impressions": 8616,
"clicks": 67,
"spent": 715,
"social_impressions": 20,
"social_clicks": 0,
"social_spent": 0,
"unique_impressions": 3544,
"social_unique_impressions": 11,
"unique_clicks": 67,
"social_unique_clicks": 0,
"actions": null,
"inline_actions": {
"title_clicks": 0,
"like": 9,
"rsvp_yes": 0,
"rsvp_maybe": 0,
"post_like": 0,
"comment": 0,
"photo_view": 0,
"link_click": 0,
"video_play": 0,
"question_vote": 0
},...
Querying for all time:
https://graph.facebook.com/<ad_group_id>/stats
I get:
{
"id": "<ad_group_id>/stats",
"impressions": 8616,
"clicks": 67,
"spent": 715,
"social_impressions": 20,
"social_clicks": 0,
"social_spent": 0,
"unique_impressions": 0,
"social_unique_impressions": 11,
"unique_clicks": 67,
"social_unique_clicks": 0,
"actions": null,
"inline_actions": {
"title_clicks": 0,
"like": 9,
"rsvp_yes": 0,
"rsvp_maybe": 0,
"post_like": 0,
"comment": 0,
"photo_view": 0,
"link_click": 0,
"video_play": 0,
"question_vote": 0
},...
Thanks,
Amit
Are you forgetting to use timestamps which are for a 1, 7 or 28 day period, and adjusted to match the timezone of the ad account itself? This is the most likely explanation here
For example, if your ad account (/act_<ACCOUNT_NUMBER_HERE) is like this:
"account_id": "<SNIP>",
"id": "act_<SNIP",
"name": "<SNIP> default (EUR) account",
"account_status": 1,
"currency": "EUR",
"timezone_id": 69,
"timezone_name": "Europe/Dublin",
"timezone_offset_hours_utc": 1,
You need to adjust the timestamps of your stats calls to UTC +1
So for retrieving unique stats, you need to request 1, 7 or 28 days of data, from midnight-midnight, in UTC +1 , this example should work for you:
<SNIP>/stats/2013-02-01 00:00:00 +0100/2013-03-01 00:00:00 +0100
or
<SNIP>/stats/1359673200/1362092400
Example response (truncated)
{
"id": "<SNIP>/stats/1359673200/1362092400",
"impressions": "166561",
"clicks": "6304",
"spent": "45257",
"social_impressions": "166556",
"social_clicks": "6304",
"social_spent": "45257",
"unique_impressions": 111368,
"social_unique_impressions": 111368,
"unique_clicks": 5992,
"social_unique_clicks": 5992,
"actions": {
I'm not strong JS user, but I want make "Nightingale chart" like this: http://windhistory.com/station.html?KHKA
I have that code:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="d3.v2.js"></script>
<style type="text/css">
.arc{
fill: pink;
stroke: red;
}
</style>
</head>
<body>
<div id="chart" class="chart"></div>
<div id="table"></div>
<script type="text/javascript">
var svg = d3.select("#chart").append("svg").attr("width", 900).attr("height", 600);
var pi = Math.PI;
d3.json(
'data.json',
function(data){
var arc = d3.svg.arc()
.innerRadius(50)
.outerRadius(function(d) {
return (50 + d.value);
})
.startAngle(function(d) { return ((d.time - 1) * 30 * pi / 180); })
.endAngle(function(d) { return (d.time * 30 * pi / 180 ); });
var chartContainer = svg.append("g")
.attr('class', 'some_class')
.attr("transform", "translate(450, 300)");
chartContainer.append("path")
.data(data)
.attr("d", arc)
.attr("class", "arc");
}
);
</script>
</body>
</html>
On jsfinddle: http://jsfiddle.net/lmasikl/gZ62Z/
my json:
[
{"label": "January", "value": 150, "time": 1},
{"label": "February", "value": 65, "time": 2},
{"label": "March", "value": 50, "time": 3},
{"label": "April", "value": 75, "time": 4},
{"label": "May", "value": 150, "time": 5},
{"label": "June", "value": 65, "time": 6},
{"label": "July", "value": 50, "time": 7},
{"label": "August", "value": 75, "time": 8},
{"label": "September", "value": 65, "time": 9},
{"label": "October", "value": 50, "time": 10},
{"label": "November", "value": 75, "time": 11},
{"label": "December", "value": 150, "time": 12}
]
But my script draw only one arc. Can anybody help to solve this problem?
You may want to read Thinking With Joins. The D3 pattern for adding data-driven elements is to create a selection with selectAll, then set the data with data, then append the element, to the .enter() selection. So
chartContainer.append("path")
.data(data)
.attr("d", arc)
.attr("class", "arc");
needs to be
chartContainer.selectAll("path")
.data(data)
.enter().append("path")
.attr("d", arc)
.attr("class", "arc");
See updated fiddle: http://jsfiddle.net/gZ62Z/1/