Skip to content

Commit

Permalink
Adds a motif/track selector to the details panel (for "Cluster" data …
Browse files Browse the repository at this point in the history
…only) -- #5
  • Loading branch information
chrtannus committed Oct 31, 2024
1 parent 179436c commit 9a23ce7
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 56 deletions.
4 changes: 0 additions & 4 deletions src/client/components/home/query-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import React, { useState } from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';

import { useTheme } from '@mui/material/styles';

import makeStyles from '@mui/styles/makeStyles';

import { Box, Paper, Typography, Link } from '@mui/material';
Expand Down Expand Up @@ -117,11 +115,9 @@ export function QueryPanel({ initialOrganism, isMobile, onOrganismChanged, onGen
const [ organism, setOrganism ] = useState(organisms.indexOf(initialOrganism));

const classes = useQueryPanelStyles();
const theme = useTheme();

const handleOrganismChange = (event) => {
const idx = event.target.value;
console.log(idx);
setOrganism(idx);
onOrganismChanged(organisms[idx]);
};
Expand Down
83 changes: 55 additions & 28 deletions src/client/components/network-editor/bottom-drawer.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ import { motifName, motifTrackLinkOut, rowId, rowTypeIdField } from '../util';
import makeStyles from '@mui/styles/makeStyles';

import Collapse from '@mui/material/Collapse';
import { AppBar, Toolbar, Divider } from '@mui/material';
import { AppBar, Toolbar, Divider, Grid } from '@mui/material';
import { Drawer, Tooltip, Typography } from '@mui/material';
import { IconButton, ToggleButtonGroup, ToggleButton } from '@mui/material';
import { FormControl, InputLabel, Select, MenuItem } from '@mui/material';

import ExpandIcon from '@mui/icons-material/ExpandLess';
import CollapseIcon from '@mui/icons-material/ExpandMore';
Expand Down Expand Up @@ -76,18 +77,6 @@ function toTableData(results, type, sortFn) {
return sortFn ? sortFn(data) : data;
}

function rowsInNetwork(data) {
const rows = [];
data.forEach(r => {
r.transcriptionFactors && r.transcriptionFactors.forEach(tf => {
if (tf.inNetwork) {
rows.push(r);
}
});
});
return rows;
}

//==[ BottomDrawer ]==================================================================================================

const useBottomDrawerStyles = makeStyles((theme) => ({
Expand Down Expand Up @@ -185,6 +174,7 @@ export function BottomDrawer({ controller, open, leftDrawerOpen, isMobile, isTab
const [ searchTerms, setSearchTerms ] = useState();
const [ currentRow, setCurrentRow ] = useState();
const [ scrollToId, setScrollToId ] = useState();
const [ selectedMotifOrTrack, setSelectedMotifOrTrack ] = useState();
const [ _, forceUpdate ] = useState(0); // Dummy state to force update

const classes = useBottomDrawerStyles();
Expand Down Expand Up @@ -325,11 +315,16 @@ export function BottomDrawer({ controller, open, leftDrawerOpen, isMobile, isTab
};
const onRowClick = (row) => {
setCurrentRow(row);
setSelectedMotifOrTrack(row?.motifsAndTracks?.[0]);
};
const onDataSort = (sortFn) => {
sortFnRef.current = sortFn; // Save the current sort function for later use
};

const onMotifAndTrackSelectChange = (motifOrTrack) => {
setSelectedMotifOrTrack(motifOrTrack);
};

const onTFCheckChange = async (tfInfo, checked, rowId) => {
// Find the row to update
let row = data.find(r => r.type === type && r.id === rowId);
Expand Down Expand Up @@ -386,7 +381,7 @@ export function BottomDrawer({ controller, open, leftDrawerOpen, isMobile, isTab
<ToolbarButton
title="Back"
icon={<ArrowBackIcon fontSize="medium" />}
onClick={() => setCurrentRow(null)}
onClick={() => { setCurrentRow(null); setSelectedMotifOrTrack(null); }}
/>
:
<SearchBar
Expand All @@ -408,6 +403,9 @@ export function BottomDrawer({ controller, open, leftDrawerOpen, isMobile, isTab
</Typography>
)}
<ToolbarDivider unrelated />
{open && currentRow && type === 'CLUSTER' && (
<MotifAndTrackSelect motifsAndTracks={currentRow.motifsAndTracks} onChange={onMotifAndTrackSelectChange} />
)}
<div className={classes.grow} />
{open && !currentRow && (
<ToggleButtonGroup
Expand Down Expand Up @@ -454,6 +452,7 @@ export function BottomDrawer({ controller, open, leftDrawerOpen, isMobile, isTab
<DataDetailsPanel
visible={open && currentRow != null}
data={currentRow || {}}
selectedMotifOrTrack={selectedMotifOrTrack}
controller={controller}
isMobile={isMobile}
onTFCheckChange={onTFCheckChange}
Expand All @@ -473,6 +472,48 @@ BottomDrawer.propTypes = {
onToggle: PropTypes.func.isRequired,
};

//==[ MotifAndTrackSelect ]===========================================================================================

function MotifAndTrackSelect({ motifsAndTracks, onChange }) {
const [value, setValue] = useState(0);

const handleChange = (event) => {
const idx = event.target.value;
setValue(idx);
const obj = motifsAndTracks[idx];
onChange?.(obj);
};

return (
<FormControl variant="filled" size="small">
<Select
variant="outlined"
value={value}
onChange={handleChange}
autoWidth
sx={{ pr: 2, backgroundColor: (theme) => theme.palette.background.paper, fontSize: '0.75rem' }}
>
{motifsAndTracks.map(({ rank, name }, idx) => (
<MenuItem key={rank} value={idx} sx={{ pr: 7 }}>
<Grid container spacing={2}>
<Grid item xs={2} sx={{ color: (theme) => theme.palette.text.disabled, textAlign: 'right' }}>
{ rank }
</Grid>
<Grid item xs={10}>
{ name }
</Grid>
</Grid>
</MenuItem>
))}
</Select>
</FormControl>
);
}
MotifAndTrackSelect.propTypes = {
motifsAndTracks: PropTypes.array.isRequired,
onChange: PropTypes.func,
};

//==[ ToolbarButton ]=================================================================================================

function ToolbarButton({ title, icon, color, className, disabled, onClick }) {
Expand Down Expand Up @@ -525,18 +566,4 @@ ToolbarDivider.propTypes = {
unrelated: PropTypes.bool
};

//==[ SelectionNavigator ]============================================================================================

const useSelectionNavigatorStyles = makeStyles(() => ({
root: {
maxWidth: 24,
},
button: {
minWidth: 24,
maxWidth: 24,
minHeight: 24,
maxHeight: 24,
},
}));

export default BottomDrawer;
33 changes: 9 additions & 24 deletions src/client/components/network-editor/data-details-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import makeStyles from '@mui/styles/makeStyles';

import { Table, TableHead, TableBody, TableCell, TableRow, TableSortLabel } from '@mui/material';
import { Box, Grid, Paper, Typography, Tooltip } from '@mui/material';
import { FormControl, InputLabel, Select, Menu, MenuItem } from '@mui/material';
import { Checkbox } from '@mui/material';


Expand Down Expand Up @@ -95,6 +96,7 @@ const useDataDetailsPanelStyles = makeStyles((theme) => ({
export function DataDetailsPanel({
visible,
data, // Track, Motif or TF
selectedMotifOrTrack, // Only used for CLUSTER data
controller,
isMobile,
onTFCheckChange,
Expand All @@ -119,14 +121,11 @@ export function DataDetailsPanel({

if (type === 'MOTIF') {
logoImgPath = logoPath(data.nameWithCollection);
} else if (type === 'CLUSTER') {
// TODO: temporary solution!
// Show the name and description of the first motif/track in the cluster, which is the one with the highest NES.
if (data.motifsAndTracks.length > 0) {
description = data.motifsAndTracks[0].name + ' -- ' + data.motifsAndTracks[0].description;
if (data.motifsAndTracks[0].type === 'MOTIF') {
logoImgPath = logoPath(data.motifsAndTracks[0].name);
}
} else if (type === 'CLUSTER' && selectedMotifOrTrack) {
// Show the name and description of the selected motif/track in the cluster
description = selectedMotifOrTrack.name + ' -- ' + selectedMotifOrTrack.description;
if (selectedMotifOrTrack.type === 'MOTIF') {
logoImgPath = logoPath(selectedMotifOrTrack.name);
}
}

Expand All @@ -138,7 +137,7 @@ export function DataDetailsPanel({
<Paper className={classes.root} sx={{display: visible ? 'block' : 'none'}}>
<Grid container direction="row" spacing={1} sx={{height: '100%'}}>
<Grid item xs={type === 'MOTIF' ? 3 : 4} sx={{height: '100%'}}>
<Box variant="outlined" sx={{height: '100%', border: 'none'}}>
<Box sx={{height: '100%', border: 'none'}}>
<Paper
variant="outlined"
sx={{p: theme.spacing(0.25, 1, 0.25, 1), overflowY: 'auto', maxHeight: 100, borderRadius: 2}}
Expand Down Expand Up @@ -176,6 +175,7 @@ export function DataDetailsPanel({
DataDetailsPanel.propTypes = {
visible: PropTypes.bool.isRequired,
data: PropTypes.object.isRequired,
selectedMotifOrTrack: PropTypes.object,
controller: PropTypes.instanceOf(NetworkEditorController).isRequired,
isMobile: PropTypes.bool,
onTFCheckChange: PropTypes.func,
Expand Down Expand Up @@ -295,21 +295,6 @@ function GeneTable({ columns, data, isMobile, onRowCheckChange }) {
</TableBody>
</Table>
</Paper>
// <Paper variant="outlined" className={classes.infoBox} sx={{height: '100%'}}>
// <List
// dense
// subheader={<ListSubheader className={classes.subheader}>Targets &#40;{data.candidateTargetGenes.length}&#41;</ListSubheader>}
// >
// {data.map(({ row }, idx) => (
// <ListItem key={`target-${idx}`} className={classes.listItem}>
// <ListItemIcon className={classes.listItemIcon}>
// <LabelImportantIcon className={classes.listItemIconIcon} />
// </ListItemIcon>
// <ListItemText className={classes.listItemText} primary={geneID.name} secondary={rank} />
// </ListItem>
// ))}
// </List>
// </Paper>
);
}
GeneTable.propTypes = {
Expand Down

0 comments on commit 9a23ce7

Please sign in to comment.