diff --git a/protzilla/constants/colors.py b/protzilla/constants/colors.py index eec08b1b..0c6600f7 100644 --- a/protzilla/constants/colors.py +++ b/protzilla/constants/colors.py @@ -1,8 +1,14 @@ -PROTZILLA_DISCRETE_COLOR_SEQUENCE = [ +PLOT_COLOR_SEQUENCE = [ "#4A536A", - "#87A8B9", "#CE5A5A", + "#87A8B9", "#8E3325", "#E2A46D", ] -PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE = ["#4A536A", "#CE5A5A"] +"""List of colors to use in plots.""" + +PLOT_PRIMARY_COLOR = PLOT_COLOR_SEQUENCE[0] +"""First color in list. Conventionally used for visualizing outliers.""" + +PLOT_SECONDARY_COLOR = PLOT_COLOR_SEQUENCE[1] +"""Second color in list.""" \ No newline at end of file diff --git a/protzilla/constants/paths.py b/protzilla/constants/paths.py index 6802d503..49364bda 100644 --- a/protzilla/constants/paths.py +++ b/protzilla/constants/paths.py @@ -1,8 +1,9 @@ from pathlib import Path PROJECT_PATH = Path(__file__).resolve().parent.parent.parent -RUNS_PATH = Path(PROJECT_PATH, "user_data/runs") -WORKFLOWS_PATH = Path(PROJECT_PATH, "user_data/workflows") +USER_DATA_PATH = Path(PROJECT_PATH, "user_data") +RUNS_PATH = USER_DATA_PATH / "runs" +WORKFLOWS_PATH = USER_DATA_PATH / "workflows" EXTERNAL_DATA_PATH = Path(PROJECT_PATH, "user_data/external_data") WORKFLOW_META_PATH = Path(PROJECT_PATH, "protzilla/constants/workflow_meta.json") UI_PATH = Path(PROJECT_PATH, "ui") diff --git a/protzilla/data_analysis/model_evaluation_plots.py b/protzilla/data_analysis/model_evaluation_plots.py index bae98b9b..644b202e 100644 --- a/protzilla/data_analysis/model_evaluation_plots.py +++ b/protzilla/data_analysis/model_evaluation_plots.py @@ -1,7 +1,7 @@ import matplotlib.pyplot as plot from sklearn.metrics import PrecisionRecallDisplay, RocCurveDisplay -from protzilla.constants.colors import PROTZILLA_DISCRETE_COLOR_SEQUENCE +from protzilla.constants.colors import PLOT_PRIMARY_COLOR from protzilla.data_analysis.classification_helper import encode_labels from protzilla.utilities.utilities import fig_to_base64 @@ -28,7 +28,7 @@ def precision_recall_curve_plot(model, input_test_df, labels_test_df, plot_title display = PrecisionRecallDisplay.from_estimator( model, input_test_df, labels_test_df["Encoded Label"] ) - display.plot(color=PROTZILLA_DISCRETE_COLOR_SEQUENCE[0]) + display.plot(color=PLOT_PRIMARY_COLOR) plot.title(plot_title) return [fig_to_base64(display.figure_)] @@ -55,6 +55,6 @@ def roc_curve_plot(model, input_test_df, labels_test_df, plot_title=None): display = RocCurveDisplay.from_estimator( model, input_test_df, labels_test_df["Encoded Label"] ) - display.plot(color=PROTZILLA_DISCRETE_COLOR_SEQUENCE[0]) + display.plot(color=PLOT_PRIMARY_COLOR) plot.title(plot_title) return [fig_to_base64(display.figure_)] diff --git a/protzilla/data_analysis/plots.py b/protzilla/data_analysis/plots.py index 84ae2b59..a01967a7 100644 --- a/protzilla/data_analysis/plots.py +++ b/protzilla/data_analysis/plots.py @@ -8,7 +8,7 @@ from scipy import stats from sklearn.metrics.pairwise import cosine_similarity, euclidean_distances -from protzilla.constants.colors import PROTZILLA_DISCRETE_COLOR_SEQUENCE +from protzilla.constants.colors import PLOT_COLOR_SEQUENCE, PLOT_PRIMARY_COLOR, PLOT_SECONDARY_COLOR from protzilla.utilities.clustergram import Clustergram from protzilla.utilities.transform_dfs import is_long_format, long_to_wide @@ -171,11 +171,11 @@ def create_volcano_plot( ) ) fig.update_traces( - marker=dict(color=PROTZILLA_DISCRETE_COLOR_SEQUENCE[2]), + marker=dict(color=PLOT_SECONDARY_COLOR), selector=dict(name=f"Significant {item_type}s"), ) fig.update_traces( - marker=dict(color=PROTZILLA_DISCRETE_COLOR_SEQUENCE[0]), + marker=dict(color=PLOT_PRIMARY_COLOR), selector=dict(name=f"Not Significant {item_type}s"), ) @@ -326,8 +326,8 @@ def prot_quant_plot( fig = go.Figure() color_mapping = { - "A": PROTZILLA_DISCRETE_COLOR_SEQUENCE[0], - "C": PROTZILLA_DISCRETE_COLOR_SEQUENCE[1], + "A": PLOT_PRIMARY_COLOR, + "C": PLOT_COLOR_SEQUENCE[2], } lower_upper_x = [] @@ -381,7 +381,7 @@ def prot_quant_plot( y=wide_df[group], mode="lines", name=group[:15] + "..." if len(group) > 15 else group, - line=dict(color=PROTZILLA_DISCRETE_COLOR_SEQUENCE[1]), + line=dict(color=PLOT_COLOR_SEQUENCE[2]), showlegend=len(similar_groups) <= 7, ) ) @@ -392,7 +392,7 @@ def prot_quant_plot( x=[None], y=[None], mode="lines", - line=dict(color=PROTZILLA_DISCRETE_COLOR_SEQUENCE[1]), + line=dict(color=PLOT_COLOR_SEQUENCE[2]), name="Similar Protein Groups", ) ) @@ -406,7 +406,7 @@ def prot_quant_plot( y=wide_df[protein_group], mode="lines", name=formatted_protein_name, - line=dict(color=PROTZILLA_DISCRETE_COLOR_SEQUENCE[2]), + line=dict(color=PLOT_SECONDARY_COLOR), ) ) diff --git a/protzilla/data_integration/di_plots.py b/protzilla/data_integration/di_plots.py index 74d50ff1..6e3cceeb 100644 --- a/protzilla/data_integration/di_plots.py +++ b/protzilla/data_integration/di_plots.py @@ -7,7 +7,7 @@ from protzilla.constants.protzilla_logging import logger from protzilla.utilities.utilities import fig_to_base64 -from ..constants.colors import PROTZILLA_DISCRETE_COLOR_SEQUENCE +from protzilla.constants.colors import PLOT_COLOR_SEQUENCE def GO_enrichment_bar_plot( @@ -17,7 +17,7 @@ def GO_enrichment_bar_plot( value, gene_sets=[], title="", - colors=PROTZILLA_DISCRETE_COLOR_SEQUENCE, + colors=PLOT_COLOR_SEQUENCE, figsize=None, ): """ @@ -39,7 +39,7 @@ def GO_enrichment_bar_plot( :type value: str :param title: Title of the plot, defaults to "" :type title: str, optional - :param colors: Colors to use for the bars, defaults to PROTZILLA_DISCRETE_COLOR_SEQUENCE + :param colors: Colors to use for the bars, defaults to PROTZILLA_COLOR_SEQUENCE :type colors: list, optional :param figsize: Size of the plot, defaults to None and is calculated dynamically if not provided. :type figsize: tuple, optional @@ -110,7 +110,7 @@ def GO_enrichment_bar_plot( if colors == "" or colors is None or len(colors) == 0: - colors = PROTZILLA_DISCRETE_COLOR_SEQUENCE + colors = PLOT_COLOR_SEQUENCE size_y = top_terms * 0.5 * len(gene_sets) try: ax = gseapy.barplot( diff --git a/protzilla/data_preprocessing/plots.py b/protzilla/data_preprocessing/plots.py index 6215f5c9..2a487eb6 100644 --- a/protzilla/data_preprocessing/plots.py +++ b/protzilla/data_preprocessing/plots.py @@ -7,9 +7,8 @@ from protzilla.data_preprocessing.plots_helper import generate_tics from protzilla.utilities import default_intensity_column - -from ..constants.colors import PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE - +from protzilla.utilities.plot_template import * +from protzilla.constants.colors import * def create_pie_plot( names_of_sectors: "list[str]", @@ -21,7 +20,6 @@ def create_pie_plot( Especially helpful for visualisation of basic parts of a whole. - :param color: Optional argument to specify the colour of the pie chart :param names_of_sectors: Name of parts (so-called sectors) or categories :param values_of_sectors: Corresponding values for sectors :param heading: Header for the graph - for example the topic @@ -32,21 +30,10 @@ def create_pie_plot( fig = px.pie( names=names_of_sectors, - values=values_of_sectors, - color_discrete_sequence=PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE, + values=values_of_sectors ) - fig.update_layout( - title={ - "text": f"{heading}", - "font": dict(size=16), - "y": 0.98, - "x": 0.5, - "xanchor": "center", - "yanchor": "top", - }, - font=dict(size=14, family="Arial"), - ) + fig.update_layout(title={"text": f"{heading}"}) fig.update_traces(hovertemplate="%{label}
Amount: %{value}") return fig @@ -55,7 +42,6 @@ def create_bar_plot( names_of_sectors: "list[str]", values_of_sectors: "list[int]", heading: str = "", - colour: "list[str]" = PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE, y_title: str = "", x_title: str = "", ) -> Figure: @@ -64,7 +50,6 @@ def create_bar_plot( Especially helpful for visualisation of basic parts of a whole. - :param color: Optional argument to specify the colour of the bar chart :param names_of_sectors: Name of parts (so called sectors) or categories :param values_of_sectors: Corresponding values for sectors :param heading: Header for the graph - for example the topic @@ -76,28 +61,13 @@ def create_bar_plot( fig = px.bar( x=names_of_sectors, y=values_of_sectors, - color=colour[: len(values_of_sectors)], - color_discrete_map="identity", - ) - - fig.update_layout( - xaxis_title=x_title, - yaxis_title=y_title, - plot_bgcolor="white", - yaxis={"gridcolor": "lightgrey", "zerolinecolor": "lightgrey"}, + color=[PLOT_PRIMARY_COLOR, PLOT_SECONDARY_COLOR], + color_discrete_map="identity" ) - fig.update_layout( - title={ - "text": f"{heading}", - "font": dict(size=16), - "y": 0.98, - "x": 0.5, - "xanchor": "center", - "yanchor": "top", - }, - font=dict(size=14, family="Arial"), - ) + fig.update_layout(title={"text": f"{heading}"}) + fig.update_xaxes(title=x_title) + fig.update_yaxes(title=y_title) return fig @@ -148,14 +118,14 @@ def create_box_plots( trace0 = go.Box( y=dataframe_a[intensity_name_a], x=dataframe_a[group_by], - marker_color=PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE[0], - name=name_a, + marker_color=PLOT_PRIMARY_COLOR, + name=name_a ) trace1 = go.Box( y=dataframe_b[intensity_name_b], x=dataframe_b[group_by], - marker_color=PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE[1], - name=name_b, + marker_color=PLOT_SECONDARY_COLOR, + name=name_b ) fig.add_trace(trace0, 1, 1) fig.add_trace(trace1, 1, 2) @@ -165,38 +135,25 @@ def create_box_plots( fig = make_subplots(rows=1, cols=2) trace0 = go.Box( y=dataframe_a[intensity_name_a], - marker_color=PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE[0], - name=name_a, + marker_color=PLOT_PRIMARY_COLOR, + name=name_a ) trace1 = go.Box( y=dataframe_b[intensity_name_b], - marker_color=PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE[1], - name=name_b, + marker_color=PLOT_SECONDARY_COLOR, + name=name_b ) fig.add_trace(trace0, 1, 1) fig.add_trace(trace1, 1, 2) - fig.update_layout( - xaxis_title=x_title, - yaxis_title=y_title, - xaxis2_title=x_title, - yaxis2_title=y_title, - font=dict(size=14, family="Arial"), - plot_bgcolor="white", - yaxis1={"gridcolor": "lightgrey", "zerolinecolor": "lightgrey"}, - yaxis2={"gridcolor": "lightgrey", "zerolinecolor": "lightgrey"}, - title={ - "text": f"{heading}", - "font": dict(size=16), - "y": 0.98, - "x": 0.5, - "xanchor": "center", - "yanchor": "top", - }, + fig.update_layout(title={"text": f"{heading}"}) + fig.update_xaxes(title=x_title) + fig.update_yaxes( + title=y_title, + rangemode="tozero" ) if visual_transformation == "log10": fig.update_yaxes(type="log") - fig.update_yaxes(rangemode="tozero") return fig @@ -264,13 +221,13 @@ def create_histograms( trace0 = go.Histogram( x=intensities_a, - marker_color=PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE[0], + marker_color=PLOT_PRIMARY_COLOR, name=name_a, xbins=dict(start=min_value, end=max_value, size=binsize_a), ) trace1 = go.Histogram( x=intensities_b, - marker_color=PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE[1], + marker_color=PLOT_SECONDARY_COLOR, name=name_b, xbins=dict(start=min_value, end=max_value, size=binsize_b), ) @@ -278,7 +235,6 @@ def create_histograms( fig = make_subplots(rows=1, cols=2) fig.add_trace(trace0, 1, 1) fig.add_trace(trace1, 1, 2) - fig.update_layout(xaxis2_title=x_title, yaxis2_title=y_title) if visual_transformation == "log10": fig.update_layout( xaxis=generate_tics(0, max_value, True), @@ -293,30 +249,19 @@ def create_histograms( if visual_transformation == "log10": fig.update_layout(xaxis=generate_tics(0, max_value, True)) - fig.update_layout( - xaxis_title=x_title, - yaxis_title=y_title, - font=dict(size=14, family="Arial"), - plot_bgcolor="white", - yaxis1={"gridcolor": "lightgrey", "zerolinecolor": "lightgrey"}, - yaxis2={"gridcolor": "lightgrey", "zerolinecolor": "lightgrey"}, - title={ - "text": f"{heading}", - "font": dict(size=16), - "y": 0.98, - "x": 0.5, - "xanchor": "center", - "yanchor": "top", - }, + fig.update_layout(title={"text": f"{heading}"}) + fig.update_xaxes(title=x_title) + fig.update_yaxes( + title=y_title, + rangemode="tozero" ) - fig.update_yaxes(rangemode="tozero") return fig def create_anomaly_score_bar_plot( anomaly_df: pd.DataFrame, - colour_outlier: str = PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE[1], - colour_non_outlier: str = PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE[0], + colour_outlier: str = PLOT_SECONDARY_COLOR, + colour_non_outlier: str = PLOT_PRIMARY_COLOR, ) -> Figure: """ This function creates a graph visualising the outlier @@ -325,10 +270,9 @@ def create_anomaly_score_bar_plot( :param anomaly_df: pandas Dataframe that contains the anomaly score for each\ sample, including outliers and on-outliers samples :param colour_outlier: hex code for colour depicting the outliers. - Default: PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE outlier colour + Default: PROTZILLA_SECONDARY_COLOR :param colour_non_outlier: hex code for colour depicting the - non-outliers. Default: PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE - non-outlier colour + non-outliers. Default: PROTZILLA_PRIMARY_COLOR :return: returns a plotly Figure object """ @@ -353,26 +297,23 @@ def create_anomaly_score_bar_plot( }, ) fig.update_coloraxes(showscale=False) - fig.update_layout(xaxis={"categoryorder": "category ascending"}) - fig.update_layout( - yaxis={ - "visible": True, - "showticklabels": True, - "gridcolor": "lightgrey", - }, - xaxis={"visible": False, "showticklabels": False}, - font=dict(size=18, family="Arial"), - plot_bgcolor="white", + fig.update_xaxes( + categoryorder="category ascending", + visible=False, + showticklabels=False + ) + fig.update_yaxes( + visible=True, + showticklabels=True ) - return fig def create_pca_2d_scatter_plot( pca_df: pd.DataFrame, explained_variance_ratio: list, - colour_outlier: str = PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE[1], - colour_non_outlier: str = PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE[0], + colour_outlier: str = PLOT_SECONDARY_COLOR, + colour_non_outlier: str = PLOT_PRIMARY_COLOR, ) -> Figure: """ This function creates a graph visualising the outlier @@ -384,10 +325,9 @@ def create_pca_2d_scatter_plot( :param explained_variance_ratio: a list that contains the\ explained variation for each component :param colour_outlier: hex code for colour depicting the outliers. - Default: PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE outlier colour + Default: PROTZILLA_SECONDARY_COLOR :param colour_non_outlier: hex code for colour depicting the - non-outliers. Default: PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE - non-outlier colour + non-outliers. Default: PROTZILLA_PRIMARY_COLOR :return: returns a plotly Figure object """ @@ -404,25 +344,22 @@ def create_pca_2d_scatter_plot( ) e_variance_0 = round(explained_variance_ratio[0], 4) * 100 e_variance_1 = round(explained_variance_ratio[1], 4) * 100 - fig.update_layout( - xaxis_title=f"Principal Component 1 ({e_variance_0:.2f} %)", - yaxis_title=f"Principal Component 2 ({e_variance_1:.2f} %)", - font=dict(size=14, family="Arial"), - plot_bgcolor="white", - yaxis={"gridcolor": "lightgrey", "zerolinecolor": "lightgrey"}, - xaxis={"gridcolor": "lightgrey", "zerolinecolor": "lightgrey"}, + fig.update_xaxes( + showticklabels=False, + title=f"Principal Component 1 ({e_variance_0:.2f} %)" + ) + fig.update_yaxes( + showticklabels=False, + title=f"Principal Component 2 ({e_variance_1:.2f} %)" ) - fig.update_xaxes(showticklabels=False) - fig.update_yaxes(showticklabels=False) - return fig def create_pca_3d_scatter_plot( pca_df: pd.DataFrame, explained_variance_ratio: list, - colour_outlier: str = PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE[1], - colour_non_outlier: str = PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE[0], + colour_outlier: str = PLOT_SECONDARY_COLOR, + colour_non_outlier: str = PLOT_PRIMARY_COLOR, ) -> Figure: """ This function creates a graph visualising the outlier @@ -434,10 +371,9 @@ def create_pca_3d_scatter_plot( :param explained_variance_ratio: a list that contains the\ explained variation for each component :param colour_outlier: hex code for colour depicting the outliers. - Default: PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE outlier colour + Default: PROTZILLA_SECONDARY_COLOR :param colour_non_outlier: hex code for colour depicting the - non-outliers. Default: PROTZILLA_DISCRETE_COLOR_OUTLIER_SEQUENCE - non-outlier colour + non-outliers. Default: PROTZILLA_PRIMARY_COLOR :return: returns a plotly Figure object """ @@ -458,16 +394,19 @@ def create_pca_3d_scatter_plot( z_percent = round(explained_variance_ratio[2], 4) * 100 fig.update_layout( - scene=dict( - xaxis_title=(f"Principal Component 1 ({x_percent:.2f} %)"), - yaxis_title=(f"Principal Component 2 ({y_percent:.2f} %)"), - zaxis_title=(f"Principal Component 3 ({z_percent:.2f} %)"), - xaxis=dict(showticklabels=False), - yaxis=dict(showticklabels=False), - zaxis=dict(showticklabels=False), - ), - font=dict(size=14, family="Arial"), - plot_bgcolor="white", + scene={ + "xaxis": { + "title": f"Principal Component 1 ({x_percent:.2f} %)", + "showticklabels": False + }, + "yaxis": { + "title": f"Principal Component 2 ({y_percent:.2f} %)", + "showticklabels": False + }, + "zaxis": { + "title": f"Principal Component 3 ({z_percent:.2f} %)", + "showticklabels": False + } + } ) - - return fig + return fig \ No newline at end of file diff --git a/protzilla/utilities/plot_template.py b/protzilla/utilities/plot_template.py new file mode 100644 index 00000000..9661a41f --- /dev/null +++ b/protzilla/utilities/plot_template.py @@ -0,0 +1,34 @@ +import plotly.io as pio +import plotly.graph_objects as go + +from protzilla.constants.colors import PLOT_PRIMARY_COLOR, PLOT_SECONDARY_COLOR + + +layout = go.Layout( + title={ + "font": { + "size": 16, + "family": "Arial" + }, + "y": 0.98, + "x": 0.5, + "xanchor": "center", + "yanchor": "top" + }, + font={ + "size": 14, + "family": "Arial" + }, + colorway=[PLOT_PRIMARY_COLOR, PLOT_SECONDARY_COLOR], + plot_bgcolor="white", + yaxis={ + "gridcolor": "lightgrey", + "zerolinecolor": "lightgrey" + }, + modebar={ + "remove": ["autoScale2d", "lasso", "lasso2d", "toImage", "select2d"], + }, + dragmode="pan" +) +pio.templates["plotly_protzilla"] = go.layout.Template(layout=layout) +pio.templates.default = "plotly_protzilla" \ No newline at end of file diff --git a/ui/runs/forms/data_analysis.py b/ui/runs/forms/data_analysis.py index 6e34aa6e..317fd473 100644 --- a/ui/runs/forms/data_analysis.py +++ b/ui/runs/forms/data_analysis.py @@ -520,7 +520,7 @@ class PlotClustergramForm(MethodForm): label="Choose dataframe to be used for coloring", required=False, ) - flip_axis = CustomChoiceField( + flip_axes = CustomChoiceField( choices=YesNo, label="Flip axis", initial=YesNo.no, diff --git a/ui/runs/forms/data_integration.py b/ui/runs/forms/data_integration.py index 1ed60152..29b0f46f 100644 --- a/ui/runs/forms/data_integration.py +++ b/ui/runs/forms/data_integration.py @@ -4,7 +4,7 @@ import matplotlib.colors as mcolors import restring -from protzilla.constants.colors import PROTZILLA_DISCRETE_COLOR_SEQUENCE +from protzilla.constants.colors import PLOT_COLOR_SEQUENCE from protzilla.data_integration.database_query import ( biomart_database, uniprot_databases, @@ -95,7 +95,7 @@ class GSEADotPlotXAxisValue(Enum): class PlotColors(Enum): - PROTzilla_default = PROTZILLA_DISCRETE_COLOR_SEQUENCE + PROTzilla_default = PLOT_COLOR_SEQUENCE class EmptyEnum(Enum): diff --git a/ui/runs/views.py b/ui/runs/views.py index 020063eb..56d0d264 100644 --- a/ui/runs/views.py +++ b/ui/runs/views.py @@ -1,4 +1,3 @@ -import os import io import tempfile import traceback @@ -32,6 +31,7 @@ name_to_title, ) from protzilla.workflow import get_available_workflow_names +from protzilla.constants.paths import WORKFLOWS_PATH from ui.runs.fields import ( make_displayed_history, make_method_dropdown, @@ -423,7 +423,7 @@ def export_workflow(request: HttpRequest, run_name: str): display_message( { "level": 20, - "msg": f"Workflow '{requested_workflow_name}' was exported successfully.
You can view it here: {os.path.join(settings.BASE_DIR, 'user_data', 'workflows')}", + "msg": f"Workflow '{requested_workflow_name}' was exported successfully.
You can view the file at {WORKFLOWS_PATH}.", }, request, )