Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions app/components/Image/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type ImageProps = {
isZoomable?: boolean;
/** Style to apply to img tag */
imgStyle?: React.ComponentPropsWithoutRef<'img'>['style'];
zoomStyle?: React.ComponentPropsWithoutRef<'img'>['style'];
};

const Image = ({
Expand All @@ -30,6 +31,7 @@ const Image = ({
showCaption = false,
isZoomable = true,
imgStyle = {},
zoomStyle = {},
}: ImageProps): JSX.Element => {
const [isZoomed, setIsZoomed] = useState(false);

Expand Down Expand Up @@ -85,24 +87,23 @@ const Image = ({
onClick={handleZoom}
type="button"
>
<div
className="image__dialog-button"
>
<div className="image__dialog-button">
{showTitle && title && (
<Typography variant="h3">
{title}
</Typography>
<Typography variant="h3">
{title}
</Typography>
)}
<img
className={`image__data ${isZoomable && isZoomed ? 'image__zoom--out' : ''}`}
src={`data:image/${format};base64,${data}`}
alt={title}
key={key}
style={zoomStyle}
/>
{showCaption && caption && (
<Typography className="image__caption" variant="caption">
{caption}
</Typography>
<Typography className="image__caption" variant="caption">
{caption}
</Typography>
)}
</div>
</button>
Expand Down
11 changes: 10 additions & 1 deletion app/views/ReportView/components/CopyNumber/index.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
$montage-padding: 8px;

.copy-number {
padding: 16px;

Expand All @@ -14,6 +16,13 @@
}

&__title {
padding: 16px;
padding: $montage-padding;
}

&__montage {
display: flex;
flex-wrap: wrap;
gap: 0.25rem;
padding: $montage-padding;
}
}
67 changes: 47 additions & 20 deletions app/views/ReportView/components/CopyNumber/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ const INFO_BUBBLES = {
lowExp: 'Copy number losses in known tumour supressor genes which are also lowly expressed.',
};

const CHR_LEGEND = 'legend';
const CHRS = Array.from({ length: 24 }, (_, i) => `chr${i + 1}`).join(',');
const CHR_IMG_HEIGHT = 375 / 2;

type CopyNumberProps = WithLoadingInjectedProps;

const CopyNumber = ({
Expand All @@ -55,6 +59,7 @@ const CopyNumber = ({
const { canEdit } = useReport();
const theme = useTheme();
const [images, setImages] = useState<ImageType[]>([]);
const [legend, setLegend] = useState<ImageType>([]);
const [circos, setCircos] = useState<ImageType>();
const [cnvs, setCnvs] = useState<CopyNumberType[]>([]);
const [groupedCnvs, setGroupedCnvs] = useState({
Expand Down Expand Up @@ -82,7 +87,7 @@ const CopyNumber = ({
try {
const apiCalls = new ApiCallSet([
api.get(`/reports/${report.ident}/copy-variants`),
api.get(`/reports/${report.ident}/image/retrieve/cnvLoh.circos,cnv.1,cnv.2,cnv.3,cnv.4,cnv.5,loh.1,loh.2,loh.3,loh.4,loh.5`),
api.get(`/reports/${report.ident}/image/retrieve/cnvLoh.circos,${CHR_LEGEND},${CHRS}`),
]);
const [cnvsResp, imagesResp] = await apiCalls.request() as [CopyNumberType[], ImageType[]];

Expand All @@ -109,11 +114,22 @@ const CopyNumber = ({
}

const circosIndex = imagesResp.findIndex((img) => img.key === 'cnvLoh.circos');
const [circosResp] = imagesResp.splice(circosIndex, 1);
const splicedImages = imagesResp.splice(circosIndex, 1);

const legendIndex = imagesResp.findIndex((img) => img.key === 'legend');
const splicedLegend = imagesResp.splice(legendIndex, 1);

const [circosResp] = splicedImages;
const [legendResp] = splicedLegend;

setCnvs(cnvsResp);
setCircos(circosResp);
setImages(imagesResp);
setImages(imagesResp.sort(({ key: a }, { key: b }) => {
const na = Number(a.replace(/\D/g, ''));
const nb = Number(b.replace(/\D/g, ''));
return na - nb;
}));
setLegend(legendResp);
} catch (err) {
snackbar.error(`Network error: ${err}`);
} finally {
Expand Down Expand Up @@ -204,6 +220,32 @@ const CopyNumber = ({

const handleVisibleColsChange = (change) => setVisibleCols(change);

const imagesSection = useMemo(() => {
if (images.length) {
return (
<section className="copy-number__montage">
<Image height={CHR_IMG_HEIGHT} image={legend} />
{
images.map((img) => (
<Image
height={CHR_IMG_HEIGHT}
image={img}
key={`${img.key}`}
zoomStyle={{
minWidth: '100%',
maxWidth: '90vw',
minHeight: '100%',
maxHeight: '85vh',
}}
/>
))
}
</section>
);
}
return <Typography align="center">No Copy Number &amp; LOH Plots Available</Typography>;
}, [images, legend]);

return (
<div className="copy-number">
<Typography variant="h3">Copy Number Analyses</Typography>
Expand Down Expand Up @@ -248,23 +290,8 @@ const CopyNumber = ({
))}
</>
)}
<Typography variant="h3" className="copy-number__title">Copy Number &amp; LOH</Typography>
{images.length ? (
<div className="copy-number__graphs">
{[...Array(5).keys()].map((index) => (
<React.Fragment key={index + 1}>
<Image
image={images.find((img) => img.key === `cnv.${index + 1}`)}
/>
<Image
image={images.find((img) => img.key === `loh.${index + 1}`)}
/>
</React.Fragment>
))}
</div>
) : (
<Typography align="center">No Copy Number &amp; LOH Plots Available</Typography>
)}
<Typography variant="h3" className="copy-number__title">Copy Number & LOH</Typography>
{imagesSection}
</>
)}
</div>
Expand Down