Skip to content

Commit

Permalink
Merging main branch into staging branch
Browse files Browse the repository at this point in the history
  • Loading branch information
actions-user committed Jul 12, 2024
2 parents 495c8a2 + 46501d6 commit e382000
Show file tree
Hide file tree
Showing 16 changed files with 232 additions and 128 deletions.
14 changes: 9 additions & 5 deletions backend/common/census_cube/data/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,9 @@ def cell_counts_diffexp_df(self, criteria: BaseQueryCriteria) -> DataFrame:
@tracer.wrap(
name="expression_summary_and_cell_counts_diffexp", service="de-api", resource="_query", span_type="de-api"
)
def expression_summary_and_cell_counts_diffexp(self, criteria: BaseQueryCriteria) -> tuple[DataFrame, DataFrame]:
use_simple = not any(
depluralize(key) not in cell_counts_indexed_dims and values for key, values in dict(criteria).items()
)

def expression_summary_and_cell_counts_diffexp(
self, criteria: BaseQueryCriteria, use_simple: bool
) -> tuple[DataFrame, DataFrame]:
cell_counts_diffexp_df = self.cell_counts_diffexp_df(criteria)
cell_counts_group_id_key = "group_id_simple" if use_simple else "group_id"
cube = (
Expand Down Expand Up @@ -209,6 +207,12 @@ def list_grouped_primary_filter_dimensions_term_ids(
)


def should_use_simple_group_ids(criteria: BaseQueryCriteria):
return not any(
depluralize(key) not in cell_counts_indexed_dims and values for key, values in dict(criteria).items()
)


def depluralize(attr_name):
return attr_name[:-1] if attr_name[-1] == "s" else attr_name

Expand Down
17 changes: 14 additions & 3 deletions backend/de/api/v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from backend.common.census_cube.data.criteria import BaseQueryCriteria
from backend.common.census_cube.data.ontology_labels import gene_term_label, ontology_term_label
from backend.common.census_cube.data.query import CensusCubeQuery
from backend.common.census_cube.data.query import CensusCubeQuery, should_use_simple_group_ids
from backend.common.census_cube.data.schemas.cube_schema_diffexp import cell_counts_logical_dims_exclude_dataset_id
from backend.common.census_cube.data.snapshot import CensusCubeSnapshot, load_snapshot
from backend.common.census_cube.utils import ancestors, descendants
Expand Down Expand Up @@ -248,8 +248,19 @@ def run_differential_expression(
set(sum([descendants(i) for i in criteria2.cell_type_ontology_term_ids], []))
)

es1, cell_counts1 = q.expression_summary_and_cell_counts_diffexp(criteria1)
es2, cell_counts2 = q.expression_summary_and_cell_counts_diffexp(criteria2)
if exclude_overlapping_cells == "retainBoth":
# If we are not excluding overlapping cells (retainBoth), we can use the simple group IDs where applicable.
es1, cell_counts1 = q.expression_summary_and_cell_counts_diffexp(
criteria1, should_use_simple_group_ids(criteria1)
)
es2, cell_counts2 = q.expression_summary_and_cell_counts_diffexp(
criteria2, should_use_simple_group_ids(criteria2)
)
else:
# If we are excluding overlapping cells, we can only use the simple group IDs if both groups are eligible.
use_simple_group_ids = should_use_simple_group_ids(criteria1) and should_use_simple_group_ids(criteria2)
es1, cell_counts1 = q.expression_summary_and_cell_counts_diffexp(criteria1, use_simple_group_ids)
es2, cell_counts2 = q.expression_summary_and_cell_counts_diffexp(criteria2, use_simple_group_ids)

n_cells1 = cell_counts1["n_total_cells"].sum()
n_cells2 = cell_counts2["n_total_cells"].sum()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ interface Props {
element: JSX.Element;
} | null>
>;
title: string;
title?: string;
skinnyMode?: boolean;
extraContent?: JSX.Element;
width?: "wide" | "default";
}
const HelpTooltip = ({
text,
Expand All @@ -48,12 +49,13 @@ const HelpTooltip = ({
title,
skinnyMode = false,
extraContent,
width = "wide",
}: Props) => {
return (
<Tooltip
sdsStyle={dark ? "dark" : "light"}
placement={placement}
width="wide"
width={width}
arrow
title={!skinnyMode && <StyledTooltip>{text}</StyledTooltip>}
slotProps={getSlotProps(dark)}
Expand All @@ -67,7 +69,7 @@ const HelpTooltip = ({
<ExtraContentWrapper>
<StyledQuestionMarkIcon
onClick={() => {
if (skinnyMode && setTooltipContent) {
if (skinnyMode && setTooltipContent && title) {
setTooltipContent({
title: title,
element: <StyledTooltip>{text}</StyledTooltip>,
Expand Down
45 changes: 41 additions & 4 deletions frontend/src/views/DifferentialExpression/common/store/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export const EMPTY_FILTERS = {
export const INITIAL_STATE: State = {
organismId: null,
snapshotId: null,
excludeOverlappingCells: "excludeTwo",
excludeOverlappingCells: "retainBoth",
queryGroups: { queryGroup1: EMPTY_FILTERS, queryGroup2: EMPTY_FILTERS },
queryGroupsWithNames: {
queryGroup1: EMPTY_FILTERS,
Expand Down Expand Up @@ -204,12 +204,49 @@ function selectQueryGroup2Filters(
}

function submitQueryGroups(state: State, _: PayloadAction<null>): State {
const { queryGroups, queryGroupsWithNames } = state;
const { selectedOptionsGroup1, selectedOptionsGroup2 } = state;

const filterAndMapOptions = (
selectedOptions: Record<string, FilterOption[]>,
mapTo: "id" | "name"
) => {
const result: Record<string, string[]> = {};
for (const key in selectedOptions) {
result[key as keyof QueryGroup] = selectedOptions[key as keyof QueryGroup]
.filter((option: FilterOption) => !option.unavailable)
.map((option: FilterOption) => option[mapTo]);
}
return result;
};

const newQueryGroup1 = {
...EMPTY_FILTERS,
...filterAndMapOptions(selectedOptionsGroup1, "id"),
};
const newQueryGroup2 = {
...EMPTY_FILTERS,
...filterAndMapOptions(selectedOptionsGroup2, "id"),
};

const newQueryGroupWithNames1 = {
...EMPTY_FILTERS,
...filterAndMapOptions(selectedOptionsGroup1, "name"),
};
const newQueryGroupWithNames2 = {
...EMPTY_FILTERS,
...filterAndMapOptions(selectedOptionsGroup2, "name"),
};

return {
...state,
submittedQueryGroups: queryGroups,
submittedQueryGroupsWithNames: queryGroupsWithNames,
submittedQueryGroups: {
queryGroup1: newQueryGroup1,
queryGroup2: newQueryGroup2,
},
submittedQueryGroupsWithNames: {
queryGroup1: newQueryGroupWithNames1,
queryGroup2: newQueryGroupWithNames2,
},
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { useMemo } from "react";
import {
QueryGroup,
State,
} from "src/views/DifferentialExpression/common/store/reducer";
import { QueryGroup } from "src/views/DifferentialExpression/common/store/reducer";
import { Tooltip } from "@czi-sds/components";
import { StyledTag } from "./style";
import { QUERY_GROUP_KEY_TO_TAG_SUFFIX_MAP } from "./constants";
Expand All @@ -11,71 +8,75 @@ import { NO_ORGAN_ID } from "src/views/CellGuide/components/CellGuideCard/compon
import Link from "src/views/CellGuide/components/CellGuideCard/components/common/Link";

const QueryGroupTags = ({
selectedOptions,
submittedQueryGroup,
submittedQueryGroupWithNames,
}: {
selectedOptions: State["selectedOptionsGroup1"];
submittedQueryGroup: QueryGroup;
submittedQueryGroupWithNames: QueryGroup;
}) => {
const nonEmptyQueryGroupKeys = useMemo(() => {
return Object.keys(selectedOptions).filter(
(key) => selectedOptions[key as keyof QueryGroup].length > 0
return Object.keys(submittedQueryGroup).filter(
(key) => submittedQueryGroup[key as keyof QueryGroup].length > 0
);
}, [selectedOptions]);
}, [submittedQueryGroup]);

return (
<>
{nonEmptyQueryGroupKeys.map((key) => {
const queryGroupKey = key as keyof QueryGroup;
const selected = selectedOptions[queryGroupKey].filter(
(option) => !option.unavailable
);
const selectedIds = submittedQueryGroup[queryGroupKey];
const selectedNames = submittedQueryGroupWithNames[queryGroupKey];

const suffix = QUERY_GROUP_KEY_TO_TAG_SUFFIX_MAP[queryGroupKey];
const label =
selected.length > 1
? `${selected.length} ${suffix}`
: selected[0].name;
selectedNames.length > 1
? `${selectedNames.length} ${suffix}`
: selectedNames[0];

const getValue = (index: number) => {
return key === "cellTypes" ? (
<Link
label={selected[index].name}
label={selectedNames[index]}
url={getCellTypeLink({
cellTypeId: selected[index].id,
cellTypeId: selectedIds[index],
tissueId: NO_ORGAN_ID,
})}
/>
) : (
selected[index].name
selectedNames[index]
);
};
const clickToViewText = "Click to view in CellGuide";
const tooltipContent =
selected.length === 1 && key === "cellTypes" ? (
selectedNames.length === 1 && key === "cellTypes" ? (
clickToViewText
) : (
<div>
{key === "cellTypes" && <b>{clickToViewText}</b>}
{selected.map((value, index) => (
{selectedNames.map((value, index) => (
<div key={`value-${value}-${index}`}>{getValue(index)}</div>
))}
</div>
);

const isSingleCellType = key === "cellTypes" && selected.length === 1;
const isSingleCellType =
key === "cellTypes" && selectedNames.length === 1;
return (
<Tooltip
key={`${key}-tooltip`}
sdsStyle="light"
placement="top"
width="wide"
leaveDelay={0}
disableHoverListener={key !== "cellTypes" && selected.length === 1}
disableHoverListener={
key !== "cellTypes" && selectedNames.length === 1
}
title={tooltipContent}
>
<span>
<TagWrapper
key={`${key}-tag-wrapper`}
selectedId={selected[0].id}
selectedId={selectedIds[0]}
isSingleCellType={isSingleCellType}
>
<StyledTag
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ export const useConnect = ({
}) => {
const {
excludeOverlappingCells,
selectedOptionsGroup1,
selectedOptionsGroup2,
submittedQueryGroups,
submittedQueryGroupsWithNames,
} = useContext(StateContext);
const [page, setPage] = useState(1);

Expand Down Expand Up @@ -123,7 +123,7 @@ export const useConnect = ({
datasets2.length !== 1 ? "s" : ""
}`,
showOverlappingCellsCallout: excludeOverlappingCells === "retainBoth",
selectedOptionsGroup1,
selectedOptionsGroup2,
submittedQueryGroups,
submittedQueryGroupsWithNames,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ const DifferentialExpressionResults = ({
numDatasetsText1,
numDatasetsText2,
showOverlappingCellsCallout,
selectedOptionsGroup1,
selectedOptionsGroup2,
submittedQueryGroups,
submittedQueryGroupsWithNames,
} = useConnect({
queryGroups,
queryGroupsWithNames,
Expand Down Expand Up @@ -177,6 +177,10 @@ const DifferentialExpressionResults = ({
setPage,
]);

if (!submittedQueryGroups || !submittedQueryGroupsWithNames) {
return null;
}

return (
<>
<CellGroupWrapper data-testid={DIFFERENTIAL_EXPRESSION_CELL_GROUP_1_INFO}>
Expand Down Expand Up @@ -216,7 +220,12 @@ const DifferentialExpressionResults = ({
</CellGroupStatsIndicator>
</CellCountTitle>
<FilterTagsWrapper>
<QueryGroupTags selectedOptions={selectedOptionsGroup1} />
<QueryGroupTags
submittedQueryGroup={submittedQueryGroups.queryGroup1}
submittedQueryGroupWithNames={
submittedQueryGroupsWithNames.queryGroup1
}
/>
</FilterTagsWrapper>
</CellGroupWrapper>
<CellGroupWrapper data-testid={DIFFERENTIAL_EXPRESSION_CELL_GROUP_2_INFO}>
Expand Down Expand Up @@ -256,7 +265,12 @@ const DifferentialExpressionResults = ({
</CellGroupStatsIndicator>
</CellCountTitle>
<FilterTagsWrapper>
<QueryGroupTags selectedOptions={selectedOptionsGroup2} />
<QueryGroupTags
submittedQueryGroup={submittedQueryGroups.queryGroup2}
submittedQueryGroupWithNames={
submittedQueryGroupsWithNames.queryGroup2
}
/>
</FilterTagsWrapper>
</CellGroupWrapper>
{!!errorMessage && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import { TextField } from "@mui/material";
import { inputBaseClasses } from "@mui/material/InputBase";
import { inputLabelClasses } from "@mui/material/InputLabel";
import { alertClasses } from "@mui/material/Alert";
import { TABLE_WIDTH } from "../../style";
import { RIGHT_PANEL_WIDTH } from "../../../../style";

const TABLE_WIDTH = RIGHT_PANEL_WIDTH - 60;

export const TableWrapper = styled.div`
width: ${TABLE_WIDTH};
width: ${TABLE_WIDTH}px;
[class*="StyledCell"] {
max-width: ${parseFloat(TABLE_WIDTH.replace("px", "")) / 3}px;
max-width: ${TABLE_WIDTH / 3}px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
Expand Down Expand Up @@ -57,7 +59,7 @@ export const EffectSizeHeaderWrapper = styled.div`
export const CellGroupWrapper = styled.div`
min-height: 92px;
height: fit-content;
width: ${TABLE_WIDTH};
width: ${TABLE_WIDTH}px;
margin-bottom: 8px;
padding: 12px;
Expand Down Expand Up @@ -90,7 +92,7 @@ export const FilterTagsWrapper = styled.div`
`;

export const StyledCallout = styled(Callout)`
width: ${TABLE_WIDTH};
width: ${TABLE_WIDTH}px;
.${alertClasses.icon} {
margin-top: auto;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import {
fontHeaderXl,
} from "@czi-sds/components";
import { gray500, primary400 } from "src/common/theme";
import { RIGHT_PANEL_WIDTH } from "../../style";

export const TABLE_WIDTH = "480px";
export const TABLE_WIDTH = RIGHT_PANEL_WIDTH - 60;

export const ButtonLabel = styled.span`
${fontBodyM}
Expand All @@ -23,7 +24,7 @@ export const ResultsHeaderWrapper = styled.div`
flex-direction: row;
margin-bottom: 16px;
justify-content: space-between;
width: ${TABLE_WIDTH};
width: ${TABLE_WIDTH}px;
`;

interface ButtonsWrapperProps {
Expand Down Expand Up @@ -51,6 +52,7 @@ export const InstructionsWrapper = styled.div`
max-width: 368px;
margin-left: 16px;
margin-top: 16px;
padding-right: 20px;
`;
export const InstructionsHeader = styled.div`
${fontHeaderL}
Expand Down
Loading

0 comments on commit e382000

Please sign in to comment.