Skip to content

Commit 13d9963

Browse files
committed
Merge branch 'master' into cita
2 parents e2ebded + 79e88e3 commit 13d9963

3 files changed

Lines changed: 36 additions & 31 deletions

File tree

CHANGELOG

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
02.02.2025 v1.28
2+
* Some adaptations for better integration with the awesome Zotero Cita plugin: https://github.com/diegodlh/zotero-cita.
3+
* Slightly changed linkToShareAppendix() logic.
4+
* Added downloadFile function.
5+
! Fixed physics of Co-authorship network by reverting to default barnesHut configuration.
6+
! Fix title of edges in Co-authorship network (only considers seed articles as of 1.21).
7+
! Fixed some old terminology in comments.
8+
19
11.11.2024 v1.27
210
+ Export options modal for CSV / RIS download.
311
* De-duplication of All Cited and All Citing is off again by default but can be turned on.

index.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ <h1 class="title">{{ (currentGraph?.API === 'Co*Citation Network via OpenAlex' |
163163
<ul class="buttons">
164164
<b-navbar-item tag="li" v-for="item, index in graphs" :key="index" class="navbar-item">
165165
<b-button :type="(index==currentTabIndex) ? 'is-primary' : ''" :title="item.tabTitle" @click="setCurrentTabIndex(index)" rounded>
166-
{{ item.tabLabel }} ({{ abbreviateAPI(item.API) }})
166+
{{ item.tabLabel + ((abbreviateAPI(item.API)) ? ' (' + abbreviateAPI(item.API) + ')' : '') }}
167167
<a title="Close tab" class="delete" @click.stop="clickCloseTab(index)"></a> <!-- .stop prevents event propagation to parent @click event -->
168168
</b-button>
169169
</b-navbar-item>
@@ -913,7 +913,7 @@ <h3 class="modal-card-title">Co-authorship network settings</h3>
913913
<header class="modal-card-head">
914914
<content>
915915
<h3 class="modal-card-title">Import custom list of IDs</h3>
916-
<p>One ID per row. Use OpenAlex / Semantic Scholar for PMIDs. Empty rows are placeholders in order to help preserve original numbering.</p>
916+
<p>One ID per row, usually DOI. Use OpenAlex / Semantic Scholar for PMIDs. Empty rows are placeholders in order to help preserve original numbering.</p>
917917
</content>
918918
</header>
919919
<section style="position: relative; height:300px">
@@ -938,7 +938,7 @@ <h3 class="modal-card-title">API options</h3>
938938
</header>
939939
<div class="card-content">
940940
<p class="content">
941-
Cited Articles (References) can be retrieved through all <a @click="indexFAQ = 'switch-api'; showFAQ = true;" href="#switch-api">APIs</a>. Citing Articles (Citations) can be retrieved through OpenAlex (OA), Semantic Scholar (S2) and OpenCitations (OC). <a @click="indexFAQ = 'top-cited'; showFAQ = true;" href="#top-cited">Top Cited</a> are the most cited references by the Seed Articles. <a @click="indexFAQ = 'top-citing'; showFAQ = true;" href="#top-citing">Top Citing</a> are citing the most Seed Articles. Retrieving All References / Citations works best with OpenAlex (OA) & Semantic Scholar (S2).
941+
Cited Articles (References) can be retrieved through all <a @click="indexFAQ = 'switch-api'; showFAQ = true;" href="#switch-api">APIs</a>. Citing Articles (Citations) can be retrieved through OpenAlex (OA), Semantic Scholar (S2) and OpenCitations (OC). <a @click="indexFAQ = 'top-cited'; showFAQ = true;" href="#top-cited">Top Cited</a> are the most cited references by the Seed Articles. <a @click="indexFAQ = 'top-citing'; showFAQ = true;" href="#top-citing">Top Citing</a> are citing the most Seed Articles. Retrieving All Cited (i.e. references) / All Citing (i.e. citations) works best with OpenAlex (OA) & Semantic Scholar (S2).
942942
</p>
943943
<b-field grouped>
944944
<b-field label="Select API">

index.js

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
'use strict'
1212

13-
const localCitationNetworkVersion = 1.27
13+
const localCitationNetworkVersion = 1.28
1414

1515
const arrSum = arr => arr.reduce((a, b) => a + b, 0)
1616
const arrAvg = arr => arrSum(arr) / arr.length
@@ -108,7 +108,7 @@ async function semanticScholarWrapper (ids, responseFunction, phase, retrieveCit
108108
offset = response.next
109109
response = response.data.map(x => x.citedPaper || x.citingPaper) // citedPaper for references, citingPaper for citations
110110
// Semantic Scholar doesn't provide references & citations lists for citations & references endpoint
111-
// That's why for S2: All Citations always only have one reference and All References only have one citation (the one that called them), which are merged in responseToArray during de-duplication
111+
// That's why for S2: All Citing (i.e. citations) always only have one reference and All Cited (i.e. references) only have one citation (the one that called them), which are merged in responseToArray during de-duplication
112112
// response can be null in case of placeholders in id-list
113113
if (phase === 'citations' && response) {
114114
response = response.map(x => { x.references = [{ paperId: id }]; return x })
@@ -120,8 +120,8 @@ async function semanticScholarWrapper (ids, responseFunction, phase, retrieveCit
120120
responses = responses.concat(response)
121121
}
122122
}
123-
// For phase 'input' and Top Citations (i.e. retrieveCitingArticles > 0 but not retrieveAllCiting) load seed articles one by one in order to retrieve proper citations fields to calculate top citations ids
124-
// With batch endpoint (below), there is a maximum of 9999 citations in total, which leads to incorrect Top Citations (compare https://github.com/allenai/s2-folks/issues/199)
123+
// For phase 'input' and Top Citing (i.e. retrieveCitingArticles > 0 but not retrieveAllCiting) load seed articles one by one in order to retrieve proper citations fields to calculate Top Citing ids
124+
// With batch endpoint (below), there is a maximum of 9999 citations in total, which leads to incorrect Top Citing (compare https://github.com/allenai/s2-folks/issues/199)
125125
// However, single API calls are currently always blocked by 429 responses, even with 15s waits, which is why this part is commented out
126126
/* } else if (phase === 'input' && retrievetopCiting) {
127127
let response
@@ -141,12 +141,12 @@ async function semanticScholarWrapper (ids, responseFunction, phase, retrieveCit
141141
responses = responses.concat(response)
142142
}
143143
vm.isLoadingTotal = 0 */
144-
// Phase 'source' / 'input' && retrieveAllCiting / 'references' && !retrieveAllCited (i.e. Top references only) / 'citations' && !retrieveAllCiting (i.e. Top Citations only)
144+
// Phase 'source' / 'input' && retrieveAllCiting / 'references' && !retrieveAllCited (i.e. Top Cited only) / 'citations' && !retrieveAllCiting (i.e. Top Citing only)
145145
// Use batch endpoint (https://api.semanticscholar.org/api-docs/graph#tag/Paper-Data/operation/post_graph_get_papers)
146146
} else {
147147
// These fields cannot be retrieved on references / citations endpoints
148148
selectFields += ',authors.externalIds,authors.name,authors.affiliations,references.paperId,tldr'
149-
// Get citations ids for seed articles for Top Citations
149+
// Get citations ids for seed articles for Top Citing
150150
if (['source', 'input'].includes(phase) && retrievetopCiting) selectFields += ',citations.paperId'
151151

152152
// Batch endpoint allows max. 500 ids and 9999 citations at the same time
@@ -267,7 +267,7 @@ async function openAlexWrapper (ids, responseFunction, phase, retrieveCitedArtic
267267
if (response.results?.length) responses = responses.concat(response.results)
268268
}
269269
}
270-
// Phase 'source' / 'input' / 'references' && !retrieveAllCited (i.e. Top references only) / 'citations' && !retrieveAllCiting (i.e. Top Citations only)
270+
// Phase 'source' / 'input' / 'references' && !retrieveAllCited (i.e. Top Cited only) / 'citations' && !retrieveAllCiting (i.e. Top Citing only)
271271
} else {
272272
vm.isLoadingTotal = ids.length
273273
for (const i of Array(ids.length).keys()) {
@@ -276,7 +276,7 @@ async function openAlexWrapper (ids, responseFunction, phase, retrieveCitedArtic
276276
vm.isLoadingIndex = i
277277
if (id) {
278278
response = await openAlexWorks('/' + id.replace('openalex:', '') + '?select=' + selectFields)
279-
// Get citations ids for seed articles (if not all citations are retrieved anyway)
279+
// Get citations ids for seed articles (if not All Citing (i.e. citations) are retrieved anyway)
280280
if (['source', 'input'].includes(phase) && response.id && !retrieveAllCiting) {
281281
// Careful: Citation results are incomplete when a paper is cited by >200 (current per-page upper-limit of OA), use "API options => Retrieve citations => All" for completeness
282282
const citations = await openAlexWorks('?select=id&per-page=200&sort=referenced_works_count:desc&filter=cites:' + response.id.replace('https://openalex.org/', ''))
@@ -909,10 +909,7 @@ function initAuthorNetwork (app, minPublications = undefined) {
909909
smooth: false
910910
},
911911
physics: {
912-
barnesHut: {
913-
centralGravity: 10
914-
},
915-
maxVelocity: 20
912+
solver: 'barnesHut'
916913
},
917914
interaction: {
918915
multiselect: true,
@@ -1516,7 +1513,7 @@ const vm = new Vue({
15161513
if (source.id) seedArticles = seedArticles.concat(source)
15171514
const seedArticlesIds = seedArticles.map(article => article.id)
15181515

1519-
// Temporary scope variables needed (without having been reduced like in computed.referencedCiting!) for getting id lists for Top References / Top Citations
1516+
// Temporary scope variables needed (without having been reduced like in computed.referencedCiting!) for getting id lists for Top Cited / Top Citing
15201517
let referenced, citing
15211518
if (!(retrieveCitedArticles === Infinity && ['OpenAlex', 'Semantic Scholar'].includes(API))) {
15221519
referenced = this.computeSeedArticlesRelationships(seedArticles, seedArticlesIds).seedArticlesA
@@ -1525,7 +1522,7 @@ const vm = new Vue({
15251522
citing = this.computeSeedArticlesRelationships(seedArticles, seedArticlesIds, 'citations').seedArticlesA
15261523
}
15271524

1528-
// Delete citations arrays in articles to save space, they were only needed for calculating citing (above) for "Top citations"
1525+
// Delete citations arrays in articles to save space, they were only needed for calculating citing (above) for "Top Citing"
15291526
seedArticles = seedArticles.map(article => { delete article.citations; return article })
15301527

15311528
// Add new tab
@@ -1549,15 +1546,15 @@ const vm = new Vue({
15491546
this.listName = undefined
15501547
this.bookmarkletURL = undefined
15511548

1552-
/* Perform API call for All / Top References (formerly References / Incoming suggestions) */
1553-
// OA & S2: If all references are supposed to be retrieved get multiple references at once based on seedArticlesIds (faster)
1549+
/* Perform API call for All / Top Cited (formerly References / Incoming suggestions) */
1550+
// OA & S2: If All Cited (i.e. references) are supposed to be retrieved get multiple references at once based on seedArticlesIds (faster)
15541551
// Otherwise use ids derived from references
15551552
let citedArticlesIds
15561553
if (!(retrieveCitedArticles === Infinity && ['OpenAlex', 'Semantic Scholar'].includes(API))) {
15571554
citedArticlesIds = Object.keys(referenced)
1558-
// De-duplicate vs seedArticles in case only Top References are retrieved
1555+
// De-duplicate vs seedArticles in case only Top Cited are retrieved
15591556
.filter(x => !seedArticlesIds.includes(x))
1560-
// Sort and slice for Top References
1557+
// Sort and slice for Top Cited
15611558
.sort((a, b) => referenced[b].length - referenced[a].length).slice(0, retrieveCitedArticles)
15621559
}
15631560
// Zotero Cita shows All Cited (i.e. all references) => do not de-duplicate against seedArticles like above
@@ -1578,17 +1575,17 @@ const vm = new Vue({
15781575
this.saveState()
15791576
if (this.currentGraph === newGraph) this.init()
15801577

1581-
/* Perform API call for All / Top Citations (formerly Citations / Outgoing suggestions) */
1578+
/* Perform API call for All / Top Citing (formerly Citations / Outgoing suggestions) */
15821579
// Only works with OpenAlex, Semantic Scholar and OpenCitations
1583-
// OA & S2: If all citations are supposed to be retrieved get multiple citations at once based on seedArticlesIds (faster)
1580+
// OA & S2: If All Citing (i.e. citations) are supposed to be retrieved get multiple citations at once based on seedArticlesIds (faster)
15841581
// Otherwise use ids derived from citations
15851582
if (this.retrieveCitingArticles && ['OpenAlex', 'Semantic Scholar', 'OpenCitations'].includes(API)) {
15861583
let citingArticlesIds
15871584
if (!(retrieveCitingArticles === Infinity && ['OpenAlex', 'Semantic Scholar'].includes(API))) {
15881585
citingArticlesIds = Object.keys(citing)
1589-
// De-duplicate vs seedArticles & citedArticles in case only Top Citations are retrieved
1586+
// De-duplicate vs seedArticles & citedArticles in case only Top Citing are retrieved
15901587
.filter(x => !seedArticlesIds.includes(x) && !citedArticles.map(x => x.id).includes(x))
1591-
// Sort and slice for Top Citations
1588+
// Sort and slice for Top Citing
15921589
.sort((a, b) => citing[b].length - citing[a].length).slice(0, retrieveCitingArticles)
15931590
}
15941591
this.callAPI((retrieveCitingArticles === Infinity && ['OpenAlex', 'Semantic Scholar'].includes(API)) ? seedArticlesIds : citingArticlesIds, data => this.retrievedCitingArticles(data, API, newGraph), API, 'citations', 0, retrieveCitingArticles)
@@ -1870,19 +1867,19 @@ const vm = new Vue({
18701867
const articlesIds = data.map(article => article.id)
18711868
articles = data.map(article => { if (article.numberInSourceReferences === undefined) article.numberInSourceReferences = articlesIds.indexOf(article.id)+1; return article; })
18721869
}
1873-
// Remove duplicates - important for de-duplication of All References / All Citations (in the sense of proper duplicates within one category (not in the sense of "de-duplicated against Seed Articles and Cited"), can be duplicated mostly with S2 but also to lesser extent with OA), rarely also needed for other calls, e.g. for S2 in references of 10.1111/J.1461-0248.2009.01285.X, eebf363bc78ca7bc16a32fa339004d0ad43aa618 came up twice
1870+
// Remove duplicates - important for de-duplication of All Cited (i.e. references) / All Citing (i.e. citations) (in the sense of proper duplicates within one category (not in the sense of "de-duplicated against Seed Articles and Cited"), can be duplicated mostly with S2 but also to lesser extent with OA), rarely also needed for other calls, e.g. for S2 in references of 10.1111/J.1461-0248.2009.01285.X, eebf363bc78ca7bc16a32fa339004d0ad43aa618 came up twice
18741871
articles = articles.reduce((articlesKeep, article) => {
18751872
const articlesKeepIds = articlesKeep.map(x => x.id)
18761873
// Keep placeholders (id undefined) and non-duplicates
18771874
if (article.id === undefined || !articlesKeepIds.includes(article.id)) {
18781875
articlesKeep.push(article)
18791876
} else {
1880-
// S2: All References and All Citations always only have one reference (the one that called them) - merge them on de-duplication
1877+
// S2: All Cited (i.e. references) and All Citing (i.e. citations) always only have one reference (the one that called them) - merge them on de-duplication
18811878
if (article.references?.length === 1) {
1882-
// This should only occur for All Citations for S2
1879+
// This should only occur for All Citing (i.e. citations) for S2
18831880
if (!articlesKeep[articlesKeepIds.indexOf(article.id)].references.includes(article.references[0])) articlesKeep[articlesKeepIds.indexOf(article.id)].references.push(article.references[0])
18841881
} else if (article.citations?.length === 1) {
1885-
// This should only occur for All References for S2
1882+
// This should only occur for All Cited (i.e. references) for S2
18861883
if (!articlesKeep[articlesKeepIds.indexOf(article.id)].citations.includes(article.citations[0])) articlesKeep[articlesKeepIds.indexOf(article.id)].citations.push(article.citations[0])
18871884
}
18881885
}
@@ -1907,7 +1904,7 @@ const vm = new Vue({
19071904
if (saveGraphs) {
19081905
const copiedGraphs = JSON.parse(JSON.stringify(this.graphs))
19091906
localStorage.graphs = JSON.stringify(copiedGraphs.map(graph => {
1910-
// Delete these two possibly existing flags so that only "Top References" / "Top Citations" instead of "All references" / "All citations" will be shown
1907+
// Delete these two possibly existing flags so that only "Top Cited" / "Top Citing" instead of "All Cited" (i.e. references) / "All Citing" (i.e. citations) will be shown
19111908
if (graph.citedArticles === undefined || graph.citedArticles.length > maxCitedCiting) delete graph.allCited
19121909
if (graph.citingArticles === undefined || graph.citingArticles.length > maxCitedCiting) delete graph.allCiting
19131910
// Don't save suggestions still in loading phase
@@ -1994,7 +1991,7 @@ const vm = new Vue({
19941991
// Prior to v1.23 referenced and citing were cached in the graph object
19951992
delete graph.referenced
19961993
delete graph.citing
1997-
// Prior to v1.26 seedArticles array was called input, citedArticles array was called citedArticles, and citingArticles array was called citingArticles
1994+
// Prior to v1.26 seedArticles array was called input, citedArticles array was called incomingSuggestions, and citingArticles array was called outgoingSuggestions
19981995
if (!graph.seedArticles) {
19991996
graph.seedArticles = graph.input
20001997
graph.citedArticles = graph.incomingSuggestions

0 commit comments

Comments
 (0)