From de1f6102ba78905124da222868a1cf638cf340ca Mon Sep 17 00:00:00 2001 From: Abigail Dawson Date: Wed, 24 Apr 2024 19:33:43 -0400 Subject: [PATCH 1/6] Create card to display additional node attributes --- observable/docs/index.md | 52 +++++++++++++++++++++++++++---- observable/docs/styles.css | 37 ++++++++++++++++++++++ observable/observablehq.config.js | 2 +- 3 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 observable/docs/styles.css diff --git a/observable/docs/index.md b/observable/docs/index.md index 4417da3..2c43ba3 100644 --- a/observable/docs/index.md +++ b/observable/docs/index.md @@ -1,19 +1,19 @@ --- tilte: CollabNext Challenge +style: ./styles.css + --- # CollabNext Challenge Exercitation ut mollit fugiat sunt. Lorem deserunt consequat voluptate consectetur reprehenderit qui. Sit exercitation commodo non esse aliqua commodo enim aliquip est dolore sit laboris occaecat tempor. Culpa commodo ad magna dolore veniam commodo est eiusmod qui eu dolore nisi pariatur eiusmod. Est mollit esse pariatur nisi eu sunt fugiat culpa. Veniam excepteur amet duis veniam officia elit cillum sunt. -## Search for anything +Search ```js const query = view(Inputs.text()); ``` -### Your Peer Network - ```js import { SQLiteDatabaseClient } from "npm:@observablehq/sqlite"; const db = FileAttachment("data/graph.sqlite").sqlite(); @@ -55,7 +55,9 @@ const orb = new Orb.Orb(container); orb.view.setSettings({ render: { - backgroundColor: "#DDDDDD", + backgroundColor: "#f4faff", + padding: "0", + margin: "0", }, }); @@ -125,18 +127,56 @@ orb.data.setup({ nodes, edges }); // Render and recenter the view orb.view.render(() => { orb.view.recenter(); + console.log(nodes.filter(node => node.type === 'INSTITUTION')); }); ``` ```js +let selectedNode; + orb.events.on('node-click', (event) => { getData(event) }); function getData(event) { - console.log('Node clicked: ', event.node); + selectedNode = event.node.data; + updateDetails(selectedNode) +} + +const details = document.querySelector('.details') + +function updateDetails(selectedNode) { + details.innerHTML = ''; + + let html = ''; + + if (selectedNode) { + html += `

${selectedNode.label}

`; + + if (selectedNode.type === 'INSTITUTION') { + html += `

Institution type: ${selectedNode.type}

`; + html += `

Homepage: ${selectedNode.homepage}

`; + html += `

Works: ${selectedNode.works_count}

`; + html += `

Cited by: ${selectedNode.cited_by_count}

`; + } else if (selectedNode.type === 'AUTHOR') { + html += `

Works: ${selectedNode.works_count}

`; + html += `

Cited by: ${selectedNode.cited_by_count}

`; + } else if (selectedNode.type === 'TOPIC') { + html += `

Description: ${selectedNode.description}

`; + html += `

Subfield: ${selectedNode.subfield}

`; + html += `

Domain: ${selectedNode.domain}

`; + } + } + + // Set the generated HTML content to the details element + details.innerHTML = html; } ``` -
+
+
+
+

Click on any node to see more details.

+
+
diff --git a/observable/docs/styles.css b/observable/docs/styles.css new file mode 100644 index 0000000..93e95a4 --- /dev/null +++ b/observable/docs/styles.css @@ -0,0 +1,37 @@ +* { + box-sizing: border-box; + padding: 0; + margin: 0; +} + +body { + font-family: 'Open Sans', sans-serif; + font-size: 16px; + line-height: 1.5; + color: #333; + background-color: #f4faff; + margin: 2vmin; + padding: 2vmin; +} + +a { + color: #244e7b; + text-decoration: none; +} + +.content { + position: relative; + padding: 1vmin; + margin: 2vmin; +} + +.details { + position: absolute; + top: 2vmin; + left: 2vmin; + width: 33%; + padding: 2vmin; + border-radius: 1vmin; + box-shadow: 5px 5px 8px 0px rgba(0,0,0,0.25); + background-color: #fff; +} \ No newline at end of file diff --git a/observable/observablehq.config.js b/observable/observablehq.config.js index 42f5ad7..a62acce 100644 --- a/observable/observablehq.config.js +++ b/observable/observablehq.config.js @@ -18,7 +18,7 @@ export default { // ], // Some additional configuration options and their defaults: - // theme: "default", // try "light", "dark", "slate", etc. + theme: "glacier", // try "light", "dark", "slate", etc. // header: "", // what to show in the header (HTML) // footer: "Built with Observable.", // what to show in the footer (HTML) toc: false, // whether to show the table of contents From 1fae275ce34b51ba068dd981eb770805223f322b Mon Sep 17 00:00:00 2001 From: Abigail Dawson Date: Wed, 24 Apr 2024 19:36:57 -0400 Subject: [PATCH 2/6] Add loader to display while graph is loading --- observable/docs/index.md | 10 +++++++++- observable/docs/styles.css | 28 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/observable/docs/index.md b/observable/docs/index.md index 2c43ba3..5518e0b 100644 --- a/observable/docs/index.md +++ b/observable/docs/index.md @@ -120,14 +120,19 @@ orb.data.setDefaultStyle({ }, }); +const loaderOverlay = document.getElementById('loader-overlay'); +const graphContainer = document.getElementById('graph'); + +// Show loader overlay +loaderOverlay.style.display = 'flex'; // Initialize nodes and edges orb.data.setup({ nodes, edges }); // Render and recenter the view orb.view.render(() => { + loaderOverlay.style.display = 'none'; orb.view.recenter(); - console.log(nodes.filter(node => node.type === 'INSTITUTION')); }); ``` @@ -175,6 +180,9 @@ function updateDetails(selectedNode) { ```
+
+
+

Click on any node to see more details.

diff --git a/observable/docs/styles.css b/observable/docs/styles.css index 93e95a4..96a00fb 100644 --- a/observable/docs/styles.css +++ b/observable/docs/styles.css @@ -34,4 +34,32 @@ a { border-radius: 1vmin; box-shadow: 5px 5px 8px 0px rgba(0,0,0,0.25); background-color: #fff; +} + +/* LOADER */ +.loader-overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(255, 255, 255, 0.8); + display: flex; + justify-content: center; + align-items: center; + z-index: 1000; +} + +.loader { + border: 4px solid #f3f3f3; + border-top: 4px solid #08a9c6; + border-radius: 50%; + width: 50px; + height: 50px; + animation: spin 1s linear infinite; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } } \ No newline at end of file From dee89b1e14b0f59bff7db3d1f6b81b1b55b680ba Mon Sep 17 00:00:00 2001 From: Abigail Dawson Date: Wed, 24 Apr 2024 20:12:40 -0400 Subject: [PATCH 3/6] Try to fix issue with accessing topic description --- collabnext/openalex/nodes.py | 2 +- observable/docs/index.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/collabnext/openalex/nodes.py b/collabnext/openalex/nodes.py index cb6ffc0..0a25726 100644 --- a/collabnext/openalex/nodes.py +++ b/collabnext/openalex/nodes.py @@ -71,7 +71,7 @@ def make_topic_nodes(topics: list[Topic]) -> list[dict]: "works_count": None, "cited_by_count": None, "field": x["field"]["display_name"], - "description": x.get("description"), + "description": x["description"], "subfield": x["subfield"]["display_name"], "domain": x["domain"]["display_name"], "label": x["field"]["display_name"], diff --git a/observable/docs/index.md b/observable/docs/index.md index 5518e0b..1c9f59d 100644 --- a/observable/docs/index.md +++ b/observable/docs/index.md @@ -146,6 +146,7 @@ orb.events.on('node-click', (event) => { function getData(event) { selectedNode = event.node.data; + console.log(selectedNode) updateDetails(selectedNode) } @@ -169,6 +170,7 @@ function updateDetails(selectedNode) { html += `

Cited by: ${selectedNode.cited_by_count}

`; } else if (selectedNode.type === 'TOPIC') { html += `

Description: ${selectedNode.description}

`; + html += `

Field: ${selectedNode.field}

`; html += `

Subfield: ${selectedNode.subfield}

`; html += `

Domain: ${selectedNode.domain}

`; } From f1f0e6f3d80e01d81d6eefd3d129e480d3831253 Mon Sep 17 00:00:00 2001 From: Abigail Dawson Date: Thu, 25 Apr 2024 20:09:12 -0400 Subject: [PATCH 4/6] Fix error caused by description attribute in make_topic_nodes --- collabnext/openalex/nodes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collabnext/openalex/nodes.py b/collabnext/openalex/nodes.py index 0a25726..cb6ffc0 100644 --- a/collabnext/openalex/nodes.py +++ b/collabnext/openalex/nodes.py @@ -71,7 +71,7 @@ def make_topic_nodes(topics: list[Topic]) -> list[dict]: "works_count": None, "cited_by_count": None, "field": x["field"]["display_name"], - "description": x["description"], + "description": x.get("description"), "subfield": x["subfield"]["display_name"], "domain": x["domain"]["display_name"], "label": x["field"]["display_name"], From dfde1c6fcd42b17c91fbd56fb2da37d08da9c188 Mon Sep 17 00:00:00 2001 From: Abigail Dawson Date: Thu, 25 Apr 2024 20:27:10 -0400 Subject: [PATCH 5/6] Update text displayed in details box, including link to more info on OpenAlex --- observable/docs/index.md | 11 +++++------ observable/docs/styles.css | 3 ++- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/observable/docs/index.md b/observable/docs/index.md index 1c9f59d..8d91344 100644 --- a/observable/docs/index.md +++ b/observable/docs/index.md @@ -146,7 +146,6 @@ orb.events.on('node-click', (event) => { function getData(event) { selectedNode = event.node.data; - console.log(selectedNode) updateDetails(selectedNode) } @@ -158,21 +157,21 @@ function updateDetails(selectedNode) { let html = ''; if (selectedNode) { - html += `

${selectedNode.label}

`; + html += `

${selectedNode.label}

`; if (selectedNode.type === 'INSTITUTION') { - html += `

Institution type: ${selectedNode.type}

`; - html += `

Homepage: ${selectedNode.homepage}

`; + html += `

Homepage: ${selectedNode.homepage}

`; html += `

Works: ${selectedNode.works_count}

`; html += `

Cited by: ${selectedNode.cited_by_count}

`; + html += `View on OpenAlex`; } else if (selectedNode.type === 'AUTHOR') { html += `

Works: ${selectedNode.works_count}

`; html += `

Cited by: ${selectedNode.cited_by_count}

`; + html += `View on OpenAlex`; } else if (selectedNode.type === 'TOPIC') { - html += `

Description: ${selectedNode.description}

`; - html += `

Field: ${selectedNode.field}

`; html += `

Subfield: ${selectedNode.subfield}

`; html += `

Domain: ${selectedNode.domain}

`; + html += `View on OpenAlex`; } } diff --git a/observable/docs/styles.css b/observable/docs/styles.css index 96a00fb..d5c283e 100644 --- a/observable/docs/styles.css +++ b/observable/docs/styles.css @@ -29,11 +29,12 @@ a { position: absolute; top: 2vmin; left: 2vmin; - width: 33%; + width: 35%; padding: 2vmin; border-radius: 1vmin; box-shadow: 5px 5px 8px 0px rgba(0,0,0,0.25); background-color: #fff; + line-height: 2; } /* LOADER */ From c7a0591907a63c4e1a956bfd3f08e9e76518db6a Mon Sep 17 00:00:00 2001 From: Abigail Dawson Date: Thu, 25 Apr 2024 21:02:03 -0400 Subject: [PATCH 6/6] Update intro text; adjust styling on details box to display only once graph has loaded --- observable/docs/index.md | 19 +++++++++++-------- observable/docs/styles.css | 15 ++++++++++++--- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/observable/docs/index.md b/observable/docs/index.md index 8d91344..88946ca 100644 --- a/observable/docs/index.md +++ b/observable/docs/index.md @@ -6,12 +6,15 @@ style: ./styles.css # CollabNext Challenge -Exercitation ut mollit fugiat sunt. Lorem deserunt consequat voluptate consectetur reprehenderit qui. Sit exercitation commodo non esse aliqua commodo enim aliquip est dolore sit laboris occaecat tempor. Culpa commodo ad magna dolore veniam commodo est eiusmod qui eu dolore nisi pariatur eiusmod. Est mollit esse pariatur nisi eu sunt fugiat culpa. Veniam excepteur amet duis veniam officia elit cillum sunt. +
+

Researchers struggle to discover connections between researchers and topics from HBCUs and underrepresented universities due to the lack of tools available that focus on diversity and inclusion of underrepresented researchers. Our app seeks to address this problem by creating a knowledge graph visualization with an intuitive user interface that allows researchers, students, conference organizers and others to discover researchers from HBCUs and understand how they are connected through their institutions and research topics.

+ +

With a sample of 5 HBCUs as our example, our app provides and interface for the user to explore a visual interactive representation of data from OpenAlex. Our app represents a scalable starting point towards addressing the broader systemic issue of diversity and inclusion in research data.

+
-Search ```js -const query = view(Inputs.text()); +const query = view(Inputs.text({placeholder: "Search"})); ``` ```js @@ -122,6 +125,7 @@ orb.data.setDefaultStyle({ const loaderOverlay = document.getElementById('loader-overlay'); const graphContainer = document.getElementById('graph'); +const details = document.querySelector('.details'); // Show loader overlay loaderOverlay.style.display = 'flex'; @@ -132,6 +136,7 @@ orb.data.setup({ nodes, edges }); // Render and recenter the view orb.view.render(() => { loaderOverlay.style.display = 'none'; + details.style.display = 'block'; orb.view.recenter(); }); ``` @@ -153,10 +158,10 @@ const details = document.querySelector('.details') function updateDetails(selectedNode) { details.innerHTML = ''; - let html = ''; if (selectedNode) { + details.style.display = 'block' html += `

${selectedNode.label}

`; if (selectedNode.type === 'INSTITUTION') { @@ -173,9 +178,7 @@ function updateDetails(selectedNode) { html += `

Domain: ${selectedNode.domain}

`; html += `View on OpenAlex`; } - } - - // Set the generated HTML content to the details element + } details.innerHTML = html; } ``` @@ -186,6 +189,6 @@ function updateDetails(selectedNode) {
-

Click on any node to see more details.

+

Click any node to see more details.

diff --git a/observable/docs/styles.css b/observable/docs/styles.css index d5c283e..6aba7a4 100644 --- a/observable/docs/styles.css +++ b/observable/docs/styles.css @@ -11,7 +11,7 @@ body { color: #333; background-color: #f4faff; margin: 2vmin; - padding: 2vmin; + padding: 2vmin 10vmin; } a { @@ -19,13 +19,22 @@ a { text-decoration: none; } +.intro { + display: flex; + flex-direction: column; + gap: 1vmin; + width: 90%; + margin: 2vmin 0; +} + .content { position: relative; - padding: 1vmin; - margin: 2vmin; + width: 90%; + margin: 2vmin 0; } .details { + display: none; position: absolute; top: 2vmin; left: 2vmin;