Source code for immuneML.reports.multi_dataset_reports.DiseaseAssociatedSequenceOverlap

from pathlib import Path
from typing import List

import pandas as pd
import plotly.express as px

from immuneML.hyperparameter_optimization.states.TrainMLModelState import TrainMLModelState
from immuneML.reports.ReportOutput import ReportOutput
from immuneML.reports.ReportResult import ReportResult
from immuneML.reports.multi_dataset_reports.MultiDatasetReport import MultiDatasetReport
from immuneML.util.PathBuilder import PathBuilder
from immuneML.util.SequenceAnalysisHelper import SequenceAnalysisHelper


[docs]class DiseaseAssociatedSequenceOverlap(MultiDatasetReport): """ DiseaseAssociatedSequenceOverlap report makes a heatmap showing the overlap of disease-associated sequences produced by :ref:`SequenceAbundance` encoders between multiple datasets of different sizes (different number of repertoires per dataset). This plot can be used only with MultiDatasetBenchmarkTool The overlap is computed by the following equation: .. math:: overlap(X,Y) = \\frac{|X \\cap Y|}{min(|X|, |Y|)} x 100 For details, see Greiff V, Menzel U, Miho E, et al. Systems Analysis Reveals High Genetic and Antigen-Driven Predetermination of Antibody Repertoires throughout B Cell Development. Cell Reports. 2017;19(7):1467-1478. doi:10.1016/j.celrep.2017.04.054. YAML specification: .. indent with spaces .. code-block:: yaml reports: # the report is defined with all other reports under definitions/reports my_overlap_report: DiseaseAssociatedSequenceOverlap # report has no parameters """
[docs] @classmethod def build_object(cls, **kwargs): return DiseaseAssociatedSequenceOverlap(**kwargs)
def __init__(self, instruction_states: List[TrainMLModelState] = None, name: str = None, result_path: Path = None): super().__init__(name) self.instruction_states = instruction_states self.result_path = result_path self.label = None def _generate(self) -> ReportResult: self.result_path = PathBuilder.build(self.result_path / self.name) self._extract_label() hp_items = [state.optimal_hp_items[self.label] for state in self.instruction_states] overlap_matrix = SequenceAnalysisHelper.compute_overlap_matrix(hp_items) labels = [state.dataset.name for state in self.instruction_states] figure_path = self._make_figure(overlap_matrix, labels) data_path = self._export_matrix(overlap_matrix, labels) return ReportResult(output_figures=[ReportOutput(figure_path, 'sequence overlap across datasets')], output_tables=[ReportOutput(data_path, 'sequence overlap across datasets (csv)')]) def _extract_label(self): all_labels = [] for state in self.instruction_states: all_labels += state.label_configuration.get_labels_by_name() all_labels = set(all_labels) assert len(all_labels) == 1, \ f"{DiseaseAssociatedSequenceOverlap.__name__}: multiple labels were specified {all_labels}, but this report accepts only one label." self.label = list(all_labels)[0] def _export_matrix(self, overlap_matrix, labels): data_path = self.result_path / "sequence_overlap.csv" pd.DataFrame(overlap_matrix, columns=labels, index=labels).to_csv(data_path) return data_path def _make_figure(self, overlap_matrix, labels): figure = px.imshow(overlap_matrix, x=labels, y=labels, zmin=0, zmax=100, color_continuous_scale=px.colors.sequential.Teal, template='plotly_white') figure.update_traces(hovertemplate="Overlap of disease-associated<br>sequences between datasets<br>%{x} and %{y}:<br>%{z}%<extra></extra>") figure_path = self.result_path / "sequence_overlap.html" figure.write_html(str(figure_path)) return figure_path