Skip to content

Commit

Permalink
feat: Enable pagination of Annotations table with temporary hacky que…
Browse files Browse the repository at this point in the history
…ry (#992)

#581 

This changes the Annotations table GQL to query annotation_files at the
top level instead of annotations.

Because `distinct_on` was not able to be used to generate distinct
`annotation` and `shape_type` pairs (see comments in issue), this
instead ignores .zarr files for the time being to make each
`annotation_file`'s `shape_type` within an `annotation` unique.
  • Loading branch information
bchu1 authored Aug 9, 2024
1 parent ffeef3f commit 79f7247
Show file tree
Hide file tree
Showing 11 changed files with 147 additions and 178 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ import {
useMetadataDrawer,
} from 'app/hooks/useMetadataDrawer'
import { useRunById } from 'app/hooks/useRunById'
import { Annotation, useAnnotation } from 'app/state/annotation'
import { AnnotationRow, useAnnotation } from 'app/state/annotation'
import { I18nKeys } from 'app/types/i18n'
import { cns, cnsNoMerge } from 'app/utils/cns'

const LOADING_ANNOTATIONS = range(0, MAX_PER_PAGE).map<Annotation>(() => ({
const LOADING_ANNOTATIONS = range(0, MAX_PER_PAGE).map<AnnotationRow>(() => ({
annotation_method: '',
author_affiliations: [],
authors_aggregate: {},
Expand Down Expand Up @@ -73,23 +73,23 @@ function ConfidenceValue({ value }: { value: number }) {
export function AnnotationTable() {
const { isLoadingDebounced } = useIsLoading()
const [searchParams] = useSearchParams()
const { run, annotationFilesAggregates } = useRunById()
const { run, annotationFiles, annotationFilesAggregates } = useRunById()
const { toggleDrawer } = useMetadataDrawer()
const { setActiveAnnotation } = useAnnotation()
const { t } = useI18n()

const { openAnnotationDownloadModal } = useDownloadModalQueryParamState()

const openAnnotationDrawer = useCallback(
(annotation: Annotation) => {
(annotation: AnnotationRow) => {
setActiveAnnotation(annotation)
toggleDrawer(MetadataDrawerId.Annotation)
},
[toggleDrawer, setActiveAnnotation],
)

const columns = useMemo(() => {
const columnHelper = createColumnHelper<Annotation>()
const columnHelper = createColumnHelper<AnnotationRow>()

function getConfidenceCell({
cellHeaderProps,
Expand All @@ -99,7 +99,7 @@ export function AnnotationTable() {
}: {
cellHeaderProps?: Partial<ComponentProps<typeof CellHeader>>
header: string
key: keyof Annotation
key: keyof AnnotationRow
tooltipI18nKey?: I18nKeys
}) {
return columnHelper.accessor(key, {
Expand Down Expand Up @@ -331,11 +331,7 @@ export function AnnotationTable() {
runId: run.id,
annotationId: annotation.id,
objectShapeType: annotation.shape_type,
fileFormat: annotation.files
.filter(
(file) => file.shape_type === annotation.shape_type,
)
.at(0)?.format,
fileFormat: annotation.format,
})
}
startIcon={
Expand All @@ -353,7 +349,7 @@ export function AnnotationTable() {
</TableCell>
),
}),
] as ColumnDef<Annotation>[]
] as ColumnDef<AnnotationRow>[]
}, [
t,
openAnnotationDrawer,
Expand All @@ -364,30 +360,14 @@ export function AnnotationTable() {

const annotations = useMemo(
() =>
run.annotation_table.flatMap((data) =>
data.annotations.flatMap((annotation) => {
const shapeTypeSet = new Set<string>()

// Some annotations have files with different shape types. We display each shape type as a separate row.
// This loops through the files and adds an annotation for each shape type.
// If the shape type is filtered out, the files will not be returned in the 'run' object
const files = annotation.files.filter((file) => {
// If the shape type has already been added, don't add another annotation for it
if (shapeTypeSet.has(file.shape_type)) {
return false
}

shapeTypeSet.add(file.shape_type)
return true
})

return files.flatMap((file) => ({
...annotation,
...file,
}))
}),
) as Annotation[],
[run.annotation_table],
annotationFiles.map((annotationFile) => {
const { annotation: _, ...restAnnotationFileFields } = annotationFile
return {
...restAnnotationFileFields,
...annotationFile.annotation,
} as AnnotationRow
}),
[annotationFiles],
)

const currentPage = toNumber(
Expand All @@ -402,8 +382,8 @@ export function AnnotationTable() {
* - The non ground truth divider is attached to the first non ground truth row.
*/
const getGroundTruthDividersForRow = (
table: Table<Annotation>,
row: Row<Annotation>,
table: Table<AnnotationRow>,
row: Row<AnnotationRow>,
): ReactNode => {
return (
<>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { createContext, useContext } from 'react'

import { GetRunByIdQuery } from 'app/__generated__/graphql'
import { Annotation } from 'app/state/annotation'
import { BaseAnnotation } from 'app/state/annotation'

export type DownloadModalType = 'dataset' | 'runs' | 'annotation'

export type TomogramResolution =
GetRunByIdQuery['runs'][number]['tomogram_stats'][number]['tomogram_resolutions'][number]

export interface DownloadModalContextValue {
activeAnnotation?: Annotation | null
activeAnnotation?: BaseAnnotation | null
activeTomogramResolution?: TomogramResolution | null
allTomogramProcessing?: string[]
allTomogramResolutions?: TomogramResolution[]
Expand Down
170 changes: 87 additions & 83 deletions frontend/packages/data-portal/app/graphql/getRunById.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,69 +131,6 @@ const GET_RUN_BY_ID_QUERY = gql(`
}
}
annotation_table: tomogram_voxel_spacings {
annotations(
limit: $limit,
offset: $annotationsOffset,
where: {
_and: $filter
},
order_by: [
{ ground_truth_status: desc }
{ deposition_date: desc }
{ id: desc }
],
) {
annotation_method
annotation_publication
annotation_software
confidence_precision
confidence_recall
deposition_date
ground_truth_status
ground_truth_used
id
is_curator_recommended
last_modified_date
method_type
object_count
object_description
object_id
object_name
object_state
release_date
files(
where: {
_and: $fileFilter
}
) {
format
https_path
s3_path
shape_type
}
authors(order_by: { author_list_order: asc }) {
primary_author_status
corresponding_author_status
name
email
orcid
}
author_affiliations: authors(distinct_on: affiliation_name) {
affiliation_name
}
authors_aggregate {
aggregate {
count
}
}
}
}
tomogram_stats: tomogram_voxel_spacings {
annotations {
object_name
Expand Down Expand Up @@ -242,6 +179,91 @@ const GET_RUN_BY_ID_QUERY = gql(`
}
}
# Annotations table:
annotation_files(
where: {
format: {
_neq: "zarr" # TODO: Remove hack, migrate to new annotation + shape object.
}
annotation: {
tomogram_voxel_spacing: {
run_id: {
_eq: $id
}
}
_and: $filter
}
_and: $fileFilter
}
order_by: [
{
annotation: {
ground_truth_status: desc
}
},
{
annotation: {
deposition_date: desc
}
},
{
annotation_id: desc
}
]
limit: $limit
offset: $annotationsOffset
) {
shape_type
format
annotation {
annotation_method
annotation_publication
annotation_software
confidence_precision
confidence_recall
deposition_date
ground_truth_status
ground_truth_used
id
is_curator_recommended
last_modified_date
method_type
object_count
object_description
object_id
object_name
object_state
release_date
files(where: { _and: $fileFilter }) {
shape_type
format
https_path
s3_path
}
authors(order_by: { author_list_order: asc }) {
primary_author_status
corresponding_author_status
name
email
orcid
}
author_affiliations: authors(distinct_on: affiliation_name) {
affiliation_name
}
authors_aggregate {
aggregate {
count
}
}
}
}
# Annotation counts:
annotation_files_aggregate_for_total: annotation_files_aggregate(
where: {
annotation: {
Expand All @@ -258,7 +280,6 @@ const GET_RUN_BY_ID_QUERY = gql(`
count
}
}
annotation_files_aggregate_for_filtered: annotation_files_aggregate(
where: {
annotation: {
Expand All @@ -277,7 +298,6 @@ const GET_RUN_BY_ID_QUERY = gql(`
count
}
}
annotation_files_aggregate_for_ground_truth: annotation_files_aggregate(
where: {
annotation: {
Expand All @@ -299,7 +319,6 @@ const GET_RUN_BY_ID_QUERY = gql(`
count
}
}
annotation_files_aggregate_for_other: annotation_files_aggregate(
where: {
annotation: {
Expand Down Expand Up @@ -349,13 +368,8 @@ function getFilter(filterState: FilterState): Annotations_Bool_Exp[] {
})
}

const {
objectNames,
objectShapeTypes,
annotationSoftwares,
methodTypes,
goId,
} = filterState.annotation
const { objectNames, annotationSoftwares, methodTypes, goId } =
filterState.annotation

if (objectNames.length > 0) {
filters.push({
Expand All @@ -373,16 +387,6 @@ function getFilter(filterState: FilterState): Annotations_Bool_Exp[] {
})
}

if (objectShapeTypes.length > 0) {
filters.push({
files: {
shape_type: {
_in: objectShapeTypes,
},
},
})
}

if (methodTypes.length > 0) {
filters.push({
method_type: {
Expand Down
3 changes: 3 additions & 0 deletions frontend/packages/data-portal/app/hooks/useRunById.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export function useRunById() {

const run = data.runs[0]

const annotationFiles = data.annotation_files

const objectNames = useMemo(
() =>
Array.from(
Expand Down Expand Up @@ -61,6 +63,7 @@ export function useRunById() {

return {
run,
annotationFiles,
objectNames,
objectShapeTypes,
annotationSoftwares,
Expand Down
Loading

0 comments on commit 79f7247

Please sign in to comment.