Commit e4fa603e authored by Romain Loth's avatar Romain Loth

journals view, with new API route for journal facet, dynatable css factorized...

journals view, with new API route for journal facet, dynatable css factorized (applies for all corpora templates) and menu.html providing a corpora navbar to switch between journals and documents
parent 8ba69ab7
...@@ -6,6 +6,7 @@ from gargantext.constants import * ...@@ -6,6 +6,7 @@ from gargantext.constants import *
from gargantext.util.validation import validate from gargantext.util.validation import validate
from collections import defaultdict
_node_available_fields = ['id', 'parent_id', 'name', 'typename', 'hyperdata', 'ngrams'] _node_available_fields = ['id', 'parent_id', 'name', 'typename', 'hyperdata', 'ngrams']
_node_default_fields = ['id', 'parent_id', 'name', 'typename'] _node_default_fields = ['id', 'parent_id', 'name', 'typename']
...@@ -109,3 +110,70 @@ class NodeResource(APIView): ...@@ -109,3 +110,70 @@ class NodeResource(APIView):
) )
session.commit() session.commit()
return JsonHttpResponse({'deleted': result.rowcount}) return JsonHttpResponse({'deleted': result.rowcount})
class CorpusFacet(APIView):
"""Loop through a corpus node's docs => do counts by a hyperdata field
(url: /api/nodes/<node_id>/facets?hyperfield=<journal>)
"""
# - old url: '^project/(\d+)/corpus/(\d+)/journals/journals.json$',
# - old view: tests.ngramstable.views.get_journals_json()
# - now generalized for various hyperdata field:
# -> journal
# -> publication_year
# -> rubrique
# -> language...
def get(self, request, node_id):
# check that the node is a corpus
# ? faster from cache than: corpus = session.query(Node)...
corpus = cache.Node[node_id]
if corpus.typename != 'CORPUS':
raise ValidationException(
"Only nodes of type CORPUS can accept facet queries" +
" (but this node has type %s)..." % corpus.typename
)
else:
self.corpus = corpus
# check that the hyperfield parameter makes sense
_facet_available_subfields = [
'journal', 'publication_year', 'rubrique',
'language_iso2', 'language_iso3', 'language_name'
]
parameters = get_parameters(request)
# validate() triggers an info message if subfield not in range
parameters = validate(parameters, {'type': dict, 'items': {
'hyperfield': {'type': str, 'range': _facet_available_subfields}
}})
subfield = parameters['hyperfield']
# do the aggregated sum
(xcounts, total) = self._ndocs_by_facet(subfield)
# response
return JsonHttpResponse({
'doc_count' : total,
'by': { subfield: xcounts }
})
def _ndocs_by_facet(self, subfield='journal'):
"""for example on 'journal'
xcounts = {'j good sci' : 25, 'nature' : 32, 'j bla bla' : 1... }"""
xcounts = defaultdict(int)
total = 0
for doc in self.corpus.children(typename='DOCUMENT'):
if subfield in doc.hyperdata:
xcounts[doc.hyperdata[subfield]] += 1
else:
xcounts["_NA_"] += 1
total += 1
# the counts below could also be memoized
# // if subfield not in corpus.aggs:
# // corpus.aggs[subfield] = xcounts
return (xcounts, total)
...@@ -6,4 +6,6 @@ from . import nodes ...@@ -6,4 +6,6 @@ from . import nodes
urlpatterns = [ urlpatterns = [
url(r'^nodes$', nodes.NodeListResource.as_view()), url(r'^nodes$', nodes.NodeListResource.as_view()),
url(r'^nodes/(\d+)$', nodes.NodeResource.as_view()), url(r'^nodes/(\d+)$', nodes.NodeResource.as_view()),
url(r'^nodes/(\d+)/facets$', nodes.CorpusFacet.as_view()),
] ]
...@@ -46,4 +46,31 @@ def corpus(request, project_id, corpus_id): ...@@ -46,4 +46,31 @@ def corpus(request, project_id, corpus_id):
@requires_auth @requires_auth
def chart(request, project_id, corpus_id): def chart(request, project_id, corpus_id):
user, project, corpus = _get_user_project_corpus(request, project_id, corpus_id) authorized, user, project, corpus = _get_user_project_corpus(request, project_id, corpus_id)
@requires_auth
def docs_by_journals(request, project_id, corpus_id):
'''
Browse journal titles for a given corpus
NB: javascript in page will GET counts from our api: facets?subfield=journal
# TODO refactor Journals_dyna_charts_and_table.js
'''
# we pass our corpus to mark it's a corpora page
corpus = cache.Node[corpus_id]
# and the project just for project.id in corpusBannerTop
project = cache.Node[project_id]
# rendered page : journals.html
return render(
template_name = 'pages/corpora/journals.html',
request = request,
context = {
'debug': settings.DEBUG,
'date': datetime.now(),
'project': project,
'corpus' : corpus,
'view': 'journals'
},
)
...@@ -23,4 +23,6 @@ urlpatterns = [ ...@@ -23,4 +23,6 @@ urlpatterns = [
url(r'^projects/(\d+)/corpora/(\d+)/?$', corpora.corpus), url(r'^projects/(\d+)/corpora/(\d+)/?$', corpora.corpus),
url(r'^projects/(\d+)/corpora/(\d+)/chart/?$', corpora.chart), url(r'^projects/(\d+)/corpora/(\d+)/chart/?$', corpora.chart),
# corpus by journals
url(r'^projects/(\d+)/corpora/(\d+)/journals/?$', corpora.docs_by_journals),
] ]
// styles for dynatables
.no-transition {
-webkit-transition: height 0.1s;
-moz-transition: height 0.1s;
-ms-transition: height 0.1s;
-o-transition: height 0.1s;
transition: height 0.1s;
}
th { color: #fff; }
th a {
color: #fff;
font-weight: bold;
font-size: 0.9em;
}
.dynatable-record-count {
font-size: 0.7em;
}
.dynatable-pagination-links {
font-size: 0.7em;
}
#corpusdisplayer {
width:200px;
margin:0 auto;
display:block;
}
This diff is collapsed.
...@@ -12,37 +12,12 @@ ...@@ -12,37 +12,12 @@
<link rel="stylesheet" type="text/css" href="{% static "css/jquery/jquery.easy-pie-chart.css"%}"> <link rel="stylesheet" type="text/css" href="{% static "css/jquery/jquery.easy-pie-chart.css"%}">
<link rel="stylesheet" type="text/css" href="{% static "css/jquery/jquery.dynatable.css"%}"/> <link rel="stylesheet" type="text/css" href="{% static "css/jquery/jquery.dynatable.css"%}"/>
<link rel="stylesheet" type="text/css" href="{% static "css/gargantext/tables.css"%}"/>
<script type="text/javascript" src="{% static "js/d3/d3.js"%}"></script> <script type="text/javascript" src="{% static "js/d3/d3.js"%}"></script>
<script type="text/javascript" src="{% static "js/d3/dc.js"%}"></script> <script type="text/javascript" src="{% static "js/d3/dc.js"%}"></script>
<script type="text/javascript" src="{% static "js/d3/crossfilter.js"%}"></script> <script type="text/javascript" src="{% static "js/d3/crossfilter.js"%}"></script>
<style>
.no-transition {
-webkit-transition: height 0.1s;
-moz-transition: height 0.1s;
-ms-transition: height 0.1s;
-o-transition: height 0.1s;
transition: height 0.1s;
}
th { color: #fff; }
th a {
color: #fff;
font-weight: normal;
font-style: italic;
font-size: 0.9em;
}
.dynatable-record-count {
font-size: 0.7em;
}
.dynatable-pagination-links {
font-size: 0.7em;
}
</style>
{% endblock %} {% endblock %}
......
{% extends "pages/menu.html" %}
{% block css %}
{% load staticfiles %}
<link rel="stylesheet" type="text/css" href="{% static "css/bootstrap.css" %}">
<link rel="stylesheet" type="text/css" href="{% static "css/d3/dc.css"%}"/>
<link rel="stylesheet" type="text/css" href="{% static "css/jquery/jquery.dynatable.css"%}"/>
<link rel="stylesheet" type="text/css" href="{% static "css/gargantext/tables.css"%}"/>
<script type="text/javascript" src="{% static "js/d3/d3.js"%}"></script>
<script type="text/javascript" src="{% static "js/d3/crossfilter.js"%}"></script>
<script type="text/javascript" src="{% static "js/d3/dc.js"%}"></script>
{% endblock %}
{% block content %}
<div class="container">
<div class="jumbotron">
<div class="row">
<div id="monthly-move-chart">
<center>
Select a frequency group in the chart with blue bars to zoom in
<p align="center">
<a class="btn btn-xs btn-default" role="button" href="/chart/corpus/{{ corpus.id }}/data.csv">Save</a>
<a class="btn btn-xs btn-default" href="javascript:volumeChart.filterAll();dc.redrawAll();">Reset</a></p>
<!-- <p style="font-size:70%">
<b>x</b>: amount of documents for the journal
<b>y</b>: number of journals with that amount
</p> -->
<div class="clearfix"></div>
</center>
</div>
</div>
<div class="row">
<div id="monthly-volume-chart"></div>
</div>
<div id="content_loader">
<br>
<center>
<!-- <img width="10%" src="{% static "img/ajax-loader.gif"%}"></img> -->
</center>
<br>
</div>
<div class="row">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-target="#journal_table" href="#">
<!-- Final_UpdateTable redraws the dynatable if necessary -->
<p id="corpusdisplayer" onclick='Final_UpdateTable("click")' class="btn btn-primary btn-lg">
Open Folder
</p>
</a>
</h4>
</div>
<div id="journal_table" class="panel-collapse collapse in no-transition" role="tabpanel">
<div class="panel-body">
<div id="div-table">
<!-- (table id="my-ajax-table") dynamically set by Journals_dyna_chart_and_table -->
</div>
</div>
</div> <!-- /div panel-collapse -->
</div> <!-- /div panel -->
</div> <!-- /row with the dynatable panels -->
</div> <!-- /jumbotron -->
</div> <!-- /container -->
<script type="text/javascript" src="{% static "js/jquery/jquery.min.js" %}"></script>
<script src="{% static "js/bootstrap/bootstrap.min.js" %}"></script>
<script type="text/javascript" src="{% static "js/jquery/jquery.dynatable.js" %}"></script>
<!-- custom-lib for dynatable.js and dc.js -->
<script type="text/javascript" src="{% static "js/gargantext/Journals_dyna_chart_and_table.js" %}"></script>
{% endblock %}
...@@ -58,6 +58,23 @@ ...@@ -58,6 +58,23 @@
<!--/.nav-collapse --> <!--/.nav-collapse -->
{% block corpusBannerTop %} {% block corpusBannerTop %}
{% if corpus %}
<div class="container theme-showcase">
<div class="jumbotron" style="margin-bottom:0">
<div id="corpusbar" class="row">
<div class="col-md-6">
<div class="btn-group btn-group-justified">
<center>
<a type="button" class="btn btn-default {% if view == "documents" %}active{%endif%}" href="/projects/{{project.id}}/corpora/{{ corpus.id }}/">Documents</a>
<a type="button" class="btn btn-default {% if view == "journals" %}active{%endif%}" href="/projects/{{project.id}}/corpora/{{ corpus.id }}/journals">Journals</a>
</center>
</div>
</div>
</div>
</div>
</div>
{% endif %}
{% endblock %} {% endblock %}
......
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