Commit 8a314114 authored by Mathieu Rodic's avatar Mathieu Rodic

[FEATURE] Included n-grams count

[FEATURE] Scale, interpolation and grouping are now customizable
parent 8518a581
......@@ -361,12 +361,16 @@ class NodesChildrenQueries(APIView):
# field = func.date_trunc(text('"%s"'% (datepart,)), field)
else:
authorized_field_names = {'id', 'name', }
if retrieve['type'] == 'aggregates' and field_name == 'count':
field = func.count(Node.id)
elif field_name not in authorized_field_names:
raise APIException('Unrecognized "field": "%s" in the query\'s "retrieve" parameter. Possible values are: "%s".' % (field_name, '", "'.join(authorized_field_names), ))
else:
authorized_aggregates = {
'nodes.count': func.count(Node.id),
'ngrams.count': func.count(Ngram.id),
}
if retrieve['type'] == 'aggregates' and field_name in authorized_aggregates:
field = authorized_aggregates[field_name]
elif field_name in authorized_field_names:
field = getattr(Node, field_name)
else:
raise APIException('Unrecognized "field": "%s" in the query\'s "retrieve" parameter. Possible values are: "%s".' % (field_name, '", "'.join(authorized_field_names), ))
fields_list.append(
field.label(
field_name if '.' in field_name else 'node.' + field_name
......@@ -382,7 +386,14 @@ class NodesChildrenQueries(APIView):
.filter(Node.parent_id == node_id)
)
# join aliases
# join ngrams if necessary
if 'ngrams.count' in fields_names:
query = (query
.join(Node_Ngram, Node_Ngram.node_id == Node.id)
.join(Ngram, Ngram.id == Node_Ngram.ngram_id)
)
# join metadata aliases
for metadata_id, metadata_alias in metadata_aliases.items():
query = (query
.join(metadata_alias, metadata_alias.node_id == Node.id)
......@@ -433,7 +444,6 @@ class NodesChildrenQueries(APIView):
# TODO: date_trunc (psql) -> index also
# groupping
authorized_aggregates = {'count': func.count(Node.id)}
for field_name in fields_names:
if field_name not in authorized_aggregates:
# query = query.group_by(text(field_name))
......@@ -476,7 +486,8 @@ class NodesChildrenQueries(APIView):
# return DebugHttpResponse(str(query))
# return DebugHttpResponse(literalquery(query))
results = [
dict(zip(fields_names, row))
list(row)
# dict(zip(fields_names, row))
for row in (
query[pagination["offset"]:pagination["offset"]+pagination["limit"]]
if pagination['limit']
......
......@@ -36,23 +36,41 @@ var strDate = function(date) {
('00' + date.getUTCMinutes()).slice(-2) + ':' +
('00' + date.getUTCSeconds()).slice(-2) + 'Z';
}
var addZero = function(x) {
return (x<10) ? ('0'+x) : x;
};
var addZeros = function(x, n) {
x = x.toString();
return '0000'.substr(0, n - x.length) + x;
};
var groupings = {
datetime: {
century: {
truncate: function(x) {return x.substr(0, 2) + '00-01-01T00:00:00Z';},
next: function(x) {x = new Date(x); x.setFullYear(x.getFullYear()+100); return strDate(x);},
next: function(x) {addZeros((parseInt(x.substr(0, 2) + 1) % 100), 2) + x.substr(2);},
},
decade: {
truncate: function(x) {return x.substr(0, 3) + '0-01-01T00:00:00Z';},
next: function(x) {x = new Date(x); x.setFullYear(x.getFullYear()+10); return strDate(x);},
next: function(x) {addZeros((parseInt(x.substr(0, 3) + 1) % 1000), 2) + x.substr(3);},
},
year: {
truncate: function(x) {return x.substr(0, 4) + '-01-01T00:00:00Z';},
next: function(x) {x = new Date(x); x.setFullYear(x.getFullYear()+1); return strDate(x);},
next: function(x) {
var y = parseInt(x.substr(0, 4));
return addZeros(y + 1, 4) + x.substr(4);
},
},
month: {
truncate: function(x) {return x.substr(0, 7) + '-01T00:00:00Z';},
next: function(x) {x = new Date(x); x.setMonth(x.getMonth()+1); return strDate(x);},
next: function(x) {
var m = parseInt(x.substr(5, 2));
if (m == 12) {
var y = parseInt(x.substr(0, 4));
return addZeros(y + 1, 4) + '-01' + x.substr(7);
} else {
return x.substr(0, 5) + addZero(m + 1) + x.substr(7);
}
},
},
day: {
truncate: function(x) {return x.substr(0, 10) + 'T00:00:00Z';},
......@@ -75,8 +93,8 @@ var gargantext = angular.module('Gargantext', ['n3-charts.linechart']);
angular.module('Gargantext').run(['$rootScope', function($rootScope){
$rootScope.Math = Math;
$rootScope.getColor = function(i, n){
var h = .5 + (i / n) % 1;
var s = .8;
var h = .3 + (i / n) % 1;
var s = .7;
var v = .8;
var i = Math.floor(h * 6);
var f = h * 6 - i;
......@@ -135,7 +153,6 @@ gargantext.controller("QueryController", function($scope, $http) {
};
// remove a filter
$scope.removeFilter = function(filterIndex) {
var filter = $scope.filters[filterIndex];
$scope.filters.splice(filterIndex, 1);
};
// perform a query
......@@ -188,6 +205,7 @@ gargantext.controller("QueryController", function($scope, $http) {
gargantext.controller("DatasetController", function($scope, $http) {
// query-specific information
$scope.mesured = 'nodes.count';
$scope.filters = [];
$scope.pagination = {offset:0, limit: 20};
// results information
......@@ -223,8 +241,8 @@ gargantext.controller("DatasetController", function($scope, $http) {
};
// remove a filter
$scope.removeFilter = function(filterIndex) {
var filter = $scope.filters[filterIndex];
$scope.filters.splice(filterIndex, 1);
$scope.updateQuery();
};
// transmit query parameters to parent elements
$scope.updateQuery = function() {
......@@ -252,6 +270,7 @@ gargantext.controller("DatasetController", function($scope, $http) {
datasetId: $scope.$id,
url: url,
filters: filters,
mesured: $scope.mesured
});
}
}
......@@ -263,25 +282,16 @@ gargantext.controller("GraphController", function($scope, $http, $element) {
$scope.datasets = [{}];
$scope.resultsList = [];
$scope.queries = {};
$scope.groupingKey = 'year';
$scope.graph = {
data: [],
options: {
axes: {
x: {key: 'x', type: 'date'},
y: {type: 'log'},
// x: {key: 'x', labelFunction: function(value) {return value;}, type: 'linear', min: 0, max: 10, ticks: 2},
// y: {type: 'linear', min: 0, max: 1, ticks: 5},
// y2: {type: 'linear'}
// y2: {type: 'linear', min: 0, max: 1, ticks: [1, 2, 3, 4]}
},
// series: [
// {y: 'y0'},
// // {y: 'y1'},
// // {y: 'y0', color: 'steelblue', thickness: '2px', type: 'area', striped: true, label: 'Pouet'},
// // {y: 'y1', axis: 'y2', color: 'orange', visible: true, drawDots: true, dotSize: 2}
// ],
lineMode: 'linear',
tension: 0.7,
tension: 1.0,
lineMode: 'bundle',
tooltip: {mode: 'scrubber', formatter: function(x, y, series) {return x + ' → ' + y;}},
drawLegend: false,
drawDots: true,
......@@ -299,9 +309,9 @@ gargantext.controller("GraphController", function($scope, $http, $element) {
// show results on the graph
$scope.showResults = function(keys) {
// Format specifications
var xKey = keys[0];
var yKey = keys[1];
var grouping = groupings.datetime.year;
var xKey = 0;
var yKey = 1;
var grouping = groupings.datetime[$scope.groupingKey];
var convert = function(x) {return new Date(x);};
// Find extrema for X
var xMin, xMax;
......@@ -356,8 +366,6 @@ gargantext.controller("GraphController", function($scope, $http, $element) {
color: $scope.getColor(i, n)
});
}
$scope.graph.options.lineMode = 'bundle';
$scope.graph.options.tension = .7;
$scope.graph.options.series = series;
$scope.graph.data = linearData;
};
......@@ -376,7 +384,7 @@ gargantext.controller("GraphController", function($scope, $http, $element) {
sort: ['metadata.publication_date.day'],
retrieve: {
type: 'aggregates',
list: ['metadata.publication_date.day', 'count']
list: ['metadata.publication_date.day', query.mesured]
}
};
$http.post(query.url, data, {cache: true}).success(function(response) {
......@@ -397,30 +405,39 @@ gargantext.controller("GraphController", function($scope, $http, $element) {
$scope.$on('updateDataset', function(e, data) {
$scope.queries[data.datasetId] = {
url: data.url,
filters: data.filters
filters: data.filters,
mesured: data.mesured
};
// $scope.query();
});
});
// For debugging only!
setTimeout(function(){
var corpusId = $('div.corpus select option').last().val();
// first dataset
$('div.corpus select').val(corpusId).change();
setTimeout(function(){
// second dataset
$('button.add').first().click();
var d = $('li.dataset').last();
d.find('select').change();
// second dataset's filter
d.find('div.filters button').last().click();
d.find('select').last().val('metadata').change();
d.find('select').last().val('abstract').change();
d.find('select').last().val('contains').change();
d.find('input').last().val('dea').change();
// refresh
$('button.refresh').first().click();
}, 500);
}, 500);
\ No newline at end of file
// // For debugging only!
// setTimeout(function(){
// var corpusId = $('div.corpus select option').last().val();
// // first dataset
// $('div.corpus select').val(corpusId).change();
// setTimeout(function(){
// $('div.filters button').last().click();
// var d = $('li.dataset').last();
// d.find('select').last().val('metadata').change();
// d.find('select').last().val('publication_date').change();
// d.find('select').last().val('>').change();
// d.find('input').last().val('2010').change();
// // second dataset
// // $('button.add').first().click();
// // var d = $('li.dataset').last();
// // d.find('select').change();
// // // second dataset's filter
// // d.find('div.filters button').last().click();
// // d.find('select').last().val('metadata').change();
// // d.find('select').last().val('abstract').change();
// // d.find('select').last().val('contains').change();
// // d.find('input').last().val('dea').change();
// // refresh
// $('button.refresh').first().click();
// }, 500);
// }, 500);
\ No newline at end of file
......@@ -219,12 +219,12 @@
<div ng-app="Gargantext" ng-controller="GraphController">
<ul class="datasets">
<button class="add" ng-click="addDataset()">Add a dataset...</button>
<li class="dataset" ng-controller="DatasetController" ng-repeat="dataset in datasets">
<hr/>
<div class="corpus">
<button ng-click="removeDataset($index)" title="remove this dataset">X</button>
<select ng-model="mesured" style="background-color:{{ getColor($index, datasets.length) }}">
<option ng-repeat="(key, value) in {'Documents count': 'count', 'Ngrams count': 'ngrams.count'}" value="{{ value }}">{{ key }}</option>
</select>
<select ng-model="mesured" style="background-color:{{ getColor($index, datasets.length) }}" ng-options="value as key for (key, value) in {'Documents count': 'nodes.count', 'Ngrams count': 'ngrams.count'}" ng-change="updateQuery()"></select>
in the corpus
<select ng-model="corpusId" ng-change="updateEntities()">
<option ng-repeat="corpus in corpora" value="{{corpus.id}}">{{corpus.name}}</option>
......@@ -255,21 +255,35 @@
</ul>
<button ng-click="addFilter()">Add a filter...</button>
</div>
<hr/>
</li>
</ul>
<button class="refresh" ng-click="query()">Refresh results</button>
<button class="add" ng-click="addDataset()">Add a dataset...</button>
<hr/>
<button style="width:100%" class="refresh" ng-click="query()">Refresh results</button>
<div class="graph">
<linechart data="graph.data" options="graph.options"></linechart>
</div>
<div class="graph-parameters">
<select ng-model="graph.options.axes.y.type">
<option ng-repeat="(key, value) in {linear: 'linear', logarithmic: 'log'}" value="{{ value }}">{{ key }}</option>
X-axis: groups the results by
<select ng-model="groupingKey" ng-options="key for key in ['day', 'month', 'year', 'decade', 'century']">
</select>
<br/>
Y-axis: use a
<select ng-model="graph.options.axes.y.type" ng-options="type for type in ['log', 'linear']"></select>
scale
</div>
<div class="graph">
<linechart data="graph.data" options="graph.options"></linechart>
<br/>
Interpolation:
<select ng-model="graph.options.lineMode">
<option ng-repeat="mode in ['bundle', 'linear']" value="{{ mode }}">{{ mode }}</option>
</select>
<span ng-if="graph.options.lineMode != 'linear'">
with a smoothing of smoothing:
<input type="text" disabled="disabled" ng-model="graph.options.tension" />
<input type="range" min="0" max="2" step=".1" ng-model="graph.options.tension" />
</span>
</div>
</div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment