Skip to content

Commit

Permalink
Merge pull request #12 from josenimo/main
Browse files Browse the repository at this point in the history
v1.0 plotting, slider, and gates table
  • Loading branch information
josenimo authored Apr 12, 2024
2 parents 8e909b0 + 237b96f commit 14ac7f6
Show file tree
Hide file tree
Showing 6 changed files with 440 additions and 134 deletions.
121 changes: 121 additions & 0 deletions gates.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
sample_id,marker_id,gate_value
68,Rabbit IgG,3478.531304347826
68,Goat IgG,0.0
68,Mouse IgG,0.0
68,CD73,0.0
68,CD107B,0.0
68,MART1,0.0
68,KI67,0.0
68,pan-CK,0.0
68,CD45,0.0
68,ECAD,0.0
68,aSMA,0.0
68,CD56,0.0
68,CD13,0.0
68,CD63,0.0
68,CD32,0.0
68,CDKN1A,0.0
68,CCNA2,0.0
68,CDKN1C,0.0
68,PCNA_1,0.0
68,pAUR,0.0
68,CDKN1B_1,0.0
68,CCND1,0.0
68,cPARP,0.0
68,CDKN1B_2,0.0
68,pCREB,0.0
68,CCNB1,0.0
68,CCNE,0.0
68,PCNA_2,3487.7142857142853
68,CDK2,0.0
68,CDKN2A,0.0
1,Rabbit IgG,0.0
1,Goat IgG,0.0
1,Mouse IgG,0.0
1,CD73,0.0
1,CD107B,0.0
1,MART1,0.0
1,KI67,0.0
1,pan-CK,0.0
1,CD45,0.0
1,ECAD,0.0
1,aSMA,0.0
1,CD56,0.0
1,CD13,0.0
1,CD63,0.0
1,CD32,0.0
1,CDKN1A,0.0
1,CCNA2,0.0
1,CDKN1C,0.0
1,PCNA_1,0.0
1,pAUR,0.0
1,CDKN1B_1,0.0
1,CCND1,0.0
1,cPARP,0.0
1,CDKN1B_2,0.0
1,pCREB,0.0
1,CCNB1,0.0
1,CCNE,0.0
1,PCNA_2,0.0
1,CDK2,0.0
1,CDKN2A,0.0
18,Rabbit IgG,2666.8921052631576
18,Goat IgG,0.0
18,Mouse IgG,0.0
18,CD73,0.0
18,CD107B,0.0
18,MART1,0.0
18,KI67,0.0
18,pan-CK,0.0
18,CD45,0.0
18,ECAD,0.0
18,aSMA,0.0
18,CD56,0.0
18,CD13,578.2247191011238
18,CD63,0.0
18,CD32,0.0
18,CDKN1A,0.0
18,CCNA2,0.0
18,CDKN1C,0.0
18,PCNA_1,0.0
18,pAUR,0.0
18,CDKN1B_1,0.0
18,CCND1,0.0
18,cPARP,0.0
18,CDKN1B_2,0.0
18,pCREB,0.0
18,CCNB1,0.0
18,CCNE,0.0
18,PCNA_2,0.0
18,CDK2,0.0
18,CDKN2A,0.0
15,Rabbit IgG,0.0
15,Goat IgG,3723.361515151514
15,Mouse IgG,3703.99125
15,CD73,1577.505063291139
15,CD107B,0.0
15,MART1,0.0
15,KI67,0.0
15,pan-CK,0.0
15,CD45,0.0
15,ECAD,0.0
15,aSMA,0.0
15,CD56,0.0
15,CD13,0.0
15,CD63,0.0
15,CD32,0.0
15,CDKN1A,821.3441860465116
15,CCNA2,0.0
15,CDKN1C,0.0
15,PCNA_1,0.0
15,pAUR,0.0
15,CDKN1B_1,0.0
15,CCND1,0.0
15,cPARP,0.0
15,CDKN1B_2,0.0
15,pCREB,0.0
15,CCNB1,0.0
15,CCNE,0.0
15,PCNA_2,0.0
15,CDK2,0.0
15,CDKN2A,0.0
6 changes: 6 additions & 0 deletions scratch
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# gates should be a dataframe where
# Column 1 is sample_id
# Column 2 is marker_id
# Column 3 is gate #default just gate
# if extra gates desired, Columns 4... are gate_1, gate_2, etc

19 changes: 18 additions & 1 deletion src/cell_gater/model/data_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import pandas as pd
from napari.utils.events import EmitterGroup, Event


@dataclass
class DataModel:
"""Model containing all necessary fields for gating."""
Expand All @@ -33,6 +32,24 @@ class DataModel:
_gates: pd.DataFrame = field(default_factory=pd.DataFrame, init=False)
_current_gate: float = field(default_factory=float, init=False)

@property
def gates(self):
"""The gates dataframe."""
return self._gates

@gates.setter
def gates(self, gates: pd.DataFrame) -> None:
self._gates = gates

@property
def current_gate(self) -> float:
"""The current gate value."""
return self._current_gate

@current_gate.setter
def current_gate(self, value: float) -> None:
self._current_gate = value

def __post_init__(self) -> None:
"""Allow fields in the dataclass to emit events when changed."""
self.events = EmitterGroup(source=self, samples=Event, regionprops_df=Event, validated=Event)
Expand Down
2 changes: 1 addition & 1 deletion src/cell_gater/utils/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@

def napari_notification(msg, severity=NotificationSeverity.INFO):
notification_ = Notification(msg, severity=severity)
notification_manager.dispatch(notification_)
notification_manager.dispatch(notification_)
34 changes: 23 additions & 11 deletions src/cell_gater/widgets/sample_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
from cell_gater.utils.misc import napari_notification
from cell_gater.widgets.scatter_widget import ScatterInputWidget


class SampleWidget(QWidget):
"""Sample widget for loading required data."""

Expand Down Expand Up @@ -53,35 +52,35 @@ def __init__(self, viewer: Viewer, model: DataModel | None = None) -> None:
# Open sample directory dialog
self.load_samples_button = QPushButton("Load regionprops dir")
self.load_samples_button.clicked.connect(self._open_sample_dialog)
self.layout().addWidget(self.load_samples_button, 1, 0)
self.layout().addWidget(self.load_samples_button, 0, 1)

# Open image directory dialog
self.load_image_dir_button = QPushButton("Load image dir")
self.load_image_dir_button.clicked.connect(self._open_image_dir_dialog)
self.layout().addWidget(self.load_image_dir_button, 1, 1)
self.layout().addWidget(self.load_image_dir_button, 0, 2)

# Open mask directory dialog
self.load_mask_dir_button = QPushButton("Load mask dir")
self.load_mask_dir_button.clicked.connect(self._open_mask_dir_dialog)
self.layout().addWidget(self.load_mask_dir_button, 1, 2)
self.layout().addWidget(self.load_mask_dir_button, 0, 3)

# The lower bound marker column dropdown
lower_col = QLabel("Select lowerbound marker column:")
self.lower_bound_marker_col = QComboBox()
if len(self.model.regionprops_df) > 0:
self.lower_bound_marker_col.addItems([None] + self.model.regionprops_df.columns)
self.lower_bound_marker_col.currentTextChanged.connect(self._update_model_lowerbound)
self.layout().addWidget(lower_col, 2, 0)
self.layout().addWidget(self.lower_bound_marker_col, 3, 0)
self.layout().addWidget(lower_col, 1, 0, 1, 2)
self.layout().addWidget(self.lower_bound_marker_col, 1, 2, 1, 2)

# The upper bound marker column dropdown
upper_col = QLabel("Select upperbound marker column:")
self.upper_bound_marker_col = QComboBox()
if len(self.model.regionprops_df) > 0:
self.upper_bound_marker_col.addItems([None] + self.model.regionprops_df.columns)
self.upper_bound_marker_col.currentTextChanged.connect(self._update_model_upperbound)
self.layout().addWidget(upper_col, 2, 1)
self.layout().addWidget(self.upper_bound_marker_col, 3, 1)
self.layout().addWidget(upper_col, 2, 0, 1, 2)
self.layout().addWidget(self.upper_bound_marker_col, 2, 2, 1, 2)

# Filter field for user to pass on strings to filter markers out.
filter_label = QLabel("Remove markers with prefix (default: DNA,DAPI)")
Expand All @@ -90,16 +89,21 @@ def __init__(self, viewer: Viewer, model: DataModel | None = None) -> None:
placeholderText="Prefixes separated by commas.",
)
self.filter_field.editingFinished.connect(self._update_filter)
self.layout().addWidget(filter_label, 4, 0)
self.layout().addWidget(self.filter_field, 5, 0)
self.layout().addWidget(filter_label, 3, 0, 1 ,2)
self.layout().addWidget(self.filter_field, 3, 3)

# Button to start validating all the input
self.validate_button = QPushButton("Validate input")
self.validate_button.clicked.connect(self._validate)
self.layout().addWidget(self.validate_button, 6, 0)
self.layout().addWidget(self.validate_button, 4, 0, 1, 4)

self.model.events.regionprops_df.connect(self._set_dropdown_marker_lowerbound)
self.model.events.regionprops_df.connect(self._set_dropdown_marker_upperbound)

#set default bounds




@property
def viewer(self) -> Viewer:
Expand Down Expand Up @@ -176,6 +180,7 @@ def _set_dropdown_marker_lowerbound(self):
region_props = self.model.regionprops_df
if region_props is not None and len(region_props) > 0:
self.lower_bound_marker_col.addItems(region_props.columns)
self.lower_bound_marker_col.setCurrentIndex(1) # Skip the cell id column

def _set_dropdown_marker_upperbound(self):
"""Add items to dropdown menu for upperbound marker.
Expand All @@ -187,6 +192,13 @@ def _set_dropdown_marker_upperbound(self):
region_props = self.model.regionprops_df
if region_props is not None and len(region_props) > 0:
self.upper_bound_marker_col.addItems(region_props.columns)

#TODO set default to column before "X_centroid"
# This does not work
# if "X_centroid" in list(self.model.regionprops_df.columns):
# self.upper_bound_marker_col.setCurrentIndex(
# self.model.regionprops_df.columns.index("X_centroid")-1 )


def _update_model_lowerbound(self):
"""Update the lowerbound marker in the data model upon change of text in the lowerbound marker column widget."""
Expand Down
Loading

0 comments on commit 14ac7f6

Please sign in to comment.