Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
fordecyt_2019
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Rodrigo Tapia-McClung
fordecyt_2019
Commits
7e24cf65
Commit
7e24cf65
authored
Sep 03, 2019
by
Rodrigo Tapia-McClung
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Create and update charts with less DB requests
parent
850046ff
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
81 additions
and
141 deletions
+81
-141
grijalva_charts.js
public/js/grijalva_charts.js
+37
-102
grijalva_functions.js
public/js/grijalva_functions.js
+44
-39
No files found.
public/js/grijalva_charts.js
View file @
7e24cf65
...
@@ -2,11 +2,11 @@
...
@@ -2,11 +2,11 @@
* Copyright 2019 - All rights reserved.
* Copyright 2019 - All rights reserved.
* Rodrigo Tapia-McClung
* Rodrigo Tapia-McClung
*
*
* August 2019
* August
-September
2019
*/
*/
/* globals map, userFiles, userDates, indicators, indicatorVars, indicatorsNames */
/* globals map, userFiles, userDates, indicators, indicatorVars, indicatorsNames */
/* exported makeIndicatorGraph, getData, getDataInSelection */
/* exported makeIndicatorGraph, getData,
updateData,
getDataInSelection */
let
minDate
,
maxDate
,
xLine
,
yLine
;
let
minDate
,
maxDate
,
xLine
,
yLine
;
...
@@ -16,145 +16,80 @@ const sortByDateAscending = (a, b) => {
...
@@ -16,145 +16,80 @@ const sortByDateAscending = (a, b) => {
}
}
//TODO: scale data to appropriate units? m2-> ha? m -> km?
//TODO: scale data to appropriate units? m2-> ha? m -> km?
const
getData
=
async
(
indicator
)
=>
{
const
getData
=
async
()
=>
{
//let data = [{name: `${indicator}0`, values: []}];
let
queryColumns
=
[
"sum(area) as area"
,
"sum(perimeter) as perimeter"
,
"avg(costa) as costa"
,
"avg(df) as df"
],
let
timeParse
=
d3
.
timeParse
(
"%B_%Y"
);
timeParse
=
d3
.
timeParse
(
"%B_%Y"
),
//timeFormat = d3.timeFormat("%B %Y")
;
data
=
{}
;
const
promises
=
userFiles
.
map
(
async
monthYear
=>
{
indicators
.
map
(
indicator
=>
{
// get sum of area/perimeter or average of coast/fractal dimension
data
[
indicator
]
=
[];
let
queryDB
=
indicator
==
"costa"
||
indicator
==
"df"
?
data
[
indicator
].
push
({
name
:
`
${
indicator
}
0`
,
values
:
[]});
`http://localhost:8090/data/query/
${
monthYear
}
?columns=avg(
${
indicator
}
)%20as%20
${
indicator
}
`
:
});
`http://localhost:8090/data/query/
${
monthYear
}
?columns=sum(
${
indicator
}
)%20as%20
${
indicator
}
`
;
const
userFilePromises
=
userFiles
.
map
(
async
monthYear
=>
{
let
queryDB
=
`http://localhost:8090/data/query/
${
monthYear
}
?columns=
${
queryColumns
.
join
(
","
)}
`
;
const
dbData
=
await
d3
.
json
(
queryDB
);
const
dbData
=
await
d3
.
json
(
queryDB
);
return
{
date
:
timeParse
(
monthYear
),
value
:
dbData
[
0
]};
return
{
date
:
timeParse
(
monthYear
),
value
:
dbData
[
0
]};
});
});
const
chartData
=
await
Promise
.
all
(
promises
);
const
chartData
=
await
Promise
.
all
(
userFilePromises
);
let
data
=
[{
name
:
`
${
indicator
}
0`
,
values
:
[]}];
chartData
.
map
(
monthData
=>
{
chartData
.
map
(
monthYear
=>
{
indicators
.
map
(
indicator
=>
{
data
[
0
].
values
.
push
({
data
[
indicator
][
0
].
values
.
push
({
"date"
:
monthYear
.
date
,
"date"
:
monthData
.
date
,
"value"
:
+
monthYear
.
value
[
indicator
]
"value"
:
+
monthData
.
value
[
indicator
]
});
});
});
data
.
forEach
(
d
=>
d
.
values
.
sort
(
sortByDateAscending
));
// order data[i].values.date
return
data
;
data
[
indicator
].
forEach
(
d
=>
d
.
values
.
sort
(
sortByDateAscending
));
}
// FIXME: Improve this function. Too many requests: indicators x months x drawn items...
// Find way to make one request and get all indicators per month and drawn item.
// Something like the commented function below.
const
getDataInSelection
=
async
(
indicator
)
=>
{
let
timeParse
=
d3
.
timeParse
(
"%B_%Y"
);
let
geojson
=
drawnItems
.
toGeoJSON
(),
data
=
[];
drawnItemsPromises
=
geojson
.
features
.
map
(
async
(
item
,
i
)
=>
{
// set SRID for drawn features
item
.
geometry
.
crs
=
{
"type"
:
"name"
,
"properties"
:{
"name"
:
"EPSG:4326"
}};
data
.
push
({
name
:
indicator
+
(
i
+
1
),
values
:
[]});
let
columns
=
indicator
==
"costa"
||
indicator
==
"df"
?
`avg(
${
indicator
}
)%20as%20
${
indicator
}
`
:
`sum(
${
indicator
}
)%20as%20
${
indicator
}
`
;
let
filter
=
`ST_Intersects(geom, (SELECT ST_Multi(ST_GeomFromGeoJSON('
${
JSON
.
stringify
(
item
.
geometry
)}
') ) ) )`
const
filePpromises
=
userFiles
.
map
(
async
monthYear
=>
{
let
queryData
=
`http://localhost:8090/data/query/
${
monthYear
}
?columns=
${
columns
}
&filter=
${
filter
}
&group=1%3D1`
;
const
selectionQuery
=
await
d3
.
json
(
queryData
);
return
{
date
:
timeParse
(
monthYear
),
value
:
selectionQuery
[
0
]};
});
});
const
selectionData
=
await
Promise
.
all
(
filePpromises
);
selectionData
.
map
(
itemData
=>
{
let
itemDataValue
=
itemData
.
value
!=
undefined
?
itemData
.
value
[
indicator
]
:
0
;
data
[
i
].
values
.
push
({
date
:
itemData
.
date
,
value
:
itemDataValue
});
});
});
return
data
;
return
data
;
});
const
drawnItemsData
=
await
Promise
.
all
(
drawnItemsPromises
);
let
data2
=
[];
data
.
map
(
a
=>
data2
.
push
(
a
.
values
));
// flatten array of data[i].values
data2
=
[].
concat
.
apply
([],
data2
);
// insert sum of each date to first element of data array with name "column0"
data
.
unshift
({
"name"
:
`
${
indicator
}
0`
,
"values"
:
d3
.
nest
()
.
key
(
d
=>
d
.
date
)
// return d3.sum or d3.average depending on indicator
.
rollup
(
v
=>
{
return
indicator
==
"costa"
||
indicator
==
"df"
?
d3
.
mean
(
v
,
v
=>
v
.
value
)
:
d3
.
sum
(
v
,
v
=>
v
.
value
)
})
.
entries
(
data2
)
// map "key" and "value" from d3.nest().rollup() to date and value
.
map
(
group
=>
{
return
{
date
:
new
Date
(
group
.
key
),
value
:
group
.
value
}
})
});
// order data[i].values.date
data
.
forEach
(
d
=>
d
.
values
.
sort
(
sortByDateAscending
));
return
data
;
}
}
/*
const getDataInSelection = async () => {
const
getDataInSelection
=
async
()
=>
{
let geojson = drawnItems.toGeoJSON()
;
let
geojson
=
drawnItems
.
toGeoJSON
()
,
let queryColumns = ["sum(area) as area", "sum(perimeter) as perimeter", "avg(costa) as costa", "avg(df) as df"];
queryColumns
=
[
"sum(area) as area"
,
"sum(perimeter) as perimeter"
,
"avg(costa) as costa"
,
"avg(df) as df"
],
let
timeParse = d3.timeParse("%B_%Y"),
timeParse
=
d3
.
timeParse
(
"%B_%Y"
),
data
=
{};
data
=
{};
indicators
.
map
(
indicator
=>
{
indicators
.
map
(
indicator
=>
{
data
[
indicator
]
=
[];
data
[
indicator
]
=
[];
});
});
//let promises;
// End up with data = {area: Array(0), perimeter: Array(0), length: Array(0), DI: Array(0)}
// Convert drawn items to GeoJSON and check what's inside each one of them
// Convert drawn items to GeoJSON and check what's inside each one of them
drawnItems.toGeoJSON().features.map( async (item, i) => {
const
drawnItemPromises
=
drawnItems
.
toGeoJSON
().
features
.
map
(
async
(
item
,
i
)
=>
{
// set SRID fro drawn features
// set SRID fro drawn features
geojson
.
features
[
i
].
geometry
.
crs
=
{
"type"
:
"name"
,
"properties"
:{
"name"
:
"EPSG:4326"
}};
geojson
.
features
[
i
].
geometry
.
crs
=
{
"type"
:
"name"
,
"properties"
:{
"name"
:
"EPSG:4326"
}};
indicators
.
map
(
async
indicator
=>
{
indicators
.
map
(
async
indicator
=>
{
data
[
indicator
].
push
({
name
:
indicator
+
(
i
+
1
),
values
:
[]});
data
[
indicator
].
push
({
name
:
indicator
+
(
i
+
1
),
values
:
[]});
});
});
// End up with data = {area: [{name: "area1", values: []}], perimeter: [{name: "perimeter1", values: []}]...}
// End up with data = {area: [{name: "area1", values: []}], perimeter: [{name: "perimeter1", values: []}]...}
//console.log(data)
let
filter
=
`ST_Intersects(geom, (SELECT ST_Multi(ST_GeomFromGeoJSON('
${
JSON
.
stringify
(
geojson
.
features
[
i
].
geometry
)}
') ) ) )`
let
filter
=
`ST_Intersects(geom, (SELECT ST_Multi(ST_GeomFromGeoJSON('
${
JSON
.
stringify
(
geojson
.
features
[
i
].
geometry
)}
') ) ) )`
const
p
romises = userFiles.map(async monthYear => {
const
userFileP
romises
=
userFiles
.
map
(
async
monthYear
=>
{
let
queryData
=
`http://localhost:8090/data/query/
${
monthYear
}
?columns=
${
queryColumns
.
join
(
","
)}
&filter=
${
filter
}
&group=1%3D1`
;
let
queryData
=
`http://localhost:8090/data/query/
${
monthYear
}
?columns=
${
queryColumns
.
join
(
","
)}
&filter=
${
filter
}
&group=1%3D1`
;
const
selectionQuery
=
await
d3
.
json
(
queryData
);
const
selectionQuery
=
await
d3
.
json
(
queryData
);
return
{
date
:
timeParse
(
monthYear
),
value
:
selectionQuery
[
0
]};
return
{
date
:
timeParse
(
monthYear
),
value
:
selectionQuery
[
0
]};
});
});
const selectionData = await Promise.all(promises);
const
selectionData
=
await
Promise
.
all
(
userFilePromises
);
// let data = [{name: `${indicator}0`, values: []}];
selectionData
.
map
(
itemData
=>
{
selectionData
.
map
(
itemData
=>
{
//console.log(itemData, i)
indicators
.
map
(
indicator
=>
{
indicators
.
map
(
indicator
=>
{
data[indicator][i].values.push({date: itemData.date, value: itemData.value[indicator] });
let
itemDataValue
=
itemData
.
value
!=
undefined
?
itemData
.
value
[
indicator
]
:
0
;
data
[
indicator
][
i
].
values
.
push
({
date
:
itemData
.
date
,
value
:
itemDataValue
});
});
});
});
});
});
});
const
drawnItemsData
=
await
Promise
.
all
(
drawnItemPromises
);
return
data
;
return
data
;
}
*/
}
const
summarizeData
=
async
(
allData
,
indicator
)
=>
{
const
summarizeData
=
(
allData
,
indicator
)
=>
{
/*let dataFull = await
allData;
let
dataFull
=
allData
;
let
data
=
dataFull
[
indicator
];
let
data
=
dataFull
[
indicator
];
let
data2
=
[];
let
data2
=
[];
console.log(allData, data[0]);
data
.
map
(
a
=>
data2
.
push
(
a
.
values
));
// flatten array of data[i].values
data.map( a => { console.log(a); data2.push(a.values)}); // flatten array of data[i].values
data2 = [].concat.apply([], data2);
console.log(data2);*/
allData
.
then
(
val
=>
{
let
data
=
val
[
'area'
];
let
data2
=
[];
console
.
log
(
val
,
data
);
data
.
forEach
(
a
=>
{
data2
.
push
(
a
.
values
)});
// flatten array of data[i].values
data2
=
[].
concat
.
apply
([],
data2
);
data2
=
[].
concat
.
apply
([],
data2
);
console
.
log
(
data2
);
// insert sum of each date to first element of data array with name "column0"
})
/*// insert sum of each date to first element of data array with name "column0"
data
.
unshift
({
data
.
unshift
({
"name"
:
`
${
indicator
}
0`
,
"name"
:
`
${
indicator
}
0`
,
"values"
:
d3
.
nest
()
"values"
:
d3
.
nest
()
...
@@ -171,7 +106,7 @@ const summarizeData = async (allData, indicator) => {
...
@@ -171,7 +106,7 @@ const summarizeData = async (allData, indicator) => {
});
});
// order data[i].values.date
// order data[i].values.date
data
.
forEach
(
d
=>
d
.
values
.
sort
(
sortByDateAscending
));
data
.
forEach
(
d
=>
d
.
values
.
sort
(
sortByDateAscending
));
//console.log(data)*/
console
.
log
(
data
)
return
data
;
return
data
;
}
}
...
...
public/js/grijalva_functions.js
View file @
7e24cf65
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
* Copyright 2019 - All rights reserved.
* Copyright 2019 - All rights reserved.
* Rodrigo Tapia-McClung
* Rodrigo Tapia-McClung
*
*
* August 2019
* August
-September
2019
*/
*/
/* globals omnivore, Promise, chroma, makeBaseMap, makeIndicatorGraph, getData, getDataInSelection */
/* globals omnivore, Promise, chroma, makeBaseMap, makeIndicatorGraph, getData, getDataInSelection */
...
@@ -338,7 +338,44 @@ const getMinMax = table => {
...
@@ -338,7 +338,44 @@ const getMinMax = table => {
});
});
}
}
const
populateMap
=
(
mapData
)
=>
{
const
populateMap
=
async
(
mapData
)
=>
{
const
chartData
=
await
getData
();
// Define charts with reusable components
indicators
.
map
(
async
(
indicator
,
index
)
=>
{
// indicatorVars[indicator].chart gives areaChart, perimeterChart, etc.
// First, make all charts with same general options
indicatorVars
[
indicator
].
chart
=
makeIndicatorGraph
()
.
width
(
Math
.
floor
(
$
(
indicatorVars
[
indicator
].
container
)[
0
].
offsetParent
.
offsetWidth
*
0.95
))
.
height
(
Math
.
floor
(
$
(
indicatorVars
[
indicator
].
container
)[
0
].
offsetParent
.
offsetHeight
*
0.95
))
.
lineVariables
([
`
${
indicator
}
0`
])
// d.area is used to draw stuff on y axis
.
displayName
(
"date"
)
// d.date is used to draw stuff on x axis
.
lineAxisLabel
(
"(m)"
)
.
id
(
indicator
)
.
xAxisFormat
(
d3
.
timeFormat
(
"%b '%y"
))
// label x axis as mm 'yy
.
yAxisFormat
(
d3
.
format
(
indicatorsxAxisFormat
[
index
]))
// yAxis label in SI or other
// Then, specify some parameters for each chart
.
tooltipUnits
(
indicatorsUnits
[
index
])
.
tooltipFormat
(
d3
.
format
(
indicatorsxAxisFormat
[
index
]))
// tooltip format in SI or other
.
title
(
indicatorsUnits
[
index
]
==
""
?
indicatorsNames
[
index
]
:
`
${
indicatorsNames
[
index
]}
(
${
indicatorsUnits
[
index
]}
)`
);
// Finally, set chart data with async function calling stuff from DB
indicatorVars
[
indicator
].
chart
.
data
(
chartData
[
indicator
]);
// create chart with passed options
d3
.
select
(
indicatorVars
[
indicator
].
container
)
.
call
(
indicatorVars
[
indicator
].
chart
);
// Reload chart data and force chart update
indicatorVars
[
indicator
].
chartData
=
indicatorVars
[
indicator
].
chart
.
data
();
// get chart data
indicatorVars
[
indicator
].
chart
.
data
(
indicatorVars
[
indicator
].
chartData
);
// set chart data
// Highlight plot title according to selected option
let
option
=
$
(
"#indicatorSelect"
).
val
();
// option selected from dropdrown
d3
.
select
(
indicatorVars
[
option
].
container
).
select
(
"svg text.title"
).
classed
(
"active"
,
true
);
});
let
map
=
mapData
.
map
,
let
map
=
mapData
.
map
,
minIndicators
=
mapData
.
minIndicators
,
minIndicators
=
mapData
.
minIndicators
,
maxIndicators
=
mapData
.
maxIndicators
;
maxIndicators
=
mapData
.
maxIndicators
;
...
@@ -411,39 +448,6 @@ const populateMap = (mapData) => {
...
@@ -411,39 +448,6 @@ const populateMap = (mapData) => {
layerControl
=
L
.
control
.
layers
(
baseLayers
,
overlays
).
addTo
(
map
);
layerControl
=
L
.
control
.
layers
(
baseLayers
,
overlays
).
addTo
(
map
);
makeBaseMap
();
// basemap.js
makeBaseMap
();
// basemap.js
});
});
// Define charts with reusable components
indicators
.
map
(
async
(
indicator
,
index
)
=>
{
// indicatorVars[indicator].chart gives areaChart, perimeterChart, etc.
// First, make all charts with same general options
indicatorVars
[
indicator
].
chart
=
makeIndicatorGraph
()
.
width
(
Math
.
floor
(
$
(
indicatorVars
[
indicator
].
container
)[
0
].
offsetParent
.
offsetWidth
*
0.95
))
.
height
(
Math
.
floor
(
$
(
indicatorVars
[
indicator
].
container
)[
0
].
offsetParent
.
offsetHeight
*
0.95
))
.
lineVariables
([
`
${
indicator
}
0`
])
// d.area is used to draw stuff on y axis
.
displayName
(
"date"
)
// d.date is used to draw stuff on x axis
.
lineAxisLabel
(
"(m)"
)
.
id
(
indicator
)
.
xAxisFormat
(
d3
.
timeFormat
(
"%b '%y"
))
// label x axis as mm 'yy
.
yAxisFormat
(
d3
.
format
(
indicatorsxAxisFormat
[
index
]))
// yAxis label in SI or other
// Then, specify some parameters for each chart
.
tooltipUnits
(
indicatorsUnits
[
index
])
.
tooltipFormat
(
d3
.
format
(
indicatorsxAxisFormat
[
index
]))
// tooltip format in SI or other
.
title
(
indicatorsUnits
[
index
]
==
""
?
indicatorsNames
[
index
]
:
`
${
indicatorsNames
[
index
]}
(
${
indicatorsUnits
[
index
]}
)`
);
// Finally, set chart data with async function calling stuff from DB
indicatorVars
[
indicator
].
chart
.
data
(
await
getData
(
indicator
));
// create chart with passed options
d3
.
select
(
indicatorVars
[
indicator
].
container
)
.
call
(
indicatorVars
[
indicator
].
chart
);
// Reload chart data and force chart update
indicatorVars
[
indicator
].
chartData
=
indicatorVars
[
indicator
].
chart
.
data
();
// get chart data
indicatorVars
[
indicator
].
chart
.
data
(
indicatorVars
[
indicator
].
chartData
);
// set chart data
// Highlight plot title according to selected option
let
option
=
$
(
"#indicatorSelect"
).
val
();
// option selected from dropdrown
d3
.
select
(
indicatorVars
[
option
].
container
).
select
(
"svg text.title"
).
classed
(
"active"
,
true
);
});
}
}
const
updateMap
=
(
mapData
)
=>
{
const
updateMap
=
(
mapData
)
=>
{
...
@@ -500,19 +504,20 @@ const updateMap = (mapData) => {
...
@@ -500,19 +504,20 @@ const updateMap = (mapData) => {
updateCharts
();
updateCharts
();
}
}
const
updateCharts
=
()
=>
{
const
updateCharts
=
async
()
=>
{
// TODO: add mask while fetching async data
// TODO: add mask while fetching async data
// if user has drawn polygons, update chart with data inside selection
// if user has drawn polygons, update chart with data inside selection
if
(
drawnItems
.
toGeoJSON
().
features
.
length
!=
0
)
{
if
(
drawnItems
.
toGeoJSON
().
features
.
length
!=
0
)
{
let
allData
=
await
getDataInSelection
();
indicators
.
map
(
async
indicator
=>
{
indicators
.
map
(
async
indicator
=>
{
//indicatorVars[indicator].chart.data( await summarizeData(await getDataInSelection(), indicator) );
indicatorVars
[
indicator
].
chart
.
data
(
summarizeData
(
allData
,
indicator
)
);
indicatorVars
[
indicator
].
chart
.
data
(
await
getDataInSelection
(
indicator
)
);
});
});
}
else
{
}
else
{
// otherwise use all data
// otherwise use all data
let
allData
=
await
getData
();
indicators
.
map
(
async
indicator
=>
{
indicators
.
map
(
async
indicator
=>
{
indicatorVars
[
indicator
].
chart
.
data
(
a
wait
getData
(
indicator
)
);
indicatorVars
[
indicator
].
chart
.
data
(
a
llData
[
indicator
]
);
});
});
}
}
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment