diff --git a/scholia/app/templates/wikiproject.html b/scholia/app/templates/wikiproject.html
new file mode 100644
index 000000000..bf4fa0ef9
--- /dev/null
+++ b/scholia/app/templates/wikiproject.html
@@ -0,0 +1,92 @@
+{% extends "base.html" %}
+
+{% set aspect = 'wikiproject' %}
+
+{% block in_ready %}
+
+{{ sparql_to_table("maintained") }}
+{{ sparql_to_table("focus") }}
+
+{{ sparql_to_iframe('context') }}
+{{ sparql_to_table('recently-published-works') }}
+{{ sparql_to_iframe('publications-per-year') }}
+{{ sparql_to_table('earliest-published-works') }}
+{{ sparql_to_table('authors') }}
+{{ sparql_to_table('author-awards') }}
+{{ sparql_to_table('topics') }}
+{{ sparql_to_table('venues') }}
+{{ sparql_to_iframe('organization-map') }}
+
+{% endblock %}
+
+
+
+{% block page_content %}
+
+
WikiProject
+
+
+
+Types of items maintained by this WikiProject
+
+
+
+Types of items on focus list of this WikiProject
+
+
+
+The topic in context
+
+
+
+
+
+Works
+
+Recently published works
+
+
+
+Publications per year
+
+
+
+
+
+Earliest published works
+
+
+
+Authors
+
+Related authors
+
+
+
+Awards received by authors
+
+
+
+Topics
+
+From random sample
+
+
+
+Related venues and series
+
+
+
+Map of organizations associated with related works
+
+The colours indicate how many publications on the topic are associated with organizations in the given location, as
+detailed in the legend (top right).
+
+
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/scholia/app/templates/wikiproject_author-awards.sparql b/scholia/app/templates/wikiproject_author-awards.sparql
new file mode 100644
index 000000000..f793d204f
--- /dev/null
+++ b/scholia/app/templates/wikiproject_author-awards.sparql
@@ -0,0 +1,31 @@
+PREFIX target:
+
+SELECT ?count
+?award ?awardLabel (CONCAT("/award/", SUBSTR(STR(?award), 32)) AS ?awardUrl)
+?recipients ?recipientsUrl
+WITH {
+ SELECT (COUNT(?researcher) AS ?count) ?award
+ (GROUP_CONCAT(DISTINCT ?researcher_label; separator=", ") AS ?recipients)
+ (CONCAT("../authors/", GROUP_CONCAT(DISTINCT SUBSTR(STR(?researcher), 32); separator=",")) AS ?recipientsUrl)
+ WHERE {
+ {
+ SELECT DISTINCT ?researcher ?award WHERE {
+ hint:Query hint:optimizer "None" .
+ { ?work wdt:P6104 target: .}
+ union
+ { ?work wdt:P5008 target: .}
+ ?work wdt:P50 ?researcher .
+ ?researcher wdt:P166 ?award .
+ }
+ LIMIT 100
+ }
+ ?researcher rdfs:label ?researcher_label . FILTER (LANG(?researcher_label) = 'en')
+ }
+ GROUP BY ?award
+} AS %result
+WHERE {
+ INCLUDE %result
+ ?award rdfs:label ?awardLabel . FILTER (LANG(?awardLabel) = 'en')
+}
+GROUP BY ?count ?award ?awardLabel ?recipients ?recipientsUrl
+ORDER BY DESC(?count)
diff --git a/scholia/app/templates/wikiproject_authors.sparql b/scholia/app/templates/wikiproject_authors.sparql
new file mode 100644
index 000000000..c0a700d82
--- /dev/null
+++ b/scholia/app/templates/wikiproject_authors.sparql
@@ -0,0 +1,30 @@
+#defaultView:Table
+
+PREFIX target:
+
+SELECT
+ ?count
+ ?author ?authorLabel ?authorDescription (CONCAT("/author/", SUBSTR(STR(?author), 32)) AS ?authorUrl)
+ (COALESCE(?orcid_, CONCAT("orcid-search/quick-search/?searchQuery=", ?authorLabel)) AS ?orcid)
+WITH {
+ SELECT
+ ?author
+ (count(?work) as ?count)
+ WHERE {
+ { ?work wdt:P6104 target: .}
+ union
+ { ?work wdt:P5008 target: .}
+ ?work wdt:P50 ?author .
+ }
+ GROUP BY ?author
+ ORDER BY DESC(?count)
+ LIMIT 200
+} AS %result
+WHERE {
+ INCLUDE %result
+
+ # Include optional ORCID iD
+ OPTIONAL { ?author wdt:P496 ?orcid_ . }
+ SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en" . }
+}
+ORDER BY DESC(?count)
diff --git a/scholia/app/templates/wikiproject_context.sparql b/scholia/app/templates/wikiproject_context.sparql
new file mode 100644
index 000000000..00fa623b8
--- /dev/null
+++ b/scholia/app/templates/wikiproject_context.sparql
@@ -0,0 +1,54 @@
+PREFIX target:
+#defaultView:Graph
+SELECT ?node ?nodeLabel ?nodeImage ?childNode ?childNodeLabel ?childNodeImage ?rgb
+WITH {
+ SELECT DISTINCT ?property WHERE {
+ ?property a wikibase:Property;
+ wdt:P31 wd:Q18610173 ;
+ wdt:P31 wd:Q26940804 .
+ }
+} AS %properties
+WITH {
+ SELECT DISTINCT ?node ?childNode WHERE {
+ BIND(target: AS ?node)
+ ?node ?p ?i.
+ ?childNode ?x ?p.
+ ?childNode rdf:type wikibase:Property.
+ FILTER(STRSTARTS(STR(?i), "http://www.wikidata.org/entity/Q"))
+ FILTER(STRSTARTS(STR(?childNode), "http://www.wikidata.org/entity/P"))
+ }
+ LIMIT 5000
+} AS %nodes
+WITH {
+ SELECT DISTINCT ?childNode ?node ?rgb WHERE {
+ BIND("EFFBD8" AS ?rgb)
+ target: ?p ?childNode.
+ ?node ?x ?p.
+ ?node rdf:type wikibase:Property.
+ FILTER(STRSTARTS(STR(?childNode), "http://www.wikidata.org/entity/Q"))
+ }
+ LIMIT 5000
+} AS %childNodes
+WHERE {
+ {
+ INCLUDE %nodes
+ }
+ UNION
+ {
+ INCLUDE %childNodes
+ }
+
+ OPTIONAL {
+ INCLUDE %properties
+ ?property wikibase:directClaim ?nodeclaim.
+ ?node ?nodeclaim ?nodeImage.
+ }
+
+ OPTIONAL {
+ INCLUDE %properties
+ ?property wikibase:directClaim ?childNodeclaim.
+ ?childNode ?childNodeclaim ?childNodeImage.
+ }
+
+ SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
+}
diff --git a/scholia/app/templates/wikiproject_earliest-published-works.sparql b/scholia/app/templates/wikiproject_earliest-published-works.sparql
new file mode 100644
index 000000000..b130562d5
--- /dev/null
+++ b/scholia/app/templates/wikiproject_earliest-published-works.sparql
@@ -0,0 +1,35 @@
+PREFIX target:
+
+SELECT ?date ?work ?workLabel (CONCAT("/work/", SUBSTR(STR(?work), 32)) AS ?workUrl)
+?topicsUrl ?topics
+WITH {
+ SELECT DISTINCT ?work WHERE {
+ { ?work wdt:P6104 target: .}
+ union
+ { ?work wdt:P5008 target: .}
+ }
+} AS %works
+WITH {
+ SELECT (MAX(?dates) as ?datetime) ?work (GROUP_CONCAT(DISTINCT ?topic_label; separator=" // ") AS ?topics)
+ (CONCAT("../topics/", GROUP_CONCAT(DISTINCT SUBSTR(STR(?topic), 32); separator=",")) AS ?topicsUrl)
+ WHERE {
+ INCLUDE %works
+ ?work wdt:P921 ?topic .
+ ?work wdt:P577 ?dates .
+ FILTER (!isBLANK(?dates)) .
+ ?topic rdfs:label ?topic_label . FILTER (lang(?topic_label) = 'en')
+ }
+ GROUP BY ?work
+} AS %result
+WHERE {
+ INCLUDE %result
+
+ # There is a problem with BC dates
+ # BIND(xsd:date(?datetime) AS ?date)
+ BIND(REPLACE(STR(?datetime), 'T.*', '') AS ?date)
+
+ SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en" . }
+}
+GROUP BY ?date ?work ?workLabel ?topicsUrl ?topics
+ORDER BY ASC(?date)
+LIMIT 500
diff --git a/scholia/app/templates/wikiproject_focus.sparql b/scholia/app/templates/wikiproject_focus.sparql
new file mode 100644
index 000000000..7e564bea9
--- /dev/null
+++ b/scholia/app/templates/wikiproject_focus.sparql
@@ -0,0 +1,13 @@
+SELECT ?type ?typeLabel ?count WITH {
+ SELECT DISTINCT ?type (COUNT(?item) AS ?count) WHERE {
+ ?item wdt:P5008 wd:{{ q }};
+ (wdt:P31|wdt:P279) ?type.
+ }
+ GROUP BY ?type ?count
+ ORDER BY DESC (?count)
+} AS %result
+WHERE {
+ INCLUDE %result
+ SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en,da,de,es,fr,it,sv,uk,zh". }
+}
+ORDER BY DESC (?count)
\ No newline at end of file
diff --git a/scholia/app/templates/wikiproject_maintained.sparql b/scholia/app/templates/wikiproject_maintained.sparql
new file mode 100644
index 000000000..2afb622f0
--- /dev/null
+++ b/scholia/app/templates/wikiproject_maintained.sparql
@@ -0,0 +1,13 @@
+SELECT ?type ?typeLabel ?count WITH {
+ SELECT DISTINCT ?type (COUNT(?item) AS ?count) WHERE {
+ ?item wdt:P6104 wd:{{ q }};
+ (wdt:P31|wdt:P279) ?type.
+ }
+ GROUP BY ?type ?count
+ ORDER BY DESC (?count)
+} AS %result
+WHERE {
+ INCLUDE %result
+ SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en,da,de,es,fr,it,sv,uk,zh". }
+}
+ORDER BY DESC (?count)
\ No newline at end of file
diff --git a/scholia/app/templates/wikiproject_organization-map.sparql b/scholia/app/templates/wikiproject_organization-map.sparql
new file mode 100644
index 000000000..b86d07c5b
--- /dev/null
+++ b/scholia/app/templates/wikiproject_organization-map.sparql
@@ -0,0 +1,37 @@
+#defaultView:Map
+
+PREFIX target:
+
+SELECT ?organization ?organizationLabel ?geo ?count ?layer
+WITH {
+ SELECT DISTINCT ?work WHERE {
+ # Works on the topic
+ { ?work wdt:P6104 target: .}
+ union
+ { ?work wdt:P5008 target: .}
+ ?work wdt:P50 [].
+ }
+ LIMIT 20000
+} AS %works
+WITH {
+ SELECT DISTINCT ?organization ?geo (COUNT(DISTINCT ?work) AS ?count) WHERE {
+ INCLUDE %works
+ # Authors who have published works on the topic
+ ?work wdt:P50 ?author .
+ ?author ( wdt:P108 | wdt:P463 | wdt:P1416 ) / wdt:P361* ?organization .
+ # Use the headquarters location by default but keep the coordinate location as a fallback
+ OPTIONAL{?organization p:P159/pq:P625 ?hq_geo}
+ OPTIONAL{?organization wdt:P625 ?coord_geo}
+ BIND(IF(BOUND(?hq_geo), ?hq_geo, ?coord_geo) AS ?geo) .
+ FILTER(BOUND(?geo)) .
+ }
+ GROUP BY ?organization ?geo
+ ORDER BY DESC (?count)
+ LIMIT 2000
+} AS %organizations
+WHERE {
+ INCLUDE %organizations
+ BIND(IF( (?count < 1), "No results", IF((?count < 2), "1 result", IF((?count < 11), "1 < results ≤ 10", IF((?count < 101), "10 < results ≤ 100", IF((?count < 1001), "100 < results ≤ 1000", IF((?count < 10001), "1000 < results ≤ 10000", "10000 or more results") ) ) ) )) AS ?layer )
+ SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
+ }
+ORDER BY DESC (?count)
diff --git a/scholia/app/templates/wikiproject_publications-per-year.sparql b/scholia/app/templates/wikiproject_publications-per-year.sparql
new file mode 100644
index 000000000..fa6513a36
--- /dev/null
+++ b/scholia/app/templates/wikiproject_publications-per-year.sparql
@@ -0,0 +1,56 @@
+#defaultView:BarChart
+
+PREFIX target:
+
+SELECT
+ (STR(?year_) AS ?year)
+ (COUNT(?work) AS ?number_of_publications)
+
+ # Work type used to color the bar chart
+ ?type
+WITH {
+ # Find works with the topic. Also report the year
+ SELECT
+ ?work (MIN(?years) AS ?year_) (1 AS ?dummy) (SAMPLE(?article_type_) AS ?article_type)
+ WHERE {
+ { ?work wdt:P6104 target: .}
+ union
+ { ?work wdt:P5008 target: .}
+ ?work wdt:P577 ?dates .
+ BIND(YEAR(?dates) AS ?years) .
+
+ ?work wdt:P31 ?article_type_ .
+ }
+ GROUP BY ?work
+} AS %works
+WITH {
+ SELECT ?year_ WHERE {
+ # default values = 0
+ ?year_item wdt:P31 wd:Q577 .
+ ?year_item wdt:P585 ?date .
+ BIND(YEAR(?date) AS ?year_)
+ }
+} AS %default_counts
+WITH {
+ # Find earliest publication year
+ SELECT (MIN(?year_) AS ?earliest_year) WHERE {
+ INCLUDE %works
+ }
+ GROUP BY ?dummy
+} AS %earliest
+WHERE {
+ {
+ INCLUDE %works
+ ?article_type rdfs:label ?type . FILTER (LANG(?type) = "en")
+ }
+ UNION
+ {
+ INCLUDE %default_counts
+ BIND("_" AS ?type)
+ }
+ INCLUDE %earliest
+ BIND(YEAR(NOW()) AS ?this_year)
+ FILTER (?year_ >= ?earliest_year && ?year_ <= ?this_year && ?year_ >= YEAR("1900-01-01"^^xsd:dateTime))
+}
+GROUP BY ?year_ ?type
+ORDER BY ?year
diff --git a/scholia/app/templates/wikiproject_recently-published-works.sparql b/scholia/app/templates/wikiproject_recently-published-works.sparql
new file mode 100644
index 000000000..d2120f49c
--- /dev/null
+++ b/scholia/app/templates/wikiproject_recently-published-works.sparql
@@ -0,0 +1,34 @@
+PREFIX target:
+
+SELECT ?date ?work ?workLabel (CONCAT("/work/", SUBSTR(STR(?work), 32)) AS ?workUrl)
+ ?topicsUrl ?topics
+WITH {
+ SELECT DISTINCT ?work WHERE {
+ { ?work wdt:P6104 target: .}
+ union
+ { ?work wdt:P5008 target: .}
+ }
+} AS %works
+WITH {
+ SELECT (MAX(?dates) as ?datetime) ?work (GROUP_CONCAT(DISTINCT ?topic_label; separator=" // ") AS ?topics)
+ (CONCAT("../topics/", GROUP_CONCAT(DISTINCT SUBSTR(STR(?topic), 32); separator=",")) AS ?topicsUrl)
+ WHERE {
+ INCLUDE %works
+ ?work wdt:P921 ?topic .
+ OPTIONAL { ?work wdt:P577 ?dates . }
+ ?topic rdfs:label ?topic_label . FILTER (lang(?topic_label) = 'en')
+ }
+ GROUP BY ?work
+} AS %result
+WHERE {
+ INCLUDE %result
+
+ # There is a problem with BC dates
+ # BIND(xsd:date(?datetime) AS ?date)
+ BIND(REPLACE(STR(?datetime), 'T.*', '') AS ?date)
+
+ SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
+}
+GROUP BY ?date ?work ?workLabel ?topicsUrl ?topics
+ORDER BY DESC(?date)
+LIMIT 500
diff --git a/scholia/app/templates/wikiproject_topics.sparql b/scholia/app/templates/wikiproject_topics.sparql
new file mode 100644
index 000000000..c046db33f
--- /dev/null
+++ b/scholia/app/templates/wikiproject_topics.sparql
@@ -0,0 +1,28 @@
+#defaultView:Table
+
+PREFIX target:
+
+SELECT ?count (CONCAT("/topics/{{ q }},", SUBSTR(STR(?topic), 32)) AS ?countUrl)
+ ?topic ?topicLabel (CONCAT("/topic/", SUBSTR(STR(?topic), 32)) AS ?topicUrl)
+ ?example_work ?example_workLabel (CONCAT("/work/", SUBSTR(STR(?example_work), 32)) AS ?example_workUrl)
+WITH {
+ SELECT (COUNT(?work) AS ?count) ?topic (SAMPLE(?work) AS ?example_work) WHERE {
+ # Find works for the specific queried topic
+ VALUES ?p { wdt:P6104 wdt:P5008 }
+ # Find works for the specific queried topic
+ SERVICE bd:sample { ?work ?p target: . bd:serviceParam bd:sample.limit 10000 }
+
+ # Find co-occuring topics
+ ?work wdt:P921 ?topic .
+
+ # Avoid listing the queried topic
+ FILTER (target: != ?topic)
+ }
+ GROUP BY ?topic
+} AS %result
+WHERE {
+ # Label the results
+ INCLUDE %result
+ SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en" . }
+}
+ORDER BY DESC(?count)
diff --git a/scholia/app/templates/wikiproject_venues.sparql b/scholia/app/templates/wikiproject_venues.sparql
new file mode 100644
index 000000000..5b082cf7e
--- /dev/null
+++ b/scholia/app/templates/wikiproject_venues.sparql
@@ -0,0 +1,21 @@
+#defaultView:Table
+
+PREFIX target:
+
+SELECT ?count ?short_name
+?venue ?venueLabel (CONCAT("/venue/", SUBSTR(STR(?venue), 32)) AS ?venueUrl)
+WITH {
+ SELECT (count(?work) as ?count) ?venue (SAMPLE(?short_name_) AS ?short_name) WHERE {
+ { ?work wdt:P6104 target: . }
+ union { ?work wdt:P5008 target: . }
+ ?work wdt:P1433/wdt:P179* ?venue .
+ OPTIONAL { ?venue wdt:P1813 ?short_name_ . }
+ }
+ GROUP BY ?venue
+} AS %result
+WHERE {
+ INCLUDE %result
+ SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en" . }
+}
+ORDER BY DESC(?count)
+LIMIT 200
diff --git a/scholia/app/views.py b/scholia/app/views.py
index 2915dfda3..6dc099424 100644
--- a/scholia/app/views.py
+++ b/scholia/app/views.py
@@ -2465,6 +2465,24 @@ def show_about():
return render_template('about.html')
+@main.route('/wikiproject/' + q_pattern)
+def show_wikiproject(q):
+ """Return rendered HTML page for specific WikiProject.
+
+ Parameters
+ ----------
+ q : str
+ Wikidata item identifier
+
+ Returns
+ -------
+ html : str
+ Rendered HTML page for specific WikiProject.
+
+ """
+ return render_template('wikiproject.html', q=q)
+
+
@main.route('/favicon.ico')
def show_favicon():
"""Detect and redirect for the favicon.ico."""
diff --git a/scholia/query.py b/scholia/query.py
index 75a84d7fb..20c2e6979 100644
--- a/scholia/query.py
+++ b/scholia/query.py
@@ -267,7 +267,7 @@ def identifier_to_qs(property, identifier):
Notes
-----
- The Wikidata Query Service is queries to resolve the given identifier. If
+ The Wikidata Query Service is queried to resolve the given identifier. If
an error happens an empty list is returned.
Examples
@@ -1271,7 +1271,7 @@ def q_to_class(q):
'Q46855', # hackathon
'Q625994', # conference
'Q2020153', # scientific conference
- 'Q40444998', # akademic workshop
+ 'Q40444998', # academic workshop
]):
class_ = 'event'
elif set(classes).intersection([
@@ -1292,6 +1292,8 @@ def q_to_class(q):
'Q22325163', # macromolecular complex
]):
class_ = 'complex'
+ elif ('Q16695773' in classes): # wikiproject
+ class_ = 'wikiproject'
else:
query = 'select ?class where {{ wd:{q} wdt:P279+ ?class }}'.format(
q=escape_string(q))