diff --git a/journals/models.py b/journals/models.py index 0d30f3a427fd004ffef4d5da950ffcf168708ea1..7b310e4377c00a774b9819d6812c757a19d2d93e 100644 --- a/journals/models.py +++ b/journals/models.py @@ -2,6 +2,7 @@ from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType from django.contrib.postgres.fields import JSONField from django.db import models +from django.db.models import Avg, F from django.utils import timezone from django.urls import reverse @@ -51,14 +52,30 @@ class Journal(models.Model): def get_abbreviation_citation(self): return journal_name_abbrev_citation(self.name) - def citation_rate(self): + def nr_publications(self, tier=None): + publications = Publication.objects.filter(in_issue__in_volume__in_journal=self) + if tier: + publications = publications.filter( + accepted_submission__eicrecommendations__recommendation=tier) + return publications.count() + + def avg_processing_duration(self): + duration = Publication.objects.filter( + in_issue__in_volume__in_journal=self).aggregate( + avg=Avg(F('publication_date') - F('submission_date')))['avg'] + return duration.total_seconds() / 86400 + + def citation_rate(self, tier=None): """ Returns the citation rate in units of nr citations per article per year. """ - pubs = Publication.objects.filter(in_issue__in_volume__in_journal=self) + publications = Publication.objects.filter(in_issue__in_volume__in_journal=self) + if tier: + publications = publications.filter( + accepted_submission__eicrecommendations__recommendation=tier) ncites = 0 - deltat = 1 # to avoid division by zero - for pub in pubs: + deltat = 1 # to avoid division by zero + for pub in publications: if pub.citedby and pub.latest_citedby_update: ncites += len(pub.citedby) deltat += (pub.latest_citedby_update.date() - pub.publication_date).days @@ -83,18 +100,34 @@ class Volume(models.Model): def doi_string(self): return '10.21468/' + self.doi_label - def citation_rate(self): + def nr_publications(self, tier=None): + publications = Publication.objects.filter(in_issue__in_volume=self) + if tier: + publications = publications.filter( + accepted_submission__eicrecommendations__recommendation=tier) + return publications.count() + + def avg_processing_duration(self): + duration = Publication.objects.filter( + in_issue__in_volume=self).aggregate( + avg=Avg(F('publication_date') - F('submission_date')))['avg'] + return duration.total_seconds() / 86400 + + def citation_rate(self, tier=None): """ Returns the citation rate in units of nr citations per article per year. """ - pubs = Publication.objects.filter(in_issue__in_volume=self) + publications = Publication.objects.filter(in_issue__in_volume=self) + if tier: + publications = publications.filter( + accepted_submission__eicrecommendations__recommendation=tier) ncites = 0 - deltat = 1 # to avoid division by zero - for pub in pubs: + deltat = 1 # to avoid division by zero + for pub in publications: if pub.citedby and pub.latest_citedby_update: ncites += len(pub.citedby) deltat += (pub.latest_citedby_update.date() - pub.publication_date).days - return (ncites * 365.25/deltat) + return (ncites * 365.25 / deltat) class Issue(models.Model): @@ -147,14 +180,30 @@ class Issue(models.Model): return self.start_date <= timezone.now().date() and\ self.until_date >= timezone.now().date() - def citation_rate(self): + def nr_publications(self, tier=None): + publications = Publication.objects.filter(in_issue=self) + if tier: + publications = publications.filter( + accepted_submission__eicrecommendations__recommendation=tier) + return publications.count() + + def avg_processing_duration(self): + duration = Publication.objects.filter( + in_issue=self).aggregate( + avg=Avg(F('publication_date') - F('submission_date')))['avg'] + return duration.total_seconds() / 86400 + + def citation_rate(self, tier=None): """ Returns the citation rate in units of nr citations per article per year. """ - pubs = Publication.objects.filter(in_issue=self) + publications = Publication.objects.filter(in_issue=self) + if tier: + publications = publications.filter( + accepted_submission__eicrecommendations__recommendation=tier) ncites = 0 - deltat = 1 # to avoid division by zero - for pub in pubs: + deltat = 1 # to avoid division by zero + for pub in publications: if pub.citedby and pub.latest_citedby_update: ncites += len(pub.citedby) deltat += (pub.latest_citedby_update.date() - pub.publication_date).days diff --git a/stats/templates/stats/statistics.html b/stats/templates/stats/statistics.html index 61fa1a21de5800c7f380a3937c80e4ad18dcd890..23e5ba55d74407e294bfab43697556b705755cd1 100644 --- a/stats/templates/stats/statistics.html +++ b/stats/templates/stats/statistics.html @@ -41,78 +41,122 @@ </ul> {% if journal %} - <h2>Results:</h2> - <table class="table"> - <tr> - <th>DOI label</th> - {% if year %} - <th>Year</th> - <th>Nr submissions<br/>(distinct)</th> - <th>Nr submissions<br/>(including resubmissions)</th> - <th>Nr assignment failed</th> - <th>Nr accepted/<br/>published</th> - <th>Nr rejected</th> - <th>Nr withdrawn</th> - {% else %} - <th>Nr publications</th> - <th>Duration average</th> - <th>Citation rate (per paper per year)</ht> - {% endif %} - </tr> - <tr> - {% if issue %} - <td>{{ issue.doi_label }}</td> - <td>{{ issue|issue_nr_publications }}</td> - <td>{{ issue|issue_avg_processing_duration|floatformat:2 }} days</td> - <td>{{ issue|issue_citation_rate|floatformat:2 }}</td> - {% elif volume %} - <td>{{ volume.doi_label }}</td> - <td>{{ volume|volume_nr_publications }}</td> - <td>{{ volume|volume_avg_processing_duration|floatformat:2 }} days</td> - <td>{{ volume|volume_citation_rate|floatformat:2 }}</td> - {% else %} - <td>{{ journal.doi_label }}</td> - {% if year %} - <td>{{ year }}</td> - <td>{{ submissions|submissions_count_distinct }}</td> - <td>{{ submissions|length }}</td> - <td>{{ submissions.assignment_failed.count }}</td> - <td>{{ submissions.accepted.count|add:submissions.published.count }}</td> - <td>{{ submissions.rejected.count }}</td> - <td>{{ submissions.withdrawn.count }}</td> - {% else %} - <td>{{ journal|journal_nr_publications }}</td> - <td>{{ journal|journal_avg_processing_duration|floatformat:2 }} days</td> - <td>{{ journal|journal_citation_rate|floatformat:2 }}</td> - {% endif %} - {% endif %} - </tr> - </table> +<h2>Results:</h2> +<table class="table"> + <tr> + <th>DOI label</th> + {% if year %} + <th>Year</th> + <th>Nr submissions<br/>(distinct)</th> + <th>Nr submissions<br/>(including resubmissions)</th> + <th>Nr assignment failed</th> + <th>Nr accepted/<br/>published</th> + <th>Nr rejected</th> + <th>Nr withdrawn</th> + {% else %} + <th>Nr publications</th> + <th>Duration average</th> + <th>Citation rate (per paper per year)</th> {% endif %} - + </tr> + <tr> + {% if issue %} + <td>{{ issue.doi_label }}</td> + <td>{% nr_publications issue %}</td> + <td>{% avg_processing_duration issue as avg %}{{ avg|floatformat:2 }} days</td> + <td>{% citation_rate issue as cr %}{{ cr|floatformat:2 %}</td> + {% elif volume %} + <td>{{ volume.doi_label }}</td> + <td>{% nr_publications volume %}</td> + <td>{% avg_processing_duration volume as avg %}{{ avg|floatformat:2 }} days</td> + <td>{% citation_rate volume as cr %}{{ cr|floatformat:2 }}</td> + {% else %} + <td>{{ journal.doi_label }}</td> {% if year %} - <h2>Refereeing stats for {{ year }}</h2> - <table class="table"> - <tr> - <th>Nr refereeing<br/>invitations</th> - <th>Nr accepted</th> - <th>Nr declined</th> - <th>Nr pending</th> - <th>Nr reports<br/>obtained</th> - <th>Nr obtained<br/>(invited)</th> - <th>Nr obtained<br/>(contributed)</th> - </tr> - <tr> - <td>{{ nr_ref_inv }}</td> - <td>{{ nr_acc }} ({% widthratio nr_acc nr_ref_inv 100 %}%)</td> - <td>{{ nr_dec }} ({% widthratio nr_dec nr_ref_inv 100 %}%)</td> - <td>{{ nr_pen }} ({% widthratio nr_pen nr_ref_inv 100 %}%)</td> - <td>{{ nr_rep_obt }}</td> - <td>{{ nr_rep_obt_inv }} ({% widthratio nr_rep_obt_inv nr_rep_obt 100 %}%)</td> - <td>{{ nr_rep_obt_con }} ({% widthratio nr_rep_obt_con nr_rep_obt 100 %}%)</td> - </tr> - </table> + <td>{{ year }}</td> + <td>{{ submissions|submissions_count_distinct }}</td> + <td>{{ submissions|length }}</td> + <td>{{ submissions.assignment_failed.count }}</td> + <td>{{ submissions.accepted.count|add:submissions.published.count }}</td> + <td>{{ submissions.rejected.count }}</td> + <td>{{ submissions.withdrawn.count }}</td> + {% else %} + <td>{% nr_publications journal %}</td> + <td>{% avg_processing_duration journal as avg %}{{ avg|floatformat:2 }} days</td> + <td>{% citation_rate journal as cr %}{{ cr|floatformat:2 }}</td> + {% endif %} {% endif %} + </tr> +</table> + +<table class="table"> + <tr> + <th>DOI label</th> + <th colspan="3">Nr per Tier</th> + <th colspan="3">Citation rate (per paper per year)</th> + </tr> + <tr> + <th></th> + <th>I</th> + <th>II</th> + <th>IIII</th> + <th>I</th> + <th>II</th> + <th>IIII</th> + </tr> + <tr> + {% if issue %} + <td>{{ issue.doi_label }}</td> + <td>{% nr_publications issue tier=1 %}</td> + <td>{% nr_publications issue tier=2 %}</td> + <td>{% nr_publications issue tier=3 %}</td> + <td>{% citation_rate issue tier=1 as cr %}{{ cr|floatformat:2 }}</td> + <td>{% citation_rate issue tier=2 as cr %}{{ cr|floatformat:2 }}</td> + <td>{% citation_rate issue tier=3 as cr %}{{ cr|floatformat:2 }}</td> + {% elif volume %} + <td>{{ volume.doi_label }}</td> + <td>{% nr_publications volume tier=1 %}</td> + <td>{% nr_publications volume tier=2 %}</td> + <td>{% nr_publications volume tier=3 %}</td> + <td>{% citation_rate volume tier=1 as cr %}{{ cr|floatformat:2 }}</td> + <td>{% citation_rate volume tier=2 as cr %}{{ cr|floatformat:2 }}</td> + <td>{% citation_rate volume tier=3 as cr %}{{ cr|floatformat:2 }}</td> + {% else %} + <td>{{ journal.doi_label }}</td> + <td>{% nr_publications journal tier=1 %}</td> + <td>{% nr_publications journal tier=2 %}</td> + <td>{% nr_publications journal tier=3 %}</td> + <td>{% citation_rate journal tier=1 as cr %}{{ cr|floatformat:2 }}</td> + <td>{% citation_rate journal tier=2 as cr %}{{ cr|floatformat:2 }}</td> + <td>{% citation_rate journal tier=3 as cr %}{{ cr|floatformat:2 }}</td> + {% endif %} + </tr> +</table> +{% endif %} + +{% if year %} +<h2>Refereeing stats for {{ year }}</h2> +<table class="table"> + <tr> + <th>Nr refereeing<br/>invitations</th> + <th>Nr accepted</th> + <th>Nr declined</th> + <th>Nr pending</th> + <th>Nr reports<br/>obtained</th> + <th>Nr obtained<br/>(invited)</th> + <th>Nr obtained<br/>(contributed)</th> + </tr> + <tr> + <td>{{ nr_ref_inv }}</td> + <td>{{ nr_acc }} ({% widthratio nr_acc nr_ref_inv 100 %}%)</td> + <td>{{ nr_dec }} ({% widthratio nr_dec nr_ref_inv 100 %}%)</td> + <td>{{ nr_pen }} ({% widthratio nr_pen nr_ref_inv 100 %}%)</td> + <td>{{ nr_rep_obt }}</td> + <td>{{ nr_rep_obt_inv }} ({% widthratio nr_rep_obt_inv nr_rep_obt 100 %}%)</td> + <td>{{ nr_rep_obt_con }} ({% widthratio nr_rep_obt_con nr_rep_obt 100 %}%)</td> + </tr> +</table> +{% endif %} {% endblock content %} diff --git a/stats/templatetags/stats_extras.py b/stats/templatetags/stats_extras.py index d6362255440acb8a9f2a27db5fd665b2bc8f2c55..335c813cc216907cb5ee9828390e200a42969854 100644 --- a/stats/templatetags/stats_extras.py +++ b/stats/templatetags/stats_extras.py @@ -1,13 +1,22 @@ from django import template -from django.db.models import Avg, F - -from journals.models import Publication -from submissions.constants import SUBMISSION_STATUS_OUT_OF_POOL -from submissions.models import Submission register = template.Library() +@register.simple_tag +def avg_processing_duration(obj, *args, **kwargs): + return getattr(obj, 'avg_processing_duration')(*args, **kwargs) + + +@register.simple_tag +def nr_publications(obj, *args, **kwargs): + return getattr(obj, 'nr_publications')(*args, **kwargs) + + +@register.simple_tag +def citation_rate(obj, *args, **kwargs): + return getattr(obj, 'citation_rate')(*args, **kwargs) + @register.filter(name='submissions_count_distinct') def submissions_count_distinct(submissions): @@ -25,54 +34,3 @@ def journal_publication_years(journal): if volume.until_date.year not in years: years.append(volume.until_date.year) return sorted(years) - - -@register.filter(name='journal_nr_publications') -def journal_nr_publications(journal): - return Publication.objects.filter(in_issue__in_volume__in_journal=journal).count() - -@register.filter(name='journal_avg_processing_duration') -def journal_avg_processing_duration(journal): - duration = Publication.objects.filter( - in_issue__in_volume__in_journal=journal).aggregate( - avg=Avg(F('publication_date') - F('submission_date')))['avg'] - if not duration: return 0 - return duration.days + duration.seconds/86400 - -@register.filter(name='journal_citation_rate') -def journal_citation_rate(journal): - return journal.citation_rate() - - -@register.filter(name='volume_nr_publications') -def volume_nr_publications(volume): - return Publication.objects.filter(in_issue__in_volume=volume).count() - -@register.filter(name='volume_avg_processing_duration') -def volume_avg_processing_duration(volume): - duration = Publication.objects.filter( - in_issue__in_volume=volume).aggregate( - avg=Avg(F('publication_date') - F('submission_date')))['avg'] - if not duration: return 0 - return duration.days + duration.seconds/86400 - -@register.filter(name='volume_citation_rate') -def volume_citation_rate(volume): - return volume.citation_rate() - - -@register.filter(name='issue_nr_publications') -def issue_nr_publications(issue): - return Publication.objects.filter(in_issue=issue).count() - -@register.filter(name='issue_avg_processing_duration') -def issue_avg_processing_duration(issue): - duration = Publication.objects.filter( - in_issue=issue).aggregate( - avg=Avg(F('publication_date') - F('submission_date')))['avg'] - if not duration: return 0 - return duration.days + duration.seconds/86400 - -@register.filter(name='issue_citation_rate') -def issue_citation_rate(issue): - return issue.citation_rate() diff --git a/stats/views.py b/stats/views.py index 11d7bd845e11df31b0c12fc591974163be366f78..dd416c843a34dfa75973cb963d437ddbd601ba5e 100644 --- a/stats/views.py +++ b/stats/views.py @@ -1,10 +1,9 @@ import datetime -from django.contrib.auth.decorators import login_required, permission_required +from django.contrib.auth.decorators import permission_required from django.shortcuts import get_object_or_404, render -from journals.constants import SCIPOST_JOURNALS_SUBMIT -from journals.models import Journal, Volume, Issue, Publication +from journals.models import Journal, Volume, Issue from submissions.models import Submission @@ -19,8 +18,9 @@ def statistics(request, journal_doi_label=None, volume_nr=None, issue_nr=None, y context['journal'] = journal if year: context['year'] = year - submissions = Submission.objects.filter(submitted_to_journal=journal_doi_label - ).originally_submitted(datetime.date(int(year), 1, 1), datetime.date(int(year), 12, 31)) + submissions = Submission.objects.filter( + submitted_to_journal=journal_doi_label).originally_submitted( + datetime.date(int(year), 1, 1), datetime.date(int(year), 12, 31)) context['submissions'] = submissions nr_ref_inv = 0 nr_acc = 0 @@ -29,8 +29,6 @@ def statistics(request, journal_doi_label=None, volume_nr=None, issue_nr=None, y nr_rep_obt = 0 nr_rep_obt_inv = 0 nr_rep_obt_con = 0 - nr_rep_ref = 0 - nr_aw_vet = 0 for submission in submissions: nr_ref_inv += submission.referee_invitations.count() nr_acc += submission.count_accepted_invitations()