Data for this view comes from TAIR{' '}
-
+
GFF3
, TAIR{' '}
-
+
Protein Sequences
, TAIR{' '}
-
+
Gene Aliases
, TAIR{' '}
-
+
Functional description
{' '}
and TAIR10 Genome Sequence.
@@ -47,7 +47,7 @@ const GeneInfoView: View
= {
)
},
header: ({ geneticElement }) => (
- Information on {geneticElement?.id}
+ Information on {geneticElement?.id}
),
}
diff --git a/Eplant/views/GetStartedView/Tile.tsx b/Eplant/views/GetStartedView/Tile.tsx
index 3aabeae0..7246eb17 100644
--- a/Eplant/views/GetStartedView/Tile.tsx
+++ b/Eplant/views/GetStartedView/Tile.tsx
@@ -44,7 +44,7 @@ export default function Tile({ view }: TileProps) {
})}
>
-
{view.name}
+
{view.name}
theme.palette.secondary.main}
>
{view.description}
@@ -71,13 +71,13 @@ export default function Tile({ view }: TileProps) {
theme.palette.secondary.main}
sx={{ ml: 1 }}
>
Example{' '}
-
diff --git a/Eplant/views/GetStartedView/component.tsx b/Eplant/views/GetStartedView/component.tsx
index 85ab7133..30998800 100644
--- a/Eplant/views/GetStartedView/component.tsx
+++ b/Eplant/views/GetStartedView/component.tsx
@@ -13,23 +13,23 @@ export default function GetStartedView({
return (
- ePlant 3
-
+ ePlant 3
+
Bioinformatics evolved
- Start
-
-
+ Start
+
+
Select a species
-
-
+
+
Enter a gene of interest
-
-
+
+
Use the view selector to navigate between views
@@ -38,25 +38,25 @@ export default function GetStartedView({
Built by students in the{' '}
-
+
Provart Lab
{' '}
at the University of Toronto. If you're interested in
contributing to the project, visit our{' '}
GitHub
{' '}
page and reach out to us{' '}
here
diff --git a/Eplant/views/PlantEFP/icon.tsx b/Eplant/views/PlantEFP/icon.tsx
index 5a4c51aa..555674a6 100644
--- a/Eplant/views/PlantEFP/icon.tsx
+++ b/Eplant/views/PlantEFP/icon.tsx
@@ -3,13 +3,13 @@ import * as React from 'react'
export default styled((props) => {
return (
)
})(({ theme }) => ({
diff --git a/Eplant/views/PlantEFP/index.tsx b/Eplant/views/PlantEFP/index.tsx
index afe5ab25..f9f0af75 100644
--- a/Eplant/views/PlantEFP/index.tsx
+++ b/Eplant/views/PlantEFP/index.tsx
@@ -9,7 +9,7 @@ import { EFPViewerData } from '../eFP/Viewer/types'
const views: EFPViewerData['views'] = [
{
- name: 'AtGenExpress',
+ name: 'AtGenExpress eFP',
id: 'atgenexpress',
svgURL:
'https://bar.utoronto.ca/eplant/data/plant/AtGenExpress/Arabidopsis_thaliana.svg',
@@ -17,7 +17,7 @@ const views: EFPViewerData['views'] = [
'https://bar.utoronto.ca/eplant/data/plant/AtGenExpress/Arabidopsis_thaliana.xml',
},
{
- name: 'Klepikova',
+ name: 'Klepikova eFP (RNA-Seq data)',
id: 'klepikova',
svgURL:
'https://bar.utoronto.ca/eplant/data/plant/Klepikova/Arabidopsis_thaliana.svg',
diff --git a/Eplant/views/PublicationViewer/GeneRIFs.tsx b/Eplant/views/PublicationViewer/GeneRIFs.tsx
index 4c2418d4..19a9c57c 100644
--- a/Eplant/views/PublicationViewer/GeneRIFs.tsx
+++ b/Eplant/views/PublicationViewer/GeneRIFs.tsx
@@ -19,10 +19,10 @@ const columns: GridColDef[] = [
renderCell: (params: GridRenderCellParams<{ [key: string]: unknown }>) => (
VIEW PAPER
diff --git a/Eplant/views/PublicationViewer/Publications.tsx b/Eplant/views/PublicationViewer/Publications.tsx
index a0cb0b11..ebe1842f 100644
--- a/Eplant/views/PublicationViewer/Publications.tsx
+++ b/Eplant/views/PublicationViewer/Publications.tsx
@@ -38,10 +38,10 @@ const columns: GridColDef[] = [
<>
VIEW PAPER
diff --git a/Eplant/views/PublicationViewer/SearchBar.tsx b/Eplant/views/PublicationViewer/SearchBar.tsx
index a4fe6196..3894ab57 100644
--- a/Eplant/views/PublicationViewer/SearchBar.tsx
+++ b/Eplant/views/PublicationViewer/SearchBar.tsx
@@ -4,10 +4,10 @@ import * as React from 'react'
export const SearchBar = () => {
return (
)
diff --git a/Eplant/views/PublicationViewer/icon.tsx b/Eplant/views/PublicationViewer/icon.tsx
index 2efffd71..d6819990 100644
--- a/Eplant/views/PublicationViewer/icon.tsx
+++ b/Eplant/views/PublicationViewer/icon.tsx
@@ -3,17 +3,17 @@ import * as React from 'react'
export default styled(function PublicationViewerIcon(props) {
return (
)
})(({ theme }) => ({
diff --git a/Eplant/views/PublicationViewer/index.tsx b/Eplant/views/PublicationViewer/index.tsx
index c3213734..3025bc50 100644
--- a/Eplant/views/PublicationViewer/index.tsx
+++ b/Eplant/views/PublicationViewer/index.tsx
@@ -21,8 +21,8 @@ const PublicationViewer: View = {
return (
setTab(val)}>
-
-
+
+
= {
return (
Data for this view comes from NCBI{' '}
-
+
Gene2Pubmed
. Data for Gene RIFs comes from NCBI{' '}
-
+
Gene RIFs
)
},
header: ({ geneticElement }) => (
-
+
Publications related to {geneticElement?.id}
),
diff --git a/Eplant/views/eFP/EFPPreview.tsx b/Eplant/views/eFP/EFPPreview.tsx
index d10f80bc..b217ca3d 100644
--- a/Eplant/views/eFP/EFPPreview.tsx
+++ b/Eplant/views/eFP/EFPPreview.tsx
@@ -70,7 +70,7 @@ export default function EFPPreview({
}}
>
Max: {Math.round(dataDeferred.max)}
@@ -83,7 +83,7 @@ export default function EFPPreview({
component
) : (
-
+
)
}
diff --git a/Eplant/views/eFP/Tooltips/EFPTooltip.tsx b/Eplant/views/eFP/Tooltips/EFPTooltip.tsx
index a7e464b1..9b4f5118 100644
--- a/Eplant/views/eFP/Tooltips/EFPTooltip.tsx
+++ b/Eplant/views/eFP/Tooltips/EFPTooltip.tsx
@@ -103,7 +103,7 @@ function SVGTooltip(props: {
paddingBottom: 1.5,
})}
>
-
+
-
+
diff --git a/Eplant/views/eFP/Viewer/EFPViewerCitation.tsx b/Eplant/views/eFP/Viewer/EFPViewerCitation.tsx
new file mode 100644
index 00000000..2abfbce3
--- /dev/null
+++ b/Eplant/views/eFP/Viewer/EFPViewerCitation.tsx
@@ -0,0 +1,52 @@
+import { Link } from '@mui/material'
+
+interface IEFPViewerCitationProps {
+ viewID: string
+ citation: { [key: string]: string }
+ xmlData: string[]
+}
+const EFPViewerCitation = ({
+ viewID,
+ citation,
+ xmlData,
+}: IEFPViewerCitationProps) => {
+ return (
+ // Need to set inner HTML to capture nested HTML tags in some citations
+
+
+ {citation.notes && (
+
+ )}
+ {citation.URL && (
+
+ citation.URL
+
+ )}
+ {xmlData.length > 0 && (
+
+ {xmlData.map((item, index) => {
+ if (item) {
+ return - {item}
+ }
+ })}
+
+ )}
+
+ This image was generated with the {viewID} at bar.utoronto.ca/eplant by
+ Waese et al. 2017.
+
+
+
+
+
+ )
+}
+
+export default EFPViewerCitation
diff --git a/Eplant/views/eFP/Viewer/GeneDistributionChart.tsx b/Eplant/views/eFP/Viewer/GeneDistributionChart.tsx
index 5ceea946..2facb1e6 100644
--- a/Eplant/views/eFP/Viewer/GeneDistributionChart.tsx
+++ b/Eplant/views/eFP/Viewer/GeneDistributionChart.tsx
@@ -47,32 +47,32 @@ const GeneDistributionChart = ({ data }: { data: EFPData }) => {
>
{geneRanking ? (
) : (
diff --git a/Eplant/views/eFP/Viewer/MaskModal.tsx b/Eplant/views/eFP/Viewer/MaskModal.tsx
index 03abf5cc..0671a796 100644
--- a/Eplant/views/eFP/Viewer/MaskModal.tsx
+++ b/Eplant/views/eFP/Viewer/MaskModal.tsx
@@ -8,6 +8,14 @@ import {
useTheme,
DialogTitle,
} from '@mui/material'
+import {
+ Modal,
+ Slider,
+ Typography,
+ Button,
+ useTheme,
+ DialogTitle,
+} from '@mui/material'
import { EFPViewerState } from './types'
// Modal component with a slider
@@ -52,14 +60,14 @@ const MaskModal = ({ state, onClose, onSubmit }: MaskModalProps) => {
Mask data
-
+
Mask samples if the expression level is below a given percentile of
the standard deviation.
`${value}%`}
min={0}
max={100}
@@ -73,7 +81,7 @@ const MaskModal = ({ state, onClose, onSubmit }: MaskModalProps) => {
Cancel
diff --git a/Eplant/views/eFP/Viewer/index.tsx b/Eplant/views/eFP/Viewer/index.tsx
index 3d55507a..d09ba6f1 100644
--- a/Eplant/views/eFP/Viewer/index.tsx
+++ b/Eplant/views/eFP/Viewer/index.tsx
@@ -3,7 +3,14 @@ import PanZoom from '@eplant/util/PanZoom'
import { View, ViewProps } from '@eplant/View'
import { ViewDataError } from '@eplant/View/viewData'
import { Box, MenuItem, Tooltip, Typography } from '@mui/material'
-import React, { startTransition } from 'react'
+import React, {
+ memo,
+ startTransition,
+ useEffect,
+ useMemo,
+ useRef,
+ useState,
+} from 'react'
import EFP from '..'
import EFPPreview from '../EFPPreview'
import { EFPViewerAction, EFPViewerData, EFPViewerState } from './types'
@@ -19,7 +26,9 @@ import NotSupported from '@eplant/UI/Layout/ViewNotSupported'
import Dropdown from '@eplant/UI/Dropdown'
import { red } from '@mui/material/colors'
import GeneDistributionChart from './GeneDistributionChart'
+import { getCitation } from '@eplant/util/citations'
import MaskModal from './MaskModal'
+import EFPViewerCitation from './EFPViewerCitation'
type EFPListProps = {
geneticElement: GeneticElement
@@ -36,10 +45,16 @@ type EFPListProps = {
maskThreshold: number
}
-const EFPListItem = React.memo(
+interface ICitationProps {
+ activeData?: EFPViewerData
+ state?: EFPViewerState
+ gene?: GeneticElement | null
+}
+
+const EFPListItem = memo(
function EFPRow({ index: i, data }: { index: number; data: EFPListProps }) {
return (
- {data.views[i].name}}>
+ {data.views[i].name}}>
({
@@ -76,7 +91,7 @@ const EFPListItem = React.memo(
},
)
-const EFPListRow = React.memo(function EFPListRow({
+const EFPListRow = memo(function EFPListRow({
style,
index,
data,
@@ -213,39 +228,36 @@ export default class EFPViewer
return state
}
}
- component = (
- props: ViewProps,
- ) => {
- const viewIndices: number[] = [
- ...Array(props.activeData.views.length).keys(),
- ]
+ component = ({
+ activeData,
+ state,
+ dispatch,
+ geneticElement,
+ }: ViewProps) => {
+ const viewIndices: number[] = [...Array(activeData.views.length).keys()]
viewIndices.sort((a, b) => {
- if (props.state.sortBy == 'name')
- return props.activeData.views[a].name.localeCompare(
- props.activeData.views[b].name,
- )
+ if (state.sortBy == 'name')
+ return activeData.views[a].name.localeCompare(activeData.views[b].name)
else {
- return (
- props.activeData.viewData[b].max - props.activeData.viewData[a].max
- )
+ return activeData.viewData[b].max - activeData.viewData[a].max
}
})
- const sortedViews = viewIndices.map((i) => props.activeData.views[i])
- const sortedViewData = viewIndices.map((i) => props.activeData.viewData[i])
+ const sortedViews = viewIndices.map((i) => activeData.views[i])
+ const sortedViewData = viewIndices.map((i) => activeData.viewData[i])
const sortedEfps = viewIndices.map((i) => this.efps[i])
- let activeViewIndex = React.useMemo(
- () => sortedEfps.findIndex((v) => v.id == props.state.activeView),
- [props.state.activeView, ...sortedEfps.map((v) => v.id)],
+ let activeViewIndex = useMemo(
+ () => sortedEfps.findIndex((v) => v.id == state.activeView),
+ [state.activeView, ...sortedEfps.map((v) => v.id)],
)
if (activeViewIndex == -1) {
activeViewIndex = 0
- props.dispatch({
+ dispatch({
type: 'set-view',
id: sortedEfps[0].id,
})
}
- const efp = React.useMemo(() => {
+ const efp = useMemo(() => {
const Component = sortedEfps[activeViewIndex].component
return (
{}}
/>
)
}, [
activeViewIndex,
- props.geneticElement?.id,
- props.dispatch,
+ geneticElement?.id,
+ dispatch,
sortedViewData[activeViewIndex],
- props.state.colorMode,
- props.state.maskThreshold,
+ state.colorMode,
+ state.maskThreshold,
])
- const ref = React.useRef(null)
+ const ref = useRef(null)
const dimensions = useDimensions(ref)
- if (!props.geneticElement) return <>>
+ if (!geneticElement) return <>>
return (
(
- props.dispatch({ type: 'sort-by', by: 'name' })
- }
+ selected={state.sortBy == 'name' ? true : false}
+ key='byName'
+ onClick={() => dispatch({ type: 'sort-by', by: 'name' })}
>
By name
,
{/* main canvas area */}
@@ -375,25 +381,20 @@ export default class EFPViewer
sx={(theme) => ({
flexGrow: 1,
position: 'relative',
- overflow: 'hidden',
- background: theme.palette.background.paperOverlay,
- border: `1px solid`,
- borderColor: theme.palette.background.edge,
- borderRadius: theme.shape.borderRadius + 'px',
})}
>
- {props.activeData.viewData[activeViewIndex].supported ? (
+ {activeData.viewData[activeViewIndex].supported ? (
<>
- {props.activeData.views[activeViewIndex].name !== 'cellEFP' && (
+ {activeData.views[activeViewIndex].name !== 'cellEFP' && (
)}
props.dispatch({ type: 'toggle-mask-modal' })}
+ state={state}
+ onClose={() => dispatch({ type: 'toggle-mask-modal' })}
onSubmit={(threshold) =>
- props.dispatch({
+ dispatch({
type: 'set-mask-threshold',
threshold: threshold,
})
@@ -407,12 +408,12 @@ export default class EFPViewer
zIndex: 10,
})}
data={{
- ...props.activeData.viewData[activeViewIndex],
+ ...activeData.viewData[activeViewIndex],
}}
state={{
- colorMode: props.state.colorMode,
+ colorMode: state.colorMode,
renderAsThumbnail: false,
- maskThreshold: props.state.maskThreshold,
+ maskThreshold: state.maskThreshold,
}}
/>
{
- props.dispatch({
+ dispatch({
type: 'set-transform',
transform,
})
@@ -444,7 +445,7 @@ export default class EFPViewer
}}
>
@@ -471,10 +472,60 @@ export default class EFPViewer
header: View['header'] = (
props,
) => (
-
+
{props.activeData.views.find((v) => v.id == props.state.activeView)?.name}
{': '}
{props.geneticElement?.id}
)
+
+ citation = ({ activeData, state, gene }: ICitationProps) => {
+ const [xmlData, setXMLData] = useState([])
+
+ const viewID = activeData?.views.find((v) => v.id == state?.activeView)
+ ?.name
+ const viewXML = activeData?.views.find((v) => v.id == state?.activeView)
+ ?.xmlURL
+ useEffect(() => {
+ const xmlLoad = async () => {
+ let xmlString = ''
+ if (viewXML) {
+ try {
+ const response = await fetch(viewXML)
+ const data = await response.text()
+ xmlString = data
+ } catch (error) {
+ console.error('Error fetching xmlData:', error)
+ }
+ }
+
+ // Extract tags
+ if (xmlString !== '') {
+ const parser = new DOMParser()
+ const xmlDoc = parser.parseFromString(xmlString, 'text/xml')
+ const listItems = xmlDoc.querySelectorAll('info li')
+ const itemsArray = Array.from(listItems).map((liElement) =>
+ liElement.textContent ? liElement.textContent : '',
+ )
+ setXMLData(itemsArray)
+ } else {
+ setXMLData([])
+ }
+ }
+ xmlLoad()
+ }, [viewXML])
+
+ if (viewID) {
+ const citation = getCitation(viewID) as { [key: string]: string }
+ return (
+
+ )
+ } else {
+ return No Citation information provided.
+ }
+ }
}
diff --git a/Eplant/views/eFP/index.tsx b/Eplant/views/eFP/index.tsx
index acb34f6c..838629af 100644
--- a/Eplant/views/eFP/index.tsx
+++ b/Eplant/views/eFP/index.tsx
@@ -299,7 +299,7 @@ export default class EFP implements View {
geneticElement,
}) => {
return (
-
+
{this.name} for {geneticElement?.id}
)
diff --git a/tsconfig.json b/tsconfig.json
index a88995e6..feef5f8d 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,7 +1,7 @@
{
"compilerOptions": {
"baseUrl": ".",
- "jsx": "react",
+ "jsx": "react-jsx",
"paths": {
"@eplant/*": ["Eplant/*"],
"@stories/*": ["stories/*"]