Skip to content

Commit 4971524

Browse files
committed
v1.24
+ Now add placeholders in Input Articles table when id was set (e.g. in custom list of IDs or via bookmarklet) but not found via API or an error occurred. + Now truely retrieve All References / All Citations also with Semantic Scholar (S2) by implementing API paging, not just the first 1000 per paper. * Optimized code to use recursive deepFreeze() instead of Object.freeze(), before actually adding article arrays/objects to Vue data tree, vastly increasing performance (especially noticable when All References & All Citations tables contain (tens of) thousands of rows). * Refactored code to improve readability (splitting up the createNewNetwork function in createNewNetwork, retrievedInputArticles, retrievedIncomingSuggestions, retrievedOutgoingSuggestions). * Added a few first end-to-end tests with cypress (more are needed for better maintainability). * Updated examples to also include placeholders.
1 parent eeb1fab commit 4971524

11 files changed

+609
-352
lines changed

CHANGELOG

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
08.06.2024 v1.24
2+
+ Now add placeholders in Input Articles table when id was set (e.g. in custom list of IDs or via bookmarklet) but not found via API or an error occurred.
3+
+ Now truely retrieve All References / All Citations also with Semantic Scholar (S2) by implementing API paging, not just the first 1000 per paper.
4+
* Optimized code to use recursive deepFreeze() instead of Object.freeze(), before actually adding article arrays/objects to Vue data tree, vastly increasing performance (especially noticable when All References & All Citations tables contain (tens of) thousands of rows).
5+
* Refactored code to improve readability (splitting up the createNewNetwork function in createNewNetwork, retrievedInputArticles, retrievedIncomingSuggestions, retrievedOutgoingSuggestions).
6+
* Added a few first end-to-end tests with cypress (more are needed for better maintainability).
7+
* Updated examples to also include placeholders.
8+
19
02.06.2024 v1.23
210
+ Support Semantic Scholar API Keys (may occassionally speed up API, request one here: https://www.semanticscholar.org/product/api#api-key).
311
* Refactored code to make use of Object.freeze() for large arrays containing articles, increasing performance.
@@ -7,7 +15,7 @@
715
01.06.2024 v1.22
816
+ For Input Articles: Added "Filter References" and "Filter Citations" in article details.
917
+ For all articles: Added "Filter Input Articles cited by this" (corresponds to Out-Degree) and "Filter Input Articles citing this" (corresponds to In-Degree).
10-
+ Added "Too Long Didn't Read" (TLDR) summaries for Semantic Scholar (S2).
18+
+ Added "Too Long Didn't Read" (TLDR) summaries for Semantic Scholar (S2) (https://www.semanticscholar.org/faq#tldr).
1119
* Use batch API for Semantic Scholar (S2), which allows much faster retrievals and much fewer API-overloads (error 429). (Unfortunately seems to have a bug, compare below "Known bugs")
1220
* In case "All references" or "All citations" are retrieved (OA & S2 only): don't de-duplicate them anymore so that numbers in the respective tabs are correct, also when filtering them.
1321
* Let users choose number of articles per page.

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Local-Citation-Network
22

3-
This web app aims to help scientists with their literature review using metadata from [OpenAlex](https://openalex.org/) (OA), [Semantic Scholar](https://semanticscholar.org/) (S2) and [Crossref](https://crossref.org/) (CR). Academic papers cite one another, thus creating a [citation network (= graph)](https://en.wikipedia.org/wiki/Citation_graph). Each node (= vertex) represents an article and each edge (= link / arrow) represents a reference / citation. Citation graphs are a topic of [bibliometrics, for which other great software exists as well](https://timwoelfle.github.io/Local-Citation-Network#bibliometrics).
3+
This web app aims to help scientists with their literature review using metadata from [OpenAlex](https://openalex.org/) (OA), [Semantic Scholar](https://semanticscholar.org/) (S2) and [Crossref](https://crossref.org/) (CR). Academic papers cite one another, thus creating a [citation network (= graph)](https://en.wikipedia.org/wiki/Citation_graph). Each node (= vertex) represents an article and each edge (= link / arrow) represents a reference / citation. Citation graphs are a topic of [bibliometrics, for which other great software exists as well](https://localcitationnetwork.github.io/#bibliometrics).
44

55
This web app visualizes subsets of the global citation network that I call 'local citation networks', defined by the references (and citations) of a given set of input articles. In addition, the locally most relevant references (and citations) missing in the set of input articles are suggested for further review.
66

cypress.config.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const { defineConfig } = require("cypress");
2+
3+
module.exports = defineConfig({
4+
e2e: {
5+
setupNodeEvents(on, config) {
6+
// implement node event listeners here
7+
},
8+
},
9+
});

cypress/e2e/check-examples.cy.js

+54
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
describe('Load examples from scratch', () => {
2+
it('Load example from scratch: Amazon deforestation (S2)', () => {
3+
cy.visit('./index.html?API=Semantic%20Scholar&source=10.1038/S41558-022-01287-8&listOfIds=10.1073/PNAS.0705414105,10.1146/ANNUREV.ENERGY.28.050302.105532,10.1126/SCIENCE.1146961,10.1038/S41586-021-03629-6,10.1038/NATURE14283,10.1002/2015GB005133,10.1038/S41586-020-2035-0,10.1038/SREP41489,10.1038/35041539,10.1038/NATURE06960,10.1126/SCIADV.AAT2340,10.1126/SCIADV.ABA2949,10.1073/PNAS.1305499111,10.1111/J.1461-0248.2010.01497.X,10.1029/WR015I005P01250,10.1038/NGEO555,10.1111/GCB.13733,10.1038/NGEO1741,10.1016/S0304-3800(96)00034-8,10.1111/J.1365-2486.2009.02157.X,10.1111/J.1365-2486.2008.01626.X,10.1007/BF00384470,10.1038/NATURE08227,10.1038/307321A0,10.1073/PNAS.0802430105,10.1029/2004GL020972,10.1007/S12080-013-0191-7,10.1038/NCLIMATE1143,10.1073/PNAS.0811729106,10.1073/PNAS.2024192118,10.1038/S41558-021-01097-4,10.1038/NCLIMATE3108,10.5194/ESSD-12-177-2020,10.7289/V5ZG6QH9,10.1038/NCLIMATE2581,10.1038/386698A0,10.5067/MODIS/MCD12C1.006,10.1016/J.RSE.2016.02.056,10.1073/PNAS.1617988114,10.1038/SDATA.2015.66,10.1038/NCOMMS15519,10.1073/PNAS.1302584110,10.3389/FEART.2018.00228,10.1029/2018JD029537,10.1002/JOC.6335,10.1126/SCIENCE.1200807,10.1038/S41598-017-05373-2,10.1088/1748-9326/AB9CFF,10.1029/2002JD002670,10.1111/GCB.14413,585bf445ec84c1d9621b2726bdcce9f544b515c8,10.1175/JCLI-D-15-0828.1,10.1038/S41467-018-04881-7,10.1126/SCIENCE.1244693,10.1890/11-0889.1,10.3334/ORNLDAAC/1284,10.5281/ZENODO.5837469&bookmarkletURL=https://www.nature.com/articles/d41586-019-00857-9')
4+
5+
cy.get('button').contains('Import').click()
6+
7+
cy.window().its('app.__vue__').should(($vue) => {
8+
expect($vue.isLoading).to.be.true;
9+
})
10+
11+
cy.waitUntil(() => cy.window().then(win => win.app.__vue__.isLoading === false), {
12+
timeout: 30000,
13+
interval: 5000
14+
})
15+
16+
cy.get('#app').should(($app) => {
17+
expect($app[0].__vue__.currentGraph.input.length).to.equal(58);
18+
})
19+
20+
cy.waitUntil(() => cy.window().then(win => win.app.__vue__.currentGraph.incomingSuggestions !== undefined), {
21+
timeout: 30000,
22+
interval: 5000
23+
})
24+
25+
cy.get('#app').should(($app) => {
26+
expect($app[0].__vue__.currentGraph.incomingSuggestions.length).to.equal(10);
27+
})
28+
29+
cy.waitUntil(() => cy.window().then(win => win.app.__vue__.currentGraph.outgoingSuggestions !== undefined), {
30+
timeout: 30000,
31+
interval: 5000
32+
})
33+
34+
cy.get('#app').should(($app) => {
35+
expect($app[0].__vue__.currentGraph.outgoingSuggestions.length).to.equal(10);
36+
})
37+
})
38+
39+
it('Load example from scratch: Medicine meta-research (OA)', () => {
40+
cy.visit('./index.html?API=OpenAlex&source=10.1371/JOURNAL.PMED.0020124&listOfIds=pmid:11302887,pmid:15158637,pmid:15158638,pmid:15705458,pmid:11600885,pmid:12642066,pmid:12727138,pmid:15705441,pmid:11159626,pmid:15026468,pmid:10866211,ISBN-13-978-0195083774,pmid:15470193,pmid:6528136,pmid:10694730,pmid:7618077,pmid:10521349,pmid:11323066,pmid:15545678,pmid:10532877,pmid:10584742,pmid:10789670,pmid:10755072,pmid:8015123,pmid:15161896,pmid:9693346,pmid:11405896,pmid:1535110,pmid:15878467,pmid:14602436,pmid:15057290,10.1093/BIOMET/44.1-2.187,10.1093/BIOMET/44.3-4.533,pmid:11434499,10.1056/NEJME048225,pmid:16014596,pmid:14584715&bookmarkletURL=https://pubmed.ncbi.nlm.nih.gov/16060722/')
41+
42+
cy.get('button').contains('Import').click()
43+
44+
cy.window().its('app.__vue__').should(($vue) => {
45+
expect($vue.isLoading).to.be.true;
46+
})
47+
48+
cy.waitUntil(() => cy.window().then(win => win.app.__vue__.isLoading === false), {
49+
timeout: 30000,
50+
interval: 5000
51+
})
52+
53+
cy.get('#app').should(($app) => {
54+
expect($app[0].__vue__.currentGraph.input.length).to.equal(38);
55+
})
56+
57+
cy.waitUntil(() => cy.window().then(win => win.app.__vue__.currentGraph.incomingSuggestions !== undefined), {
58+
timeout: 30000,
59+
interval: 5000
60+
})
61+
62+
cy.get('#app').should(($app) => {
63+
expect($app[0].__vue__.currentGraph.incomingSuggestions.length).to.equal(10);
64+
})
65+
66+
cy.waitUntil(() => cy.window().then(win => win.app.__vue__.currentGraph.outgoingSuggestions !== undefined), {
67+
timeout: 30000,
68+
interval: 5000
69+
})
70+
71+
cy.get('#app').should(($app) => {
72+
expect($app[0].__vue__.currentGraph.outgoingSuggestions.length).to.equal(10);
73+
})
74+
})
75+
76+
it('Load example from scratch: Statistics (OC)', () => {
77+
cy.visit('./index.html?API=OpenCitations&source=10.1038/D41586-019-00857-9&listOfIds=10.1038/136474B0,10.1016/J.IJCARD.2014.09.205,10.1080/00031305.2019.1583913,10.1080/00031305.2018.1543616,10.1007/0-387-27605-X,10.1177/2515245918771329,10.1093/AJE/KWX259,10.1080/00031305.2018.1527253,10.1511/2014.111.460,10.1080/00031305.2018.1543137&bookmarkletURL=https://www.nature.com/articles/d41586-019-00857-9')
78+
79+
cy.get('button').contains('Import').click()
80+
81+
cy.window().its('app.__vue__').should(($vue) => {
82+
expect($vue.isLoading).to.be.true;
83+
})
84+
85+
cy.waitUntil(() => cy.window().then(win => win.app.__vue__.isLoading === false), {
86+
timeout: 30000,
87+
interval: 5000
88+
})
89+
90+
cy.get('#app').should(($app) => {
91+
expect($app[0].__vue__.currentGraph.input.length).to.equal(11);
92+
})
93+
94+
cy.waitUntil(() => cy.window().then(win => win.app.__vue__.currentGraph.incomingSuggestions !== undefined), {
95+
timeout: 30000,
96+
interval: 5000
97+
})
98+
99+
cy.get('#app').should(($app) => {
100+
expect($app[0].__vue__.currentGraph.incomingSuggestions.length).to.equal(10);
101+
})
102+
103+
cy.waitUntil(() => cy.window().then(win => win.app.__vue__.currentGraph.outgoingSuggestions !== undefined), {
104+
timeout: 30000,
105+
interval: 5000
106+
})
107+
108+
cy.get('#app').should(($app) => {
109+
expect($app[0].__vue__.currentGraph.outgoingSuggestions.length).to.equal(10);
110+
})
111+
})
112+
})

cypress/fixtures/example.json

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "Using fixtures to represent data",
3+
"email": "[email protected]",
4+
"body": "Fixtures are a great way to mock data for responses to routes"
5+
}

cypress/support/commands.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// ***********************************************
2+
// This example commands.js shows you how to
3+
// create various custom commands and overwrite
4+
// existing commands.
5+
//
6+
// For more comprehensive examples of custom
7+
// commands please read more here:
8+
// https://on.cypress.io/custom-commands
9+
// ***********************************************
10+
//
11+
//
12+
// -- This is a parent command --
13+
// Cypress.Commands.add('login', (email, password) => { ... })
14+
//
15+
//
16+
// -- This is a child command --
17+
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
18+
//
19+
//
20+
// -- This is a dual command --
21+
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
22+
//
23+
//
24+
// -- This will overwrite an existing command --
25+
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
26+
27+
import 'cypress-wait-until';

cypress/support/e2e.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// ***********************************************************
2+
// This example support/e2e.js is processed and
3+
// loaded automatically before your test files.
4+
//
5+
// This is a great place to put global configuration and
6+
// behavior that modifies Cypress.
7+
//
8+
// You can change the location of this file or turn off
9+
// automatically serving support files with the
10+
// 'supportFile' configuration option.
11+
//
12+
// You can read more here:
13+
// https://on.cypress.io/configuration
14+
// ***********************************************************
15+
16+
// Import commands.js using ES2015 syntax:
17+
import './commands'
18+
19+
// Alternatively you can use CommonJS syntax:
20+
// require('./commands')

examples.json

+1-1
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)