{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":106680,"databundleVersionId":13374319,"sourceType":"competition"}],"dockerImageVersionId":31192,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install biopython logomaker\n!sudo apt-get install mafft","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        #print(os.path.join(dirname, filename))\n        pass\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport plotly.graph_objects as go\n\nfrom Bio.Seq import Seq\nfrom Bio.SeqRecord import SeqRecord\nfrom Bio import SeqIO\nimport subprocess\nimport logomaker\nimport matplotlib.pyplot as plt\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:39:35.117577Z","iopub.execute_input":"2025-11-17T03:39:35.117989Z","iopub.status.idle":"2025-11-17T03:39:35.546693Z","shell.execute_reply.started":"2025-11-17T03:39:35.117952Z","shell.execute_reply":"2025-11-17T03:39:35.545971Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_datasets = os.listdir(\"/kaggle/input/adaptive-immune-profiling-challenge-2025/train_datasets/train_datasets\")\ntrain_datasets","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:34:53.246191Z","iopub.execute_input":"2025-11-17T03:34:53.246741Z","iopub.status.idle":"2025-11-17T03:34:53.254964Z","shell.execute_reply.started":"2025-11-17T03:34:53.246700Z","shell.execute_reply":"2025-11-17T03:34:53.253900Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"os.listdir(\"/kaggle/input/adaptive-immune-profiling-challenge-2025/train_datasets/train_datasets/train_dataset_1\")[:5]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:34:53.258673Z","iopub.execute_input":"2025-11-17T03:34:53.258997Z","iopub.status.idle":"2025-11-17T03:34:53.286018Z","shell.execute_reply.started":"2025-11-17T03:34:53.258969Z","shell.execute_reply":"2025-11-17T03:34:53.284946Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_datasets_path = \"/kaggle/input/adaptive-immune-profiling-challenge-2025/train_datasets/train_datasets/\"\nplt.figure(figsize=(6,10))\nfor i, dataset in enumerate(os.listdir(train_datasets_path)):\n    metadata = pd.read_csv(f\"{train_datasets_path}/{dataset}/metadata.csv\")\n    plt.subplot(4,2,i+1)\n    sns.countplot(metadata, x = \"label_positive\")\n    plt.title(dataset)\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:34:53.287339Z","iopub.execute_input":"2025-11-17T03:34:53.287965Z","iopub.status.idle":"2025-11-17T03:34:54.609015Z","shell.execute_reply.started":"2025-11-17T03:34:53.287929Z","shell.execute_reply":"2025-11-17T03:34:54.607656Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_datasets_path = \"/kaggle/input/adaptive-immune-profiling-challenge-2025/train_datasets/train_datasets/\"\nfor i, dataset in enumerate(os.listdir(train_datasets_path)):\n    metadata = pd.read_csv(f\"{train_datasets_path}/{dataset}/metadata.csv\")\n    print(dataset)\n    display(metadata.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:34:54.610287Z","iopub.execute_input":"2025-11-17T03:34:54.610673Z","iopub.status.idle":"2025-11-17T03:34:54.713362Z","shell.execute_reply.started":"2025-11-17T03:34:54.610650Z","shell.execute_reply":"2025-11-17T03:34:54.712615Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Example Patient","metadata":{}},{"cell_type":"code","source":"example = pd.read_csv(\"/kaggle/input/adaptive-immune-profiling-challenge-2025/train_datasets/train_datasets/train_dataset_1/2c65ef1f4fd1744fc8177cc73f63f589.tsv\", sep=\"\\t\")\nexample","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:34:54.716364Z","iopub.execute_input":"2025-11-17T03:34:54.716631Z","iopub.status.idle":"2025-11-17T03:34:54.765333Z","shell.execute_reply.started":"2025-11-17T03:34:54.716610Z","shell.execute_reply":"2025-11-17T03:34:54.764304Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"j_call unique\", len(example.j_call.unique()))\nprint(\"v_call unique\", len(example.v_call.unique()))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:34:54.766253Z","iopub.execute_input":"2025-11-17T03:34:54.766562Z","iopub.status.idle":"2025-11-17T03:34:54.777120Z","shell.execute_reply.started":"2025-11-17T03:34:54.766536Z","shell.execute_reply":"2025-11-17T03:34:54.776264Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(10,6))\nsns.countplot(example, x= \"j_call\")\nplt.xticks(rotation=90)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:34:54.778270Z","iopub.execute_input":"2025-11-17T03:34:54.778604Z","iopub.status.idle":"2025-11-17T03:34:55.001921Z","shell.execute_reply.started":"2025-11-17T03:34:54.778570Z","shell.execute_reply":"2025-11-17T03:34:55.000932Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(10,6))\nsns.countplot(example, x= \"v_call\")\nplt.xticks(rotation=90)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:34:55.003043Z","iopub.execute_input":"2025-11-17T03:34:55.003408Z","iopub.status.idle":"2025-11-17T03:34:55.450504Z","shell.execute_reply.started":"2025-11-17T03:34:55.003377Z","shell.execute_reply":"2025-11-17T03:34:55.449280Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sns.histplot(example.junction_aa.str.len())\nplt.xlabel(\"Sequence length\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:34:55.451516Z","iopub.execute_input":"2025-11-17T03:34:55.451977Z","iopub.status.idle":"2025-11-17T03:34:55.848897Z","shell.execute_reply.started":"2025-11-17T03:34:55.451869Z","shell.execute_reply":"2025-11-17T03:34:55.847895Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"example","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:34:55.850093Z","iopub.execute_input":"2025-11-17T03:34:55.850366Z","iopub.status.idle":"2025-11-17T03:34:55.860340Z","shell.execute_reply.started":"2025-11-17T03:34:55.850337Z","shell.execute_reply":"2025-11-17T03:34:55.859331Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Secuencias repetidas","metadata":{}},{"cell_type":"code","source":"example.junction_aa.value_counts().value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:34:55.861331Z","iopub.execute_input":"2025-11-17T03:34:55.861638Z","iopub.status.idle":"2025-11-17T03:34:55.890707Z","shell.execute_reply.started":"2025-11-17T03:34:55.861611Z","shell.execute_reply":"2025-11-17T03:34:55.889698Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"example = example.merge(example.v_call.value_counts(), on=\"v_call\")\nexample = example.rename(columns={\"count\": \"v_count\"})\nexample = example.merge(example.j_call.value_counts(), on=\"j_call\")\nexample = example.rename(columns={\"count\": \"j_count\"})","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:35:29.474817Z","iopub.execute_input":"2025-11-17T03:35:29.475173Z","iopub.status.idle":"2025-11-17T03:35:29.520115Z","shell.execute_reply.started":"2025-11-17T03:35:29.475148Z","shell.execute_reply":"2025-11-17T03:35:29.519102Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"example","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:35:30.575571Z","iopub.execute_input":"2025-11-17T03:35:30.575901Z","iopub.status.idle":"2025-11-17T03:35:30.596665Z","shell.execute_reply.started":"2025-11-17T03:35:30.575851Z","shell.execute_reply":"2025-11-17T03:35:30.595863Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def series_to_fasta(series, fasta_path=\"sequences.fasta\"):\n    records = []\n    for i, seq in enumerate(series):\n        records.append(SeqRecord(Seq(str(seq)), id=f\"seq{i}\", description=\"\"))\n    SeqIO.write(records, fasta_path, \"fasta\")\n    return fasta_path","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:48:20.223291Z","iopub.execute_input":"2025-11-17T03:48:20.224076Z","iopub.status.idle":"2025-11-17T03:48:20.229516Z","shell.execute_reply.started":"2025-11-17T03:48:20.224044Z","shell.execute_reply":"2025-11-17T03:48:20.228645Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def align_fasta_mafft(input_fasta, output_fasta=\"aligned.fasta\"):\n    cmd = [\"mafft\", \"--auto\", input_fasta]\n    with open(output_fasta, \"w\") as out:\n        subprocess.run(cmd, stdout=out, check=True, stderr=subprocess.DEVNULL)\n    return output_fasta","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:49:59.799345Z","iopub.execute_input":"2025-11-17T03:49:59.800212Z","iopub.status.idle":"2025-11-17T03:49:59.807425Z","shell.execute_reply.started":"2025-11-17T03:49:59.800132Z","shell.execute_reply":"2025-11-17T03:49:59.806328Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def make_logo_from_alignment(aligned_fasta, title, output_png=\"logo.png\"):\n    alignment = [str(rec.seq) for rec in SeqIO.parse(aligned_fasta, \"fasta\")]\n    matrix = logomaker.alignment_to_matrix(alignment, to_type='information')\n    plt.figure(figsize=(12, 3))\n    logo = logomaker.Logo(matrix,\n                          shade_below=0.5,\n                          fade_below=0.5,\n                          font_name='DejaVu Sans Mono')\n\n    logo.style_xticks(anchor=0)\n    logo.ax.set_ylabel(\"Information (bits)\")\n    plt.title(title)\n    plt.tight_layout()\n    plt.show()\n    plt.savefig(output_png)\n    return output_png","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:50:01.272586Z","iopub.execute_input":"2025-11-17T03:50:01.272943Z","iopub.status.idle":"2025-11-17T03:50:01.280608Z","shell.execute_reply.started":"2025-11-17T03:50:01.272915Z","shell.execute_reply":"2025-11-17T03:50:01.279707Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def make_logo_from_series(series, title):\n    fasta = series_to_fasta(series, fasta_path = f\"{title}.fasta\")\n    aln = align_fasta_mafft(fasta, output_fasta = f\"{title}_aligned.fasta\")\n    logo = make_logo_from_alignment(aln, title, output_png = f\"{title}.png\")\n    return logo\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:50:02.266340Z","iopub.execute_input":"2025-11-17T03:50:02.268345Z","iopub.status.idle":"2025-11-17T03:50:02.273676Z","shell.execute_reply.started":"2025-11-17T03:50:02.268295Z","shell.execute_reply":"2025-11-17T03:50:02.272597Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for j in example.j_call.unique()[:5]: #Drop [:5] to obtain all Logos\n    j_df = example[example.j_call == j]\n    make_logo_from_series(j_df.junction_aa, j)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T04:06:45.097280Z","iopub.execute_input":"2025-11-17T04:06:45.098387Z","iopub.status.idle":"2025-11-17T04:07:58.319278Z","shell.execute_reply.started":"2025-11-17T04:06:45.098343Z","shell.execute_reply":"2025-11-17T04:07:58.318164Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for v in example.v_call.unique()[:5]: #Drop [:5] to obtain all Logos\n    v_df = example[example.v_call == v]\n    make_logo_from_series(v_df.junction_aa, v)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T04:07:58.320706Z","iopub.execute_input":"2025-11-17T04:07:58.321156Z","iopub.status.idle":"2025-11-17T04:09:07.364852Z","shell.execute_reply.started":"2025-11-17T04:07:58.321131Z","shell.execute_reply":"2025-11-17T04:09:07.364128Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"concordance = example[[\"v_call\", \"j_call\"]].value_counts().reset_index().pivot(columns=\"j_call\", index=\"v_call\").fillna(0)\nplt.figure(figsize=(15,20))\nsns.heatmap(concordance)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:34:58.026819Z","iopub.execute_input":"2025-11-17T03:34:58.027263Z","iopub.status.idle":"2025-11-17T03:34:58.825824Z","shell.execute_reply.started":"2025-11-17T03:34:58.027241Z","shell.execute_reply":"2025-11-17T03:34:58.824944Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Normalize by j_call\nplt.figure(figsize=(15,25))\nsns.heatmap(concordance/concordance.sum(axis = 0) * 100)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:34:58.826743Z","iopub.execute_input":"2025-11-17T03:34:58.827057Z","iopub.status.idle":"2025-11-17T03:34:59.615763Z","shell.execute_reply.started":"2025-11-17T03:34:58.827029Z","shell.execute_reply":"2025-11-17T03:34:59.614773Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"flows = example[[\"v_call\", \"j_call\"]].value_counts().reset_index()\nflows = flows.rename(columns={\"v_call\": \"source\", \"j_call\": \"target\", \"count\": \"value\"}).sort_values(by=\"source\")\nsns.histplot(flows, x = \"value\")\nplt.title(\"Combinations of V and J\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:34:59.619249Z","iopub.execute_input":"2025-11-17T03:34:59.619501Z","iopub.status.idle":"2025-11-17T03:34:59.847684Z","shell.execute_reply.started":"2025-11-17T03:34:59.619482Z","shell.execute_reply":"2025-11-17T03:34:59.846737Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def sankey(flows_sampled):\n    # Nodos únicos\n    sources = flows_sampled['source'].unique()\n    targets = flows_sampled['target'].unique()\n    nodes = list(sources) + list(targets)\n    \n    # Mapear cada nodo a un índice\n    node_index = {node: i for i, node in enumerate(nodes)}\n    \n    # Crear listas para sankey\n    flows_sampled['source_id'] = flows_sampled['source'].map(node_index)\n    flows_sampled['target_id'] = flows_sampled['target'].map(node_index)\n    \n    fig = go.Figure(data=[go.Sankey(\n        node=dict(\n            pad=15,\n            thickness=20,\n            line=dict(color=\"black\", width=0.5),\n            label=nodes,\n        ),\n        link=dict(\n            source=flows_sampled['source_id'],\n            target=flows_sampled['target_id'],\n            value=flows_sampled['value']\n        )\n    )])\n    \n    fig.update_layout(\n        title_text=\"Sankey plot\",\n        font_size=12,\n        height=900\n    )\n    fig.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:34:59.848616Z","iopub.execute_input":"2025-11-17T03:34:59.848870Z","iopub.status.idle":"2025-11-17T03:34:59.856776Z","shell.execute_reply.started":"2025-11-17T03:34:59.848846Z","shell.execute_reply":"2025-11-17T03:34:59.855809Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"threshold = 100 #Limit this to noise reduce\nflows_sampled = flows[flows[\"value\"] > threshold]\nsankey(flows_sampled)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-17T03:34:59.857809Z","iopub.execute_input":"2025-11-17T03:34:59.858139Z","iopub.status.idle":"2025-11-17T03:35:02.189472Z","shell.execute_reply.started":"2025-11-17T03:34:59.858109Z","shell.execute_reply":"2025-11-17T03:35:02.188534Z"}},"outputs":[],"execution_count":null}]}