Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/cell numbering #564

Merged
merged 4 commits into from
Jan 23, 2025
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
selectImageItemRoiAlpha,
selectImageItemFilePath,
selectImageItemAlpha,
selectImageItemShowRoiLabels,
} from "store/slice/VisualizeItem/VisualizeItemSelectors"
import {
setImageItemShowGrid,
Expand All @@ -48,6 +49,7 @@ import {
resetImageActiveIndex,
setImageItemRoiAlpha,
setImageItemAlpha,
setImageItemShowRoiLabels,
} from "store/slice/VisualizeItem/VisualizeItemSlice"
import { ColorType } from "store/slice/VisualizeItem/VisualizeItemType"
import { selectCurrentWorkspaceId } from "store/slice/Workspace/WorkspaceSelector"
Expand All @@ -71,6 +73,7 @@ export const ImageItemEditor: FC = () => {
<ShowLine />
<ShowGrid />
<ShowScale />
<ShowRoiLabels />
<Zsmooth />
<Grid container component="label" alignItems="center">
<Grid item xs={8}>
Expand Down Expand Up @@ -225,6 +228,24 @@ const RoiAlpha: FC = () => {
)
}

const ShowRoiLabels: FC = () => {
const itemId = useContext(SelectedItemIdContext)
const showRoiLabels = useSelector(selectImageItemShowRoiLabels(itemId))
const dispatch = useDispatch()
const toggleChecked = () => {
dispatch(
setImageItemShowRoiLabels({ itemId, showRoiLabels: !showRoiLabels }),
)
}
return (
<ParamSwitch
label={"Show ROI labels"}
value={showRoiLabels}
onChange={toggleChecked}
/>
)
}

const StartEndIndex: FC = () => {
const workspaceId = useSelector(selectCurrentWorkspaceId)
const itemId = useContext(SelectedItemIdContext)
Expand Down
67 changes: 62 additions & 5 deletions frontend/src/components/Workspace/Visualize/Plot/ImagePlot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
PlotData,
PlotMouseEvent,
PlotSelectionEvent,
Annotations,
} from "plotly.js"

import { Button, LinearProgress, TextField, Typography } from "@mui/material"
Expand Down Expand Up @@ -77,6 +78,7 @@ import {
selectImageItemAlpha,
selectRoiItemOutputKeys,
selectVisualizeItems,
selectImageItemShowRoiLabels,
} from "store/slice/VisualizeItem/VisualizeItemSelectors"
import {
incrementImageActiveIndex,
Expand Down Expand Up @@ -227,6 +229,7 @@ const ImagePlotChart = memo(function ImagePlotChart({
const [startDragAddRoi, setStartDragAddRoi] = useState(false)
const [action, setAction] = useState("")
const [positionDrag, setChangeSize] = useState<PositionDrag | undefined>()
const showRoiLabels = useSelector(selectImageItemShowRoiLabels(itemId))

const outputKey: string | null = useSelector(selectRoiItemOutputKeys(itemId))

Expand Down Expand Up @@ -300,7 +303,7 @@ const ImagePlotChart = memo(function ImagePlotChart({
z: roiDataState,
type: "heatmap",
name: "roi",
hovertemplate: action === ADD_ROI ? "none" : "cell id: %{z}",
hovertemplate: action === ADD_ROI ? "none" : "ROI: %{z}",
// hoverinfo: isAddRoi || pointClick.length ? "none" : undefined,
colorscale: [...Array(timeDataMaxIndex + 1)].map((_, i) => {
const new_i = Math.floor(((i % 10) * 10 + i / 10) % 100)
Expand Down Expand Up @@ -389,6 +392,57 @@ const ImagePlotChart = memo(function ImagePlotChart({
dispatch(selectingImageArea({ itemId, range: event.range }))
}
})

const roiLabels = useMemo(() => {
if (!showRoiLabels) return []
const labels: Annotations[] = []
const seen = new Set()

roiDataState.forEach((row, _y) => {
row.forEach((value, _x) => {
if (value !== null && !seen.has(value)) {
seen.add(value)
const points = {
x: [] as number[],
y: [] as number[],
count: 0,
}
roiDataState.forEach((r, yi) => {
r.forEach((v, xi) => {
if (v === value) {
points.x.push(xi)
points.y.push(yi)
points.count++
}
})
})

const centerX = points.x.reduce((a, b) => a + b, 0) / points.count
const centerY = points.y.reduce((a, b) => a + b, 0) / points.count

const annotation: Partial<Annotations> = {
x: centerX,
y: centerY,
text: `${value}`,
xref: "x",
yref: "y",
showarrow: false,
font: {
color: "black", // Black text
size: 10,
weight: 700, // Bold text
},
bgcolor: "rgba(255, 255, 255, 0.6)", // Soft white semi-transparent background (60% opacity)
borderpad: 0.5, // Padding around the text
}

labels.push(annotation as Annotations)
}
})
})
return labels
}, [roiDataState, showRoiLabels])

const layout = useMemo(
() => ({
title: {
Expand All @@ -412,6 +466,7 @@ const ImagePlotChart = memo(function ImagePlotChart({
autotick: true,
ticks: "",
showticklabels: showticklabels,
annotations: roiLabels,
},
yaxis: {
title: meta?.ylabel,
Expand All @@ -420,10 +475,11 @@ const ImagePlotChart = memo(function ImagePlotChart({
showgrid: showgrid,
showline: showline,
zeroline: false,
autotick: true, // todo
autotick: true,
ticks: "",
showticklabels: showticklabels, // todo
showticklabels: showticklabels,
},
annotations: roiLabels,
}),
//eslint-disable-next-line react-hooks/exhaustive-deps
[
Expand All @@ -435,6 +491,7 @@ const ImagePlotChart = memo(function ImagePlotChart({
height,
selectMode,
action,
roiLabels,
],
)

Expand Down Expand Up @@ -709,8 +766,8 @@ const ImagePlotChart = memo(function ImagePlotChart({
action === DELETE_ROI
? "#F84E1B"
: action === MERGE_ROI
? "#6619A9"
: "default",
? "#6619A9"
: "default",
display: "flex",
gap: 1,
textDecoration: "none",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ const RoiPlotImple = memo(function RoiPlotImple() {
// zsmooth: zsmooth, // ['best', 'fast', false]
zsmooth: false,
showlegend: true,
hovertemplate: "ROI: %{z}",
},
],
[imageData, colorscale],
Expand Down
10 changes: 10 additions & 0 deletions frontend/src/store/slice/VisualizeItem/VisualizeItemSelectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -608,3 +608,13 @@ export const selectImageItemRangeUnit =
throw new Error("invalid VisualaizeItemType")
}
}

export const selectImageItemShowRoiLabels =
(itemId: number) => (state: RootState) => {
const item = selectVisualizeItemById(itemId)(state)
if (isImageItem(item)) {
return item.showRoiLabels
} else {
throw new Error("invalid VisualaizeItemType")
}
}
14 changes: 14 additions & 0 deletions frontend/src/store/slice/VisualizeItem/VisualizeItemSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ const imageItemInitialValue: ImageItem = {
roiItem: null,
roiAlpha: 1.0,
duration: 500,
showRoiLabels: false,
}
const timeSeriesItemInitialValue: TimeSeriesItem = {
...displayDataCommonInitialValue,
Expand Down Expand Up @@ -857,6 +858,18 @@ export const visualaizeItemSlice = createSlice({
targetItem.selectedIndex = action.payload.selectedIndex
}
},
setImageItemShowRoiLabels: (
state,
action: PayloadAction<{
itemId: number
showRoiLabels: boolean
}>,
) => {
const targetItem = state.items[action.payload.itemId]
if (isImageItem(targetItem)) {
targetItem.showRoiLabels = action.payload.showRoiLabels
}
},
},
extraReducers: (builder) => {
builder
Expand Down Expand Up @@ -1025,6 +1038,7 @@ export const {
setHistogramItemBins,
setLineItemSelectedIndex,
setPolartemItemSelectedIndex,
setImageItemShowRoiLabels,
resetAllOrderList,
reset,
} = visualaizeItemSlice.actions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export interface ImageItem extends DisplayDataItemBaseType {
roiAlpha: number
duration: number
clickedDataId?: string
showRoiLabels: boolean
}

export interface TimeSeriesItem extends DisplayDataItemBaseType {
Expand Down
6 changes: 3 additions & 3 deletions studio/app/optinist/wrappers/caiman/cnmf.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ def get_roi(A, roi_thr, thr_method, swap_dim, dims):
# we compute the cumulative sum of the energy of the Ath component
# that has been ordered from least to highest
patch_data = A.data[A.indptr[i] : A.indptr[i + 1]]
indx = np.argsort(patch_data)[::-1]
idx = np.argsort(patch_data)[::-1]

if thr_method == "nrg":
cumEn = np.cumsum(patch_data[indx] ** 2)
cumEn = np.cumsum(patch_data[idx] ** 2)
if len(cumEn) == 0:
pars = dict(
coordinates=np.array([]),
Expand All @@ -48,7 +48,7 @@ def get_roi(A, roi_thr, thr_method, swap_dim, dims):
cumEn /= cumEn[-1]
Bvec = np.ones(d)
# we put it in a similar matrix
Bvec[A.indices[A.indptr[i] : A.indptr[i + 1]][indx]] = cumEn
Bvec[A.indices[A.indptr[i] : A.indptr[i + 1]][idx]] = cumEn
else:
Bvec = np.zeros(d)
Bvec[A.indices[A.indptr[i] : A.indptr[i + 1]]] = (
Expand Down
Loading