diff --git a/protzilla/data_preprocessing/imputation.py b/protzilla/data_preprocessing/imputation.py index 48af773b..ece7e4fb 100644 --- a/protzilla/data_preprocessing/imputation.py +++ b/protzilla/data_preprocessing/imputation.py @@ -359,6 +359,7 @@ def by_knn_plot( graph_type_quantities, group_by, visual_transformation, + proteins_of_interest=None, ): return _build_box_hist_plot( method_inputs["protein_df"], @@ -367,6 +368,7 @@ def by_knn_plot( graph_type_quantities, group_by, visual_transformation, + [] if proteins_of_interest is None else proteins_of_interest, ) @@ -377,6 +379,7 @@ def by_normal_distribution_sampling_plot( graph_type_quantities, group_by, visual_transformation, + proteins_of_interest=None, ): return _build_box_hist_plot( method_inputs["protein_df"], @@ -385,6 +388,7 @@ def by_normal_distribution_sampling_plot( graph_type_quantities, group_by, visual_transformation, + [] if proteins_of_interest is None else proteins_of_interest, ) @@ -395,6 +399,7 @@ def by_simple_imputer_plot( graph_type_quantities, group_by, visual_transformation, + proteins_of_interest=None, ): return _build_box_hist_plot( method_inputs["protein_df"], @@ -403,6 +408,7 @@ def by_simple_imputer_plot( graph_type_quantities, group_by, visual_transformation, + [] if proteins_of_interest is None else proteins_of_interest, ) @@ -413,6 +419,7 @@ def by_min_per_sample_plot( graph_type_quantities, group_by, visual_transformation, + proteins_of_interest=None, ): return _build_box_hist_plot( method_inputs["protein_df"], @@ -421,6 +428,7 @@ def by_min_per_sample_plot( graph_type_quantities, group_by, visual_transformation, + [] if proteins_of_interest is None else proteins_of_interest, ) @@ -431,6 +439,7 @@ def by_min_per_protein_plot( graph_type_quantities, group_by, visual_transformation, + proteins_of_interest=None, ): return _build_box_hist_plot( method_inputs["protein_df"], @@ -439,6 +448,7 @@ def by_min_per_protein_plot( graph_type_quantities, group_by, visual_transformation, + [] if proteins_of_interest is None else proteins_of_interest, ) @@ -449,6 +459,7 @@ def by_min_per_dataset_plot( graph_type_quantities, group_by, visual_transformation, + proteins_of_interest=None, ): return _build_box_hist_plot( method_inputs["protein_df"], @@ -457,6 +468,7 @@ def by_min_per_dataset_plot( graph_type_quantities, group_by, visual_transformation, + [] if proteins_of_interest is None else proteins_of_interest, ) @@ -471,6 +483,7 @@ def _build_box_hist_plot( graph_type_quantities: str = "Pie chart", group_by: str = "None", visual_transformation: str = "linear", + proteins_of_interest= None, ) -> list[Figure]: """ This function creates two visualisations: @@ -506,6 +519,7 @@ def _build_box_hist_plot( heading="Distribution of Protein Intensities", group_by=group_by, visual_transformation=visual_transformation, + proteins_of_interest=proteins_of_interest, y_title="Intensity", ) elif graph_type == "Histogram": diff --git a/protzilla/data_preprocessing/normalisation.py b/protzilla/data_preprocessing/normalisation.py index e2be755b..62ffbcb8 100644 --- a/protzilla/data_preprocessing/normalisation.py +++ b/protzilla/data_preprocessing/normalisation.py @@ -233,14 +233,16 @@ def by_z_score_plot( method_outputs, graph_type, group_by, - visual_transformation + visual_transformation, + proteins_of_interest=None, ): return _build_box_hist_plot( method_inputs["protein_df"], method_outputs["protein_df"], graph_type, group_by, - visual_transformation + visual_transformation, + [] if proteins_of_interest is None else proteins_of_interest, ) @@ -249,13 +251,15 @@ def by_median_plot( method_outputs, graph_type, group_by, - visual_transformation + visual_transformation, + proteins_of_interest=None, ): return _build_box_hist_plot( method_inputs["protein_df"], method_outputs["protein_df"], graph_type, group_by, - visual_transformation + visual_transformation, + [] if proteins_of_interest is None else proteins_of_interest, ) @@ -264,13 +268,15 @@ def by_totalsum_plot( method_outputs, graph_type, group_by, - visual_transformation + visual_transformation, + proteins_of_interest=None, ): return _build_box_hist_plot( method_inputs["protein_df"], method_outputs["protein_df"], graph_type, group_by, - visual_transformation + visual_transformation, + [] if proteins_of_interest is None else proteins_of_interest, ) @@ -279,18 +285,20 @@ def by_reference_protein_plot( method_outputs, graph_type, group_by, - visual_transformation + visual_transformation, + proteins_of_interest=None, ): return _build_box_hist_plot( method_inputs["protein_df"], method_outputs["protein_df"], graph_type, group_by, - visual_transformation + visual_transformation, + [] if proteins_of_interest is None else proteins_of_interest, ) -def _build_box_hist_plot(df, result_df, graph_type, group_by, visual_transformation): +def _build_box_hist_plot(df, result_df, graph_type, group_by, visual_transformation, proteins_of_interest=None): if graph_type == "Boxplot": fig = create_box_plots( dataframe_a=df, @@ -302,6 +310,7 @@ def _build_box_hist_plot(df, result_df, graph_type, group_by, visual_transformat y_title="Intensity", group_by=group_by, visual_transformation=visual_transformation, + proteins_of_interest=proteins_of_interest, ) if graph_type == "Histogram": fig = create_histograms( diff --git a/protzilla/data_preprocessing/plots.py b/protzilla/data_preprocessing/plots.py index 6215f5c9..f9d95b48 100644 --- a/protzilla/data_preprocessing/plots.py +++ b/protzilla/data_preprocessing/plots.py @@ -55,7 +55,7 @@ def create_bar_plot( names_of_sectors: "list[str]", values_of_sectors: "list[int]", heading: str = "", - colour: "list[str]" = PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE, + color: "list[str]" = PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE, y_title: str = "", x_title: str = "", ) -> Figure: @@ -76,7 +76,7 @@ def create_bar_plot( fig = px.bar( x=names_of_sectors, y=values_of_sectors, - color=colour[: len(values_of_sectors)], + color=color[: len(values_of_sectors)], color_discrete_map="identity", ) @@ -110,6 +110,7 @@ def create_box_plots( y_title: str = "", x_title: str = "", group_by: str = "None", + proteins_of_interest=None, visual_transformation: str = "linear", ) -> Figure: """ @@ -129,6 +130,7 @@ def create_box_plots( :param y_title: Optional y-axis title for graphs. :param x_title: Optional x-axis title for graphs. :param group_by: Optional argument to create a grouped boxplot\ + :param proteins_of_interest: List of proteins to be included in the boxplot :param visual_transformation: Visual transformation of the y-axis data. graph. Arguments can be either "Sample" to group by sample or\ "Protein ID" to group by protein. Leave "None" to get ungrouped\ @@ -141,19 +143,29 @@ def create_box_plots( f"""Group_by parameter must be "None" or "Sample" or "Protein ID" but is {group_by}""" ) - intensity_name_a = default_intensity_column(dataframe_a) - intensity_name_b = default_intensity_column(dataframe_b) + if len(proteins_of_interest) == 0: + proteins_of_interest = dataframe_a["Protein ID"] + elif isinstance(proteins_of_interest, str): + proteins_of_interest = [proteins_of_interest] + + filtered_df = dataframe_a[dataframe_a["Protein ID"].isin(proteins_of_interest)] + filtered_result_df = dataframe_b[ + dataframe_b["Protein ID"].isin(proteins_of_interest) + ] + intensity_name_a = default_intensity_column(filtered_df) + intensity_name_b = default_intensity_column(filtered_result_df) + if group_by in {"Sample", "Protein ID"}: fig = make_subplots(rows=1, cols=2) trace0 = go.Box( - y=dataframe_a[intensity_name_a], - x=dataframe_a[group_by], + y=filtered_df[intensity_name_a], + x=filtered_df[group_by], marker_color=PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE[0], name=name_a, ) trace1 = go.Box( - y=dataframe_b[intensity_name_b], - x=dataframe_b[group_by], + y=filtered_result_df[intensity_name_b], + x=filtered_result_df[group_by], marker_color=PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE[1], name=name_b, ) @@ -164,12 +176,12 @@ def create_box_plots( elif group_by == "None": fig = make_subplots(rows=1, cols=2) trace0 = go.Box( - y=dataframe_a[intensity_name_a], + y=filtered_df[intensity_name_a], marker_color=PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE[0], name=name_a, ) trace1 = go.Box( - y=dataframe_b[intensity_name_b], + y=filtered_result_df[intensity_name_b], marker_color=PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE[1], name=name_b, ) @@ -208,6 +220,7 @@ def create_histograms( heading: str = "", y_title: str = "", x_title: str = "", + proteins_of_interest=None, visual_transformation: str = "linear", overlay: bool = False, ) -> Figure: diff --git a/protzilla/data_preprocessing/transformation.py b/protzilla/data_preprocessing/transformation.py index 221b01ab..c0c062f9 100644 --- a/protzilla/data_preprocessing/transformation.py +++ b/protzilla/data_preprocessing/transformation.py @@ -44,13 +44,28 @@ def by_log(protein_df: pd.DataFrame, peptide_df: pd.DataFrame | None, log_base=" return dict(protein_df=transformed_df, peptide_df=transformed_peptide_df) -def by_log_plot(method_inputs, method_outputs, graph_type, group_by): +def by_log_plot( + method_inputs, + method_outputs, + graph_type, + group_by, + proteins_of_interest=None, +): return _build_box_hist_plot( - method_inputs["protein_df"], method_outputs["protein_df"], graph_type, group_by + method_inputs["protein_df"], + method_outputs["protein_df"], + graph_type, + group_by, + [] if proteins_of_interest is None else proteins_of_interest, ) - -def _build_box_hist_plot(df, result_df, graph_type, group_by): +def _build_box_hist_plot( + df, + result_df, + graph_type, + group_by, + proteins_of_interest=None, +): if graph_type == "Boxplot": fig = create_box_plots( dataframe_a=df, @@ -59,6 +74,7 @@ def _build_box_hist_plot(df, result_df, graph_type, group_by): name_b="After Transformation", heading="Distribution of Protein Intensities", group_by=group_by, + proteins_of_interest=proteins_of_interest, y_title="Intensity", ) if graph_type == "Histogram": @@ -68,6 +84,7 @@ def _build_box_hist_plot(df, result_df, graph_type, group_by): name_a="Before Transformation", name_b="After Transformation", heading="Distribution of Protein Intensities", + proteins_of_interest=proteins_of_interest, x_title="Protein Intensities", y_title="Frequency of Protein Intensities", ) diff --git a/protzilla/steps.py b/protzilla/steps.py index ad898d9e..5fe78207 100644 --- a/protzilla/steps.py +++ b/protzilla/steps.py @@ -661,7 +661,7 @@ def _clear_future_steps(self, index: int | None = None) -> None: index = self.current_step_index if index == len(self.all_steps) - 1: return - for step in self.all_steps[index + 1 :]: + for step in self.all_steps[index:]: step.output = Output() step.messages = Messages() step.plots = Plots() diff --git a/tests/protzilla/data_preprocessing/test_imputation.py b/tests/protzilla/data_preprocessing/test_imputation.py index 93953095..55015d2e 100644 --- a/tests/protzilla/data_preprocessing/test_imputation.py +++ b/tests/protzilla/data_preprocessing/test_imputation.py @@ -165,6 +165,7 @@ def test_imputation_min_value_per_df( "Bar chart", "Sample", "linear", + [], ) if show_figures: fig1.show() @@ -200,6 +201,7 @@ def test_imputation_min_value_per_sample( "Bar chart", "Sample", "linear", + [], ) if show_figures: fig1.show() @@ -235,6 +237,7 @@ def test_imputation_min_value_per_protein( "Bar chart", "Sample", "linear", + [], ) if show_figures: fig1.show() @@ -270,6 +273,7 @@ def test_imputation_mean_per_protein( "Bar chart", "Sample", "linear", + [], ) if show_figures: fig1.show() @@ -303,6 +307,7 @@ def test_imputation_knn(show_figures, input_imputation_df, assertion_df_knn): "Bar chart", "Sample", "linear", + [], ) if show_figures: fig1.show() @@ -345,6 +350,7 @@ def test_imputation_normal_distribution_sampling(show_figures, input_imputation_ "Bar chart", "Sample", "linear", + [], ) if show_figures: fig1.show() diff --git a/tests/protzilla/data_preprocessing/test_normalisation.py b/tests/protzilla/data_preprocessing/test_normalisation.py index 8e5c2a45..4b6a26cf 100644 --- a/tests/protzilla/data_preprocessing/test_normalisation.py +++ b/tests/protzilla/data_preprocessing/test_normalisation.py @@ -305,7 +305,7 @@ def test_normalisation_by_z_score( method_input = {"protein_df": normalisation_df} method_outputs = by_z_score(**method_input) - fig = by_z_score_plot(method_input, method_outputs, "Boxplot", "Sample", "log10")[0] + fig = by_z_score_plot(method_input, method_outputs, "Boxplot", "Sample", "log10", [],)[0] if show_figures: fig.show() @@ -323,7 +323,7 @@ def test_normalisation_by_median( method_inputs = {"protein_df": normalisation_df} method_outputs = by_median(**method_inputs) - fig = by_median_plot(method_inputs, method_outputs, "Boxplot", "Sample", "log10")[0] + fig = by_median_plot(method_inputs, method_outputs, "Boxplot", "Sample", "log10", [])[0] if show_figures: fig.show() @@ -349,7 +349,7 @@ def test_totalsum_normalisation( method_inputs = {"protein_df": normalisation_df} method_outputs = by_totalsum(**method_inputs) - fig = by_totalsum_plot(method_inputs, method_outputs, "Boxplot", "Sample", "log10")[0] + fig = by_totalsum_plot(method_inputs, method_outputs, "Boxplot", "Sample", "log10", [])[0] if show_figures: fig.show() @@ -376,9 +376,7 @@ def test_ref_protein_normalisation( } method_outputs = by_reference_protein(**method_input) - fig = by_reference_protein_plot(method_input, method_outputs, "Boxplot", "Sample", "log10")[ - 0 - ] + fig = by_reference_protein_plot(method_input, method_outputs, "Boxplot", "Sample","log10", [])[0] if show_figures: fig.show() diff --git a/tests/protzilla/data_preprocessing/test_plots_data_preprocessing.py b/tests/protzilla/data_preprocessing/test_plots_data_preprocessing.py index 4aaabb0e..ae9cf1bb 100644 --- a/tests/protzilla/data_preprocessing/test_plots_data_preprocessing.py +++ b/tests/protzilla/data_preprocessing/test_plots_data_preprocessing.py @@ -51,6 +51,7 @@ def test_create_box_plots( name_b="After Transformation", heading="Distribution of Protein Intensities", group_by="None", + proteins_of_interest=[], ) if show_figures: fig.show() @@ -120,6 +121,7 @@ def test_build_box_hist_plot( "Bar chart", "Sample", "linear", + [], ) fig3, fig4 = imputation._build_box_hist_plot( input_imputation_df, @@ -128,6 +130,7 @@ def test_build_box_hist_plot( "Pie chart", "Protein ID", "linear", + [], ) if show_figures: diff --git a/tests/protzilla/data_preprocessing/test_transformation.py b/tests/protzilla/data_preprocessing/test_transformation.py index 09827157..fb991d9f 100644 --- a/tests/protzilla/data_preprocessing/test_transformation.py +++ b/tests/protzilla/data_preprocessing/test_transformation.py @@ -185,7 +185,7 @@ def test_log2_transformation( } method_outputs = by_log(**method_inputs) - fig = by_log_plot(method_inputs, method_outputs, "Boxplot", "Protein ID")[0] + fig = by_log_plot(method_inputs, method_outputs, "Boxplot", "Protein ID", [])[0] if show_figures: fig.show() @@ -222,6 +222,7 @@ def test_log10_transformation( method_output, "Boxplot", "Protein ID", + [] )[0] if show_figures: fig.show() @@ -242,7 +243,9 @@ def test_log10_transformation( @pytest.mark.parametrize("log_base", ["log2", "log10"]) def test_by_log_without_peptide_df(log2_transformation_df, log_base): - method_outputs = by_log(log2_transformation_df, None, log_base=log_base) + method_outputs = by_log( + log2_transformation_df, None, log_base=log_base + ) assert ( method_outputs["peptide_df"] is None diff --git a/ui/runs/form_mapping.py b/ui/runs/form_mapping.py index ab27a219..76ba3be6 100644 --- a/ui/runs/form_mapping.py +++ b/ui/runs/form_mapping.py @@ -79,6 +79,9 @@ data_preprocessing.FilterByProteinsCount: data_preprocessing_forms.FilterByProteinsCountPlotForm, data_preprocessing.FilterSamplesByProteinsMissing: data_preprocessing_forms.FilterSamplesByProteinsMissingPlotForm, data_preprocessing.FilterSamplesByProteinIntensitiesSum: data_preprocessing_forms.FilterSamplesByProteinIntensitiesSumPlotForm, + data_preprocessing.OutlierDetectionByLocalOutlierFactor: data_preprocessing_forms.OutlierDetectionByLocalOutlierFactorPlotForm, + data_preprocessing.OutlierDetectionByIsolationForest: data_preprocessing_forms.OutlierDetectionByIsolationForestPlotForm, + data_preprocessing.OutlierDetectionByPCA: data_preprocessing_forms.OutlierDetectionByPCAPlotForm, data_preprocessing.TransformationLog: data_preprocessing_forms.TransformationLogPlotForm, data_preprocessing.NormalisationByZScore: data_preprocessing_forms.NormalisationByZscorePlotForm, data_preprocessing.NormalisationByTotalSum: data_preprocessing_forms.NormalisationByTotalSumPlotForm, @@ -159,6 +162,12 @@ def get_filled_form_by_method( ) +def get_filled_plot_form_by_request(request: HttpRequest, run: Run) -> MethodForm: + form_class = _get_plot_form_class_by_step(run.current_step) + return form_class(run=run, data=request.POST, files=request.FILES) + + +# TODO accomodate the plot form def get_filled_form_by_request(request: HttpRequest, run: Run) -> MethodForm: form_class = _get_form_class_by_step(run.current_step) return form_class(run=run, data=request.POST, files=request.FILES) diff --git a/ui/runs/forms/base.py b/ui/runs/forms/base.py index ba6b9385..77526fe6 100644 --- a/ui/runs/forms/base.py +++ b/ui/runs/forms/base.py @@ -98,3 +98,15 @@ def submit(self, run: Run) -> None: self.fields[field_name] = field self.cleaned_data[field_name] = None run.step_calculate(self.cleaned_data) + + +class PlotForm(MethodForm): + def __init__(self, run: Run, *args, **kwargs) -> None: + super().__init__(run, *args, **kwargs) + + def submit(self, run: Run) -> None: + for field_name, field in self.initial_fields.items(): + if field_name not in self.fields: + self.fields[field_name] = field + self.cleaned_data[field_name] = None + run.current_step.plot(self.cleaned_data) diff --git a/ui/runs/forms/custom_fields.py b/ui/runs/forms/custom_fields.py index 7171f173..0c51f6d2 100644 --- a/ui/runs/forms/custom_fields.py +++ b/ui/runs/forms/custom_fields.py @@ -85,6 +85,8 @@ def __init__(self, choices: Enum | list, initial=None, *args, **kwargs): self.widget.attrs.update({"class": "form-select mb-2"}) def clean(self, value: list[str] | None): + if not isinstance(value, list): + value = [value] return [el for el in value if el != "hidden"] if value else None diff --git a/ui/runs/forms/data_preprocessing.py b/ui/runs/forms/data_preprocessing.py index 08590b79..98badded 100644 --- a/ui/runs/forms/data_preprocessing.py +++ b/ui/runs/forms/data_preprocessing.py @@ -1,10 +1,14 @@ from enum import Enum -from .base import MethodForm +from protzilla.run_v2 import Run + +from . import fill_helper +from .base import MethodForm, PlotForm from .custom_fields import ( CustomCharField, CustomChoiceField, CustomFloatField, + CustomMultipleChoiceField, CustomNumberField, ) @@ -65,7 +69,7 @@ class FilterProteinsBySamplesMissingForm(MethodForm): ) -class FilterProteinsBySamplesMissingPlotForm(MethodForm): +class FilterProteinsBySamplesMissingPlotForm(PlotForm): graph_type = CustomChoiceField( choices=BarAndPieChart, label="Graph type", @@ -81,7 +85,7 @@ class FilterByProteinsCountForm(MethodForm): ) -class FilterByProteinsCountPlotForm(MethodForm): +class FilterByProteinsCountPlotForm(PlotForm): graph_type = CustomChoiceField( choices=BarAndPieChart, label="Graph type", @@ -99,7 +103,7 @@ class FilterSamplesByProteinsMissingForm(MethodForm): ) -class FilterSamplesByProteinsMissingPlotForm(MethodForm): +class FilterSamplesByProteinsMissingPlotForm(PlotForm): graph_type = CustomChoiceField( choices=BarAndPieChart, label="Graph type", @@ -115,7 +119,7 @@ class FilterSamplesByProteinIntensitiesSumForm(MethodForm): ) -class FilterSamplesByProteinIntensitiesSumPlotForm(MethodForm): +class FilterSamplesByProteinIntensitiesSumPlotForm(PlotForm): graph_type = CustomChoiceField( choices=BarAndPieChart, label="Graph type", @@ -138,6 +142,10 @@ class OutlierDetectionByPCAForm(MethodForm): ) +class OutlierDetectionByPCAPlotForm(PlotForm): + pass + + class OutlierDetectionByIsolationForestForm(MethodForm): n_estimators = CustomNumberField( label="Number of estimators", @@ -147,6 +155,10 @@ class OutlierDetectionByIsolationForestForm(MethodForm): ) +class OutlierDetectionByIsolationForestPlotForm(PlotForm): + pass + + class OutlierDetectionByLocalOutlierFactorForm(MethodForm): number_of_neighbors = CustomNumberField( label="Number of neighbours", @@ -156,6 +168,10 @@ class OutlierDetectionByLocalOutlierFactorForm(MethodForm): ) +class OutlierDetectionByLocalOutlierFactorPlotForm(PlotForm): + pass + + class TransformationLogForm(MethodForm): log_base = CustomChoiceField( choices=LogTransformationBaseType, @@ -164,7 +180,7 @@ class TransformationLogForm(MethodForm): ) -class TransformationLogPlotForm(MethodForm): +class TransformationLogPlotForm(PlotForm): graph_type = CustomChoiceField( choices=BoxAndHistogramGraph, label="Graph type", @@ -173,13 +189,22 @@ class TransformationLogPlotForm(MethodForm): group_by = CustomChoiceField( choices=GroupBy, label="Group by", initial=GroupBy.no_grouping ) + proteins_of_interest = CustomMultipleChoiceField( + choices=[], + label="Proteins of interest (By default all proteins are selected)", + ) + + def fill_form(self, run: Run) -> None: + proteins = run.steps.protein_df["Protein ID"].unique() + + self.fields["proteins_of_interest"].choices = fill_helper.to_choices(proteins) class NormalisationByZScoreForm(MethodForm): pass -class NormalisationByZscorePlotForm(MethodForm): +class NormalisationByZscorePlotForm(PlotForm): graph_type = CustomChoiceField( choices=BoxAndHistogramGraph, label="Graph type", @@ -193,13 +218,22 @@ class NormalisationByZscorePlotForm(MethodForm): label="Visual transformation", initial=VisualTrasformations.log10, ) + proteins_of_interest = CustomMultipleChoiceField( + choices=[], + label="Proteins of interest (By default all proteins are selected)", + ) + + def fill_form(self, run: Run) -> None: + proteins = run.steps.protein_df["Protein ID"].unique() + + self.fields["proteins_of_interest"].choices = fill_helper.to_choices(proteins) class NormalisationByTotalSumForm(MethodForm): pass -class NormalisationByTotalSumPlotForm(MethodForm): +class NormalisationByTotalSumPlotForm(PlotForm): graph_type = CustomChoiceField( choices=BoxAndHistogramGraph, label="Graph type", @@ -213,6 +247,15 @@ class NormalisationByTotalSumPlotForm(MethodForm): label="Visual transformation", initial=VisualTrasformations.log10, ) + proteins_of_interest = CustomMultipleChoiceField( + choices=[], + label="Proteins of interest (By default all proteins are selected)", + ) + + def fill_form(self, run: Run) -> None: + proteins = run.steps.protein_df["Protein ID"].unique() + + self.fields["proteins_of_interest"].choices = fill_helper.to_choices(proteins) class NormalisationByMedianForm(MethodForm): @@ -225,7 +268,7 @@ class NormalisationByMedianForm(MethodForm): ) -class NormalisationByMedianPlotForm(MethodForm): +class NormalisationByMedianPlotForm(PlotForm): graph_type = CustomChoiceField( choices=BoxAndHistogramGraph, label="Graph type", @@ -239,6 +282,15 @@ class NormalisationByMedianPlotForm(MethodForm): label="Visual transformation", initial=VisualTrasformations.log10, ) + proteins_of_interest = CustomMultipleChoiceField( + choices=[], + label="Proteins of interest (By default all proteins are selected)", + ) + + def fill_form(self, run: Run) -> None: + proteins = run.steps.protein_df["Protein ID"].unique() + + self.fields["proteins_of_interest"].choices = fill_helper.to_choices(proteins) class NormalisationByReferenceProteinForms(MethodForm): @@ -256,7 +308,7 @@ class NormalisationByReferenceProteinForms(MethodForm): ) -class NormalisationByReferenceProteinPlotForm(MethodForm): +class NormalisationByReferenceProteinPlotForm(PlotForm): graph_type = CustomChoiceField( choices=BoxAndHistogramGraph, label="Graph type", @@ -270,6 +322,15 @@ class NormalisationByReferenceProteinPlotForm(MethodForm): label="Visual transformation", initial=VisualTrasformations.log10, ) + proteins_of_interest = CustomMultipleChoiceField( + choices=[], + label="Proteins of interest (By default all proteins are selected)", + ) + + def fill_form(self, run: Run) -> None: + proteins = run.steps.protein_df["Protein ID"].unique() + + self.fields["proteins_of_interest"].choices = fill_helper.to_choices(proteins) class ImputationByMinPerDatasetForm(MethodForm): @@ -285,7 +346,7 @@ class ImputationByMinPerDatasetForm(MethodForm): ) -class ImputationByMinPerDatasetPlotForm(MethodForm): +class ImputationByMinPerDatasetPlotForm(PlotForm): graph_type = CustomChoiceField( choices=BoxAndHistogramGraph, label="Graph type", @@ -299,12 +360,21 @@ class ImputationByMinPerDatasetPlotForm(MethodForm): label="Visual transformation", initial=VisualTrasformations.log10, ) + proteins_of_interest = CustomMultipleChoiceField( + choices=[], + label="Proteins of interest (By default all proteins are selected)", + ) graph_type_quantities = CustomChoiceField( choices=BarAndPieChart, label="Graph type - quantity of imputed values", initial=BarAndPieChart.pie_chart, ) + def fill_form(self, run: Run) -> None: + proteins = run.steps.protein_df["Protein ID"].unique() + + self.fields["proteins_of_interest"].choices = fill_helper.to_choices(proteins) + class ImputationByMinPerProteinForm(MethodForm): shrinking_value = CustomFloatField( @@ -319,7 +389,7 @@ class ImputationByMinPerProteinForm(MethodForm): ) -class ImputationByMinPerProteinPlotForm(MethodForm): +class ImputationByMinPerProteinPlotForm(PlotForm): graph_type = CustomChoiceField( choices=BoxAndHistogramGraph, label="Graph type", @@ -333,12 +403,20 @@ class ImputationByMinPerProteinPlotForm(MethodForm): label="Visual transformation", initial=VisualTrasformations.log10, ) + proteins_of_interest = CustomMultipleChoiceField( + choices=[], + label="Proteins of interest (By default all proteins are selected)", + ) graph_type_quantities = CustomChoiceField( choices=BarAndPieChart, label="Graph type - quantity of imputed values", initial=BarAndPieChart.pie_chart, ) + def fill_form(self, run: Run) -> None: + proteins = run.steps.protein_df["Protein ID"].unique() + + self.fields["proteins_of_interest"].choices = fill_helper.to_choices(proteins) class ImputationByMinPerSampleForms(MethodForm): shrinking_value = CustomFloatField( @@ -350,7 +428,7 @@ class ImputationByMinPerSampleForms(MethodForm): ) -class ImputationByMinPerSamplePlotForm(MethodForm): +class ImputationByMinPerSamplePlotForm(PlotForm): graph_type = CustomChoiceField( choices=BoxAndHistogramGraph, label="Graph type", @@ -364,12 +442,21 @@ class ImputationByMinPerSamplePlotForm(MethodForm): label="Visual transformation", initial=VisualTrasformations.log10, ) + proteins_of_interest = CustomMultipleChoiceField( + choices=[], + label="Proteins of interest (By default all proteins are selected)", + ) graph_type_quantities = CustomChoiceField( choices=BarAndPieChart, label="Graph type - quantity of imputed values", initial=BarAndPieChart.pie_chart, ) + def fill_form(self, run: Run) -> None: + proteins = run.steps.protein_df["Protein ID"].unique() + + self.fields["proteins_of_interest"].choices = fill_helper.to_choices(proteins) + class SimpleImputationPerProteinForm(MethodForm): strategy = CustomChoiceField( @@ -379,7 +466,7 @@ class SimpleImputationPerProteinForm(MethodForm): ) -class SimpleImputationPerProteinPlotForm(MethodForm): +class SimpleImputationPerProteinPlotForm(PlotForm): graph_type = CustomChoiceField( choices=BoxAndHistogramGraph, label="Graph type", @@ -393,12 +480,21 @@ class SimpleImputationPerProteinPlotForm(MethodForm): label="Visual transformation", initial=VisualTrasformations.log10, ) + proteins_of_interest = CustomMultipleChoiceField( + choices=[], + label="Proteins of interest (By default all proteins are selected)", + ) graph_type_quantities = CustomChoiceField( choices=BarAndPieChart, label="Graph type - quantity of imputed values", initial=BarAndPieChart.pie_chart, ) + def fill_form(self, run: Run) -> None: + proteins = run.steps.protein_df["Protein ID"].unique() + + self.fields["proteins_of_interest"].choices = fill_helper.to_choices(proteins) + class ImputationByKNNForms(MethodForm): number_of_neighbours = CustomNumberField( @@ -409,7 +505,7 @@ class ImputationByKNNForms(MethodForm): ) -class ImputationByKNNPlotForm(MethodForm): +class ImputationByKNNPlotForm(PlotForm): graph_type = CustomChoiceField( choices=BoxAndHistogramGraph, label="Graph type", @@ -423,12 +519,21 @@ class ImputationByKNNPlotForm(MethodForm): label="Visual transformation", initial=VisualTrasformations.log10, ) + proteins_of_interest = CustomMultipleChoiceField( + choices=[], + label="Proteins of interest (By default all proteins are selected)", + ) graph_type_quantities = CustomChoiceField( choices=BarAndPieChart, label="Graph type - quantity of imputed values", initial=BarAndPieChart.pie_chart, ) + def fill_form(self, run: Run) -> None: + proteins = run.steps.protein_df["Protein ID"].unique() + + self.fields["proteins_of_interest"].choices = fill_helper.to_choices(proteins) + class ImputationByNormalDistributionSamplingForm(MethodForm): strategy = CustomChoiceField( @@ -444,7 +549,7 @@ class ImputationByNormalDistributionSamplingForm(MethodForm): ) -class ImputationByNormalDistributionSamplingPlotForm(MethodForm): +class ImputationByNormalDistributionSamplingPlotForm(PlotForm): graph_type = CustomChoiceField( choices=BoxAndHistogramGraph, label="Graph type", @@ -458,12 +563,24 @@ class ImputationByNormalDistributionSamplingPlotForm(MethodForm): label="Visual transformation", initial=VisualTrasformations.log10, ) + proteins_of_interest = CustomMultipleChoiceField( + choices=[], + label="Proteins of interest (will be highlighted)", + ) + proteins_of_interest = CustomMultipleChoiceField( + choices=[], + label="Proteins of interest (By default all proteins are selected)", + ) graph_type_quantities = CustomChoiceField( choices=BarAndPieChart, label="Graph type - quantity of imputed values", initial=BarAndPieChart.pie_chart, ) + def fill_form(self, run: Run) -> None: + proteins = run.steps.protein_df["Protein ID"].unique() + + self.fields["proteins_of_interest"].choices = fill_helper.to_choices(proteins) class FilterPeptidesByPEPThresholdForm(MethodForm): threshold = CustomFloatField( @@ -472,7 +589,7 @@ class FilterPeptidesByPEPThresholdForm(MethodForm): peptide_df = CustomChoiceField(choices=EmptyEnum, label="peptide_df") -class FilterPeptidesByPEPThresholdPlotForm(MethodForm): +class FilterPeptidesByPEPThresholdPlotForm(PlotForm): graph_type = CustomChoiceField( choices=BarAndPieChart, label="Graph type", diff --git a/ui/runs/views.py b/ui/runs/views.py index 87aa685d..7649a0c5 100644 --- a/ui/runs/views.py +++ b/ui/runs/views.py @@ -35,12 +35,13 @@ make_name_field, make_sidebar, ) -from ui.runs.views_helper import display_message, display_messages, parameters_from_post +from ui.runs.views_helper import display_message, display_messages from .form_mapping import ( get_empty_plot_form_by_method, get_filled_form_by_method, get_filled_form_by_request, + get_filled_plot_form_by_request, ) active_runs: dict[str, Run] = {} @@ -284,13 +285,10 @@ def plot(request, run_name): :rtype: HttpResponse """ run = active_runs[run_name] - parameters = parameters_from_post(request.POST) - if run.current_step.display_name == "plot": - del parameters["chosen_method"] - run.step_calculate(parameters) - else: - run.current_step.plot(parameters) + plot_form = get_filled_plot_form_by_request(request, run) + if plot_form.is_valid(): + plot_form.submit(run) return HttpResponseRedirect(reverse("runs:detail", args=(run_name,)))