Skip to content

Commit

Permalink
Merge pull request #161 from databio/genome_compatibility
Browse files Browse the repository at this point in the history
add reference genome compatibility modal
  • Loading branch information
khoroshevskyi authored Feb 18, 2025
2 parents 4aad89a + a68595a commit 0feb98d
Show file tree
Hide file tree
Showing 8 changed files with 287 additions and 18 deletions.
93 changes: 90 additions & 3 deletions ui/bedbase-types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,27 @@ export interface paths {
patch?: never;
trace?: never;
};
"/v1/bed/{bed_id}/genome-stats": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Get reference genome validation results
* @description Return reference genome validation results for a bed file
* Example: bed: 0dcdf8986a72a3d85805bbc9493a1302
*/
get: operations["get_ref_gen_results_v1_bed__bed_id__genome_stats_get"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/v1/bedset/example": {
parameters: {
query?: never;
Expand Down Expand Up @@ -909,7 +930,10 @@ export interface components {
};
/** BedPEPHub */
BedPEPHub: {
/** Sample Name */
/**
* Sample Name
* @default
*/
sample_name: string;
/**
* Genome
Expand Down Expand Up @@ -1001,7 +1025,10 @@ export interface components {
};
/** BedPEPHubRestrict */
BedPEPHubRestrict: {
/** Sample Name */
/**
* Sample Name
* @default
*/
sample_name: string;
/**
* Genome
Expand Down Expand Up @@ -1305,9 +1332,38 @@ export interface components {
/** Payload */
payload?: Record<string, never>;
/** Score */
score: number;
score?: number;
metadata?: components["schemas"]["BedMetadataBasic"] | null;
};
/** RefGenValidModel */
RefGenValidModel: {
/** Provided Genome */
provided_genome: string;
/** Compared Genome */
compared_genome: string;
/**
* Xs
* @default 0
*/
xs: number;
/** Oobr */
oobr?: number | null;
/** Sequence Fit */
sequence_fit?: number | null;
/** Assigned Points */
assigned_points: number;
/** Tier Ranking */
tier_ranking: number;
};
/** RefGenValidReturnModel */
RefGenValidReturnModel: {
/** Id */
id: string;
/** Provided Genome */
provided_genome?: string | null;
/** Compared Genome */
compared_genome: components["schemas"]["RefGenValidModel"][];
};
/** ServiceInfoResponse */
ServiceInfoResponse: {
/** Id */
Expand Down Expand Up @@ -2174,6 +2230,37 @@ export interface operations {
};
};
};
get_ref_gen_results_v1_bed__bed_id__genome_stats_get: {
parameters: {
query?: never;
header?: never;
path: {
bed_id: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["RefGenValidReturnModel"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
get_example_bedset_record_v1_bedset_example_get: {
parameters: {
query?: never;
Expand Down
58 changes: 49 additions & 9 deletions ui/src/components/bed-splash-components/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,28 @@ import { components } from '../../../bedbase-types';
import { useCopyToClipboard } from '@uidotdev/usehooks';
import { bytesToSize, formatDateTime } from '../../utils';
import { Dropdown, OverlayTrigger } from 'react-bootstrap';
import { RefGenomeModal } from './refgenome-modal';

const API_BASE = import.meta.env.VITE_API_BASE || '';

type BedMetadata = components['schemas']['BedMetadataAll'];
type BedGenomeStats = components['schemas']['RefGenValidReturnModel'];

type Props = {
metadata: BedMetadata;
record_identifier: string | undefined;
genomeStats: BedGenomeStats;
};

export const BedSplashHeader = (props: Props) => {
const { metadata, record_identifier } = props;
const { metadata, record_identifier, genomeStats } = props;

const [, copyToClipboard] = useCopyToClipboard();
const { cart, addBedToCart, removeBedFromCart } = useBedCart();
const [addedToCart, setAddedToCart] = useState(false);
const [copiedId, setCopiedId] = useState(false);
const [showRefGenomeModal, setShowRefGenomeModal] = useState(false);


const noFilesToDownload = !metadata.files?.bed_file && !metadata.files?.bigbed_file;

Expand Down Expand Up @@ -158,19 +163,47 @@ export const BedSplashHeader = (props: Props) => {
}
>
{metadata?.genome_digest ? (
<a href={`http://refgenomes.databio.org/v3/genomes/splash/${metadata.genome_digest}`} target="_blank">
<div className="badge bg-primary">
<>
<a href={`http://refgenomes.databio.org/v3/genomes/splash/${metadata.genome_digest}`} target="_blank">
<div className={genomeStats?.compared_genome ? "badge bg-primary rounded-end-0" : "badge bg-primary"}>
<i className="bi bi-database-fill me-2" />
{metadata.genome_alias || 'No assembly available'}
</div>
</a>
</>
) : (
<>
<div className="badge bg-primary rounded-end-0">
<i className="bi bi-database-fill me-2" />
{metadata.genome_alias || 'No assembly available'}
</div>
</a>
) : (
<div className="badge bg-primary">
<i className="bi bi-database-fill me-2" />
{metadata.genome_alias || 'No assembly available'}
</div>
</>
)}
</OverlayTrigger>
{genomeStats?.compared_genome &&
<OverlayTrigger
placement="top"
overlay={
<div className="tooltip">
<div className="tooltip-arrow" />
<div className="tooltip-inner">Genome compatibility</div>
</div>
}
>
<div
className="badge bg-primary border-start border-light rounded-start-0"
role="button"
onClick={() => {
// conditional required to prevent double click
if (showRefGenomeModal !== true) {
setShowRefGenomeModal(true);
}
}}
>
<i className="bi bi-info-circle-fill" />
</div>
</OverlayTrigger>
}
</p>
</div>
<div className="d-flex flex-row">
Expand Down Expand Up @@ -271,6 +304,13 @@ export const BedSplashHeader = (props: Props) => {
</div>
</div>
</div>
<RefGenomeModal
show={showRefGenomeModal}
onHide={() => {
setShowRefGenomeModal(false);
}}
genomeStats={genomeStats}
/>
</div>
);
};
94 changes: 94 additions & 0 deletions ui/src/components/bed-splash-components/refgenome-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { Modal } from 'react-bootstrap';
import { components } from '../../../bedbase-types';

type BedGenomeStats = components['schemas']['RefGenValidReturnModel'];

type Props = {
show: boolean;
onHide: () => void;
genomeStats: BedGenomeStats;
};

export const RefGenomeModal = (props: Props) => {
const { show, onHide, genomeStats } = props;

return (
<Modal
animation={false}
show={show}
onHide={() => onHide()}
size="lg"
aria-labelledby="contained-modal-title-vcenter"
centered
>
<Modal.Header closeButton>Reference Genome Compatibility</Modal.Header>
<Modal.Body>
<p className='text-sm'>
<strong>Note:</strong> Below is a ranking of the compatibility various reference genomes to this BED file (rank 1 is best).
The ranking is based on the following metrics:
</p>
<ul className='text-sm'>
<li><strong>XS</strong> (eXtra Sequences): the proportion of shared regions in both this BED file and reference genome over the total number of regions in this BED file [recall].</li>
<li><strong>OOBR</strong> (Out Of Bounds Regions): The proportion of shared regions from this BED file that do not exceed the bounds of the corresponding shared region in the reference genome.</li>
<li><strong>SF</strong> (Sequence Fit): the proportion of shared <span className='fst-italic'>region lengths</span> in both this BED file and reference genome over the total number of <span className='fst-italic'>region lengths</span> in the reference genome [precision].</li>
</ul>

<div className='row mb-1'>
<div className='col-12'>
<div className='d-flex align-items-center gap-2 px-3 fw-medium text-sm'>
<p className='mb-1' style={{width: '33%'}}>Genome</p>
<p className='mb-1 mx-2' style={{width: '14%'}}>XS</p>
<p className='mb-1 mx-2' style={{width: '14%'}}>OOBR</p>
<p className='mb-1 mx-2' style={{width: '14%'}}>SF</p>
<p className='mb-1 ms-auto'>Rank</p>
</div>
</div>
</div>

{genomeStats?.compared_genome?.sort((a, b) => a.tier_ranking - b.tier_ranking)
.map(genome => (
<div
className='card mb-2 shadow-sm genome-card'
style={{backgroundColor: (genome.tier_ranking == 1 ? '#C8EFB3A0' : (genome.tier_ranking == 2 ? '#FFF7BAA0' : (genome.tier_ranking == 3 ? '#F9D39DA0' : '#FCB6B6A0'))) }}
key={genome.compared_genome}
>
<div className='card-body'>

<div className='row'>
<div className='col-12'>
<div className='d-flex align-items-center gap-2'>
<p className='mb-1 fw-semibold' style={{width: '33%'}}>{genome.compared_genome}</p>

<div className="rounded-1 mx-2 bg-white position-relative shadow-sm" style={{width: '14%'}}>
<span className={`text-xs position-absolute start-50 top-50 translate-middle ${(genome.xs || 0) * 100 > 30 ? 'text-white' : 'text-dark'}`}>
{((genome.xs || 0) * 100).toFixed(2) + '%'}
</span>
<div className="rounded-1 bg-primary" style={{height: '16px', width: `${(genome.xs || 0) * 100}%` }} />
</div>

<div className="rounded-1 mx-2 bg-white position-relative shadow-sm" style={{width: '14%'}}>
<span className={`text-xs position-absolute start-50 top-50 translate-middle ${(genome.oobr || 0) * 100 > 30 ? 'text-white' : 'text-dark'}`}>
{((genome.oobr || 0) * 100).toFixed(2) + '%'}
</span>
<div className="rounded-1 bg-primary" style={{height: '16px', width: `${(genome.oobr || 0) * 100}%` }} />
</div>

<div className="rounded-1 mx-2 bg-white position-relative shadow-sm" style={{width: '14%'}}>
<span className={`text-xs position-absolute start-50 top-50 translate-middle ${(genome.sequence_fit || 0) * 100 > 30 ? 'text-white' : 'text-dark'}`}>
{((genome.sequence_fit || 0) * 100).toFixed(2) + '%'}
</span>
<div className="rounded-1 bg-primary" style={{height: '16px', width: `${(genome.sequence_fit || 0) * 100}%` }} />
</div>

<p className='mb-1 fw-medium ms-auto'>Rank {genome.tier_ranking}</p>
</div>
</div>
</div>

</div>
</div>
))}
</Modal.Body>
</Modal>
);
};
4 changes: 2 additions & 2 deletions ui/src/components/search/bed2bed/b2b-search-results-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ export const Bed2BedSearchResultsTable = (props: Props) => {
<span className="min-cell-width text-truncate d-inline-block">
<ProgressBar
min={5}
now={info.getValue() * 100}
label={`${roundToTwoDecimals(info.getValue() * 100)}`}
now={(info.getValue() ?? 0) * 100}
label={`${roundToTwoDecimals((info.getValue() ?? 0) * 100)}`}
variant="primary"
/>
</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ export const Text2BedSearchResultsTable = (props: Props) => {
<td>
<ProgressBar
min={5}
now={result.score * 100}
label={`${roundToTwoDecimals(result.score * 100)}`}
now={(result.score ?? 0) * 100}
label={`${roundToTwoDecimals((result.score ?? 0) * 100)}`}
variant="primary"
/>
</td>
Expand Down
5 changes: 5 additions & 0 deletions ui/src/custom.scss
Original file line number Diff line number Diff line change
Expand Up @@ -311,3 +311,8 @@ td {
color: #212529;
background: #e9ecef;
}

.genome-card:hover {
border: 1px solid $primary;
filter: brightness(98%);
}
Loading

0 comments on commit 0feb98d

Please sign in to comment.