Skip to content

Commit

Permalink
Adds a card for NDEx results and removes the Gene cards -- #18
Browse files Browse the repository at this point in the history
  • Loading branch information
chrtannus committed Sep 18, 2024
1 parent f676ccf commit d9807fb
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 19 deletions.
39 changes: 39 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@headlessui/react": "^2.0.4",
"@headlessui/tailwindcss": "^0.2.0",
"@heroicons/react": "^2.1.1",
"@js4cytoscape/ndex-client": "^0.3.2",
"@tailwindcss/forms": "^0.5.7",
"@tanstack/react-query": "^5.50.1",
"clsx": "^2.1.0",
Expand Down
140 changes: 121 additions & 19 deletions src/components/Results.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import { useEffect, useRef, useState } from 'react'
import { useQuery } from "@tanstack/react-query"
import Cytoscape from 'cytoscape'
import { NDEx } from '@js4cytoscape/ndex-client'
import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild } from '@headlessui/react'
import { LinkButton } from '@/components/base/Button'
import { LoadingMessage } from '@/components/base/Loading'
import { GeneManiaLogo } from '@/components/Logos'
import { GeneManiaLogo, NDExLogo } from '@/components/Logos'
import { XMarkIcon } from '@heroicons/react/24/outline'
import { ArrowTopRightOnSquareIcon, ExclamationTriangleIcon } from '@heroicons/react/20/solid'


const ndexClient = new NDEx('https://ndexbio.org/v2')


async function fetchGeneMetadata(symbol, taxon=9606) {
try {
const response = await fetch(`https://api.ncbi.nlm.nih.gov/datasets/v1/gene/symbol/${symbol}/taxon/${taxon}`, {
Expand Down Expand Up @@ -120,7 +125,7 @@ const GeneCard = ({ name, organism }) => {
const href = ncbiId ? `https://www.ncbi.nlm.nih.gov/gene/${ncbiId}` : null

return (
<li className={`p-4 rounded-xl min-h-28 sm:min-h-40 ${error ? 'border-double border-4 border-red-100' : 'border border-gray-200'}`}>
<li className={`p-4 rounded-xl min-h-28 sm:min-h-40 shadow-lg shadow-gray-200 ${error ? 'border-double border-4 border-red-100' : 'border border-gray-200'}`}>
<div className="flex items-center">
<a
href={href}
Expand Down Expand Up @@ -226,6 +231,7 @@ const GeneManiaCard = ({ genes, organism }) => {

useEffect(() => {
const fetchData = async () => {
setLoading(true)
const json = await fetchGeneManiaNetwork(genes.join('\n'), organism.id)
if (json.error) {
setError(json.error)
Expand Down Expand Up @@ -322,7 +328,7 @@ const GeneManiaCard = ({ genes, organism }) => {
const href = `https://genemania.org/search/${organism.id}/${genes.join('/')}`

return (
<div className="rounded-xl border border-gray-400 p-4 shadow-lg shadow-gray-200">
<div className={`w-full lg:w-2/5 p-4 rounded-xl min-h-28 sm:min-h-40 shadow-lg shadow-gray-200 ${error ? 'border-double border-4 border-red-100' : 'border border-gray-200'}`}>
<div className="flex items-center">
<GeneManiaLogo className="h-8 w-8" />
<a href={href} target="_blank" rel="noreferrer" className="flex items-start group">
Expand All @@ -331,10 +337,14 @@ const GeneManiaCard = ({ genes, organism }) => {
</a>
</div>
<div className="w-full mt-4">
{!loading && !error && (
<p className="text-right text-xs text-gray-600 overflow-y-auto">{data.resultGenes.length} result genes</p>
)}
<div className="relative w-full mt-2 border-4 rounded-lg">
<p className="text-right text-xs text-gray-600 overflow-y-auto">
{!loading && !error ?
<>{data.resultGenes.length} result genes</>
:
<>&nbsp;</>
}
</p>
<div className="relative w-full h-96 mt-2 ring-4 ring-black ring-opacity-5 rounded-lg">
<div id="genemania-cy" className="w-full h-96" />
{loading && (
<LoadingMessage className="w-full absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2" />
Expand All @@ -356,6 +366,105 @@ const GeneManiaCard = ({ genes, organism }) => {
)
}

const NDExCard = ({ genes }) => {
const [data, setData] = useState()
const [error, setError] = useState()
const [loading, setLoading] = useState(true)

useEffect(() => {
const fetchData = async () => {
const json = await ndexClient.searchNetworks(genes.join('\n'))
console.log(json)
if (json.error) {
setError(json.error)
} else {
setData(json)
}
setLoading(false)
}
fetchData()
}, [genes])

const href = `https://www.ndexbio.org/index.html#/search?searchType=All&searchString=${genes.join('%20')}&searchTermExpansion=false`

return (
<div className={`relative w-full lg:w-3/5 p-4 rounded-xl min-h-28 sm:min-h-40 shadow-lg shadow-gray-200 ${error ? 'border-double border-4 border-red-100' : 'border border-gray-200'}`}>
<div className="flex items-center">
<NDExLogo className="h-8 w-8" />
<a href={href} target="_blank" rel="noreferrer" className="flex items-start group">
<h3 className="ml-4 font-semibold text-gray-900 group-hover:text-complement-500">NDEx</h3>
<ArrowTopRightOnSquareIcon className="w-3 h-3 ml-1 mt-0.5 fill-gray-400 group-hover:fill-complement-500" />
</a>
</div>
<p className="mt-4 text-right text-xs text-gray-600 overflow-y-auto">
{!loading && !error ?
<>{data.networks.length < data.numFound ? 'Top' : '' } {data.networks.length} results</>
:
<>&nbsp;</>
}
</p>
<div className="mt-2 h-96 overflow-y-auto ring-4 ring-black ring-opacity-5 rounded-lg flow-root">
{loading && (
<LoadingMessage className="w-full absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2" />
)}
{error && (
<span className="w-full flex items-start justify-center text-red-800 absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
<ExclamationTriangleIcon className="w-5 h-5 mt-0.5" />
<span className="ml-2 font-light">
{error.message ? error.message : 'Unable to fetch networks'}
</span>
</span>
)}
{!loading && !error && (
<table className="min-w-full divide-y divide-gray-300">
<thead className="sticky bg-gray-50">
<tr>
<th scope="col" className="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">
Network
</th>
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
Owner
</th>
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
Nodes
</th>
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
Edges
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200 bg-white">
{data.networks.map((net) => (
<tr key={net.externalId}>
<td className="whitespace-nowrap px-3 py-2 text-left text-sm text-gray-500">
<a
href={`https://www.ndexbio.org/viewer/networks/${net.externalId}`}
target="_blank"
rel="noreferrer"
className=" group text-wrap"
>
<span className="underline underline-offset-2 group-hover:underline-complement-500 group-hover:text-complement-500">
{net.name}
</span>
<ArrowTopRightOnSquareIcon className="w-3 h-3 ml-1 -mt-2 inline fill-gray-400 group-hover:fill-complement-500" />
</a>
</td>
<td className="whitespace-nowrap px-3 py-2 text-sm text-gray-500">{net.owner}</td>
<td className="whitespace-nowrap px-3 py-2 text-right text-sm text-gray-500">{net.nodeCount}</td>
<td className="whitespace-nowrap px-3 py-2 text-right text-sm text-gray-500">{net.edgeCount}</td>
</tr>
))}
</tbody>
</table>
)}
</div>
<div className="flex w-full justify-center">
<LinkButton href={href}>More Results on NDEx</LinkButton>
</div>
</div>
)
}

export function Results({ open=false, data, onClose }) {
const type = data?.type
const title = data?.title || 'Results'
Expand Down Expand Up @@ -411,19 +520,12 @@ export function Results({ open=false, data, onClose }) {
<span className="ml-2">&#40;{geneNames.length} query gene{geneNames.length > 1 ? 's' : ''}&#41;</span>
</p>
</div>
<div className="flex flex-col space-y-8 items-start mt-5 px-6 sm:space-x-4 sm:flex-row sm:space-y-0">
<ul
role="list"
className="grid mx-auto w-full sm:w-1/2 grid-cols-1 gap-2 text-sm text-left sm:grid-cols-1 lg:grid-cols-2"
>
{geneNames.map((name) => (
<GeneCard key={name} name={name} organism={organism} />
))}
</ul>
<div className="flex flex-col lg:flex-row space-y-2 items-start mt-5 px-6 sm:space-x-4 sm:space-y-0">
{geneNames.length > 0 && organism && (
<div className="w-full sm:w-1/2">
<GeneManiaCard genes={geneNames} organism={organism} />
</div>
<GeneManiaCard genes={geneNames} organism={organism} />
)}
{geneNames.length > 0 && (
<NDExCard genes={geneNames} />
)}
</div>
</>
Expand Down

0 comments on commit d9807fb

Please sign in to comment.