diff --git a/docs/tutorials/DTO_analysis.ipynb b/docs/tutorials/DTO_analysis.ipynb
new file mode 100644
index 0000000..c564c38
--- /dev/null
+++ b/docs/tutorials/DTO_analysis.ipynb
@@ -0,0 +1,2384 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "48ac26da",
+ "metadata": {},
+ "source": [
+ "## DTO Active-Set Analysis\n",
+ "\n",
+ "This analysis identifies transcription factor (TF) binding samples that show\n",
+ "significant dual-threshold overlap (DTO) with both major perturbation datasets,\n",
+ "providing a high-confidence set of regulatory interactions.\n",
+ "\n",
+ "### Workflow\n",
+ "\n",
+ "1. **Filter by Hackett-2020-ZEV**: Select binding samples from all datasets\n",
+ " (Harbison, Rossi, Mahendrawada) where DTO vs. Hackett-2020-ZEV P ≤ 0.01.\n",
+ "\n",
+ "2. **Filter by Kemmeren-2014-TFKO**: Apply the same selection against the\n",
+ " Kemmeren-2014 knockout perturbation dataset (P ≤ 0.01).\n",
+ "\n",
+ "3. **Intersect**: Retain only binding samples that are significant in **both**\n",
+ " comparisons. These form the \"active set\" — samples whose regulatory\n",
+ " relationships are independently supported by two orthogonal perturbation\n",
+ " experiments (ZEV-inducible overexpression and gene knockout).\n",
+ "\n",
+ "4. **Summarize by regulator**:\n",
+ " - **Table**: One row per regulator with the count of active samples.\n",
+ " - **Distribution**: Histogram showing how many regulators have 1, 2, 3, …\n",
+ " active samples, revealing whether active evidence is concentrated in a\n",
+ " few TFs or spread broadly.\n",
+ "\n",
+ "### Rationale\n",
+ "\n",
+ "A binding sample significant in only one perturbation comparison could reflect\n",
+ "experiment-specific artifacts. Requiring significance in both Hackett (ZEV) and\n",
+ "Kemmeren (TFKO) leverages two fundamentally different perturbation strategies,\n",
+ "increasing confidence that the observed TF–target relationships are\n",
+ "biologically meaningful."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 53,
+ "id": "c59de9d2",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "VirtualDB(7 repos, 8 datasets, views not yet registered)\n"
+ ]
+ }
+ ],
+ "source": [
+ "from tfbpapi.virtual_db import VirtualDB\n",
+ "\n",
+ "# Read configuration from datasets.yaml\n",
+ "vdb = VirtualDB(\"/home/luegg/code/tfbpapi/tfbpapi/datasets.yaml\")\n",
+ "print(repr(vdb))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 54,
+ "id": "3ccc8874",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Registered views:\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "Fetching 1 files: 100%|██████████| 1/1 [00:00<00:00, 4963.67it/s]\n",
+ "Fetching 1 files: 100%|██████████| 1/1 [00:00<00:00, 9799.78it/s]\n",
+ "Fetching 1 files: 100%|██████████| 1/1 [00:00<00:00, 12595.51it/s]\n",
+ "Fetching 1 files: 100%|██████████| 1/1 [00:00<00:00, 3644.05it/s]\n",
+ "Fetching 1 files: 100%|██████████| 1/1 [00:00<00:00, 10280.16it/s]\n",
+ "Fetching 1 files: 100%|██████████| 1/1 [00:00<00:00, 11125.47it/s]\n",
+ "Fetching 1 files: 100%|██████████| 1/1 [00:00<00:00, 10058.28it/s]\n",
+ "Fetching 30 files: 100%|██████████| 30/30 [00:00<00:00, 146996.64it/s]\n",
+ "Key 'carbon_source' not found at path 'media.carbon_source' (current keys: ['name'])\n",
+ "Key 'carbon_source' not found at path 'media.carbon_source' (current keys: ['name'])\n",
+ "Key 'carbon_source' not found at path 'media.carbon_source' (current keys: ['name'])\n",
+ "Key 'temperature_celsius' not found at path 'temperature_celsius' (current keys: ['description', 'initial_temperature_celsius', 'temperature_shift_celsius', 'temperature_shift_duration_minutes', 'growth_phase_at_harvest', 'media'])\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " chec_mahendrawada_m2025_af_combined_meta\n",
+ " chec_mahendrawada_m2025_af_combined_meta_meta\n",
+ " dto_expanded\n",
+ " hackett\n",
+ " hackett_meta\n",
+ " harbison\n",
+ " harbison_meta\n",
+ " kemmeren\n",
+ " kemmeren_meta\n",
+ " knockout\n",
+ " knockout_meta\n",
+ " overexpression\n",
+ " overexpression_meta\n",
+ " rossi_2021_af_combined\n",
+ " rossi_2021_af_combined_meta\n"
+ ]
+ }
+ ],
+ "source": [
+ "# List all registered views\n",
+ "print(\"Registered views:\")\n",
+ "for name in vdb.tables():\n",
+ " print(f\" {name}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "968e3f01",
+ "metadata": {},
+ "source": [
+ "## Step1-Obtain the intersection of the binding dataset and Hackett"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 55,
+ "id": "80e34ef0",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Number of records that meet the criteria: 910\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " sample_id | \n",
+ " regulator_symbol | \n",
+ " regulator_locus_tag | \n",
+ " condition | \n",
+ " carbon_source | \n",
+ " temperature_celsius | \n",
+ " dto_empirical_pvalue | \n",
+ " dto_fdr | \n",
+ " hackett_sample_id | \n",
+ " perturbation_id_source | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 16 | \n",
+ " TEC1 | \n",
+ " YBR083W | \n",
+ " Alpha | \n",
+ " glucose | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.141768 | \n",
+ " 91 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 174 | \n",
+ " ZAP1 | \n",
+ " YJL056C | \n",
+ " YPD | \n",
+ " glucose | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.005249 | \n",
+ " 818 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 38 | \n",
+ " PHO2 | \n",
+ " YDL106C | \n",
+ " H2O2Hi | \n",
+ " glucose | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.263801 | \n",
+ " 190 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 248 | \n",
+ " SOK2 | \n",
+ " YMR016C | \n",
+ " BUT14 | \n",
+ " glucose | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.065595 | \n",
+ " 1098 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 50 | \n",
+ " NRG1 | \n",
+ " YDR043C | \n",
+ " H2O2Lo | \n",
+ " glucose | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.167487 | \n",
+ " 249 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 50 | \n",
+ " NRG1 | \n",
+ " YDR043C | \n",
+ " H2O2Lo | \n",
+ " glucose | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.241330 | \n",
+ " 248 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 323 | \n",
+ " DIG1 | \n",
+ " YPL049C | \n",
+ " BUT90 | \n",
+ " glucose | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.031633 | \n",
+ " 1598 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " 281 | \n",
+ " GCR2 | \n",
+ " YNL199C | \n",
+ " SM | \n",
+ " unspecified | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.001701 | \n",
+ " 1251 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " 86 | \n",
+ " GLN3 | \n",
+ " YER040W | \n",
+ " SM | \n",
+ " unspecified | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.099947 | \n",
+ " 434 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " 282 | \n",
+ " GCR2 | \n",
+ " YNL199C | \n",
+ " YPD | \n",
+ " glucose | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.047443 | \n",
+ " 1251 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " sample_id regulator_symbol regulator_locus_tag condition carbon_source \\\n",
+ "0 16 TEC1 YBR083W Alpha glucose \n",
+ "1 174 ZAP1 YJL056C YPD glucose \n",
+ "2 38 PHO2 YDL106C H2O2Hi glucose \n",
+ "3 248 SOK2 YMR016C BUT14 glucose \n",
+ "4 50 NRG1 YDR043C H2O2Lo glucose \n",
+ "5 50 NRG1 YDR043C H2O2Lo glucose \n",
+ "6 323 DIG1 YPL049C BUT90 glucose \n",
+ "7 281 GCR2 YNL199C SM unspecified \n",
+ "8 86 GLN3 YER040W SM unspecified \n",
+ "9 282 GCR2 YNL199C YPD glucose \n",
+ "\n",
+ " temperature_celsius dto_empirical_pvalue dto_fdr hackett_sample_id \\\n",
+ "0 30.0 0.0 0.141768 91 \n",
+ "1 30.0 0.0 0.005249 818 \n",
+ "2 30.0 0.0 0.263801 190 \n",
+ "3 30.0 0.0 0.065595 1098 \n",
+ "4 30.0 0.0 0.167487 249 \n",
+ "5 30.0 0.0 0.241330 248 \n",
+ "6 30.0 0.0 0.031633 1598 \n",
+ "7 30.0 0.0 0.001701 1251 \n",
+ "8 30.0 0.0 0.099947 434 \n",
+ "9 30.0 0.0 0.047443 1251 \n",
+ "\n",
+ " perturbation_id_source \n",
+ "0 hackett \n",
+ "1 hackett \n",
+ "2 hackett \n",
+ "3 hackett \n",
+ "4 hackett \n",
+ "5 hackett \n",
+ "6 hackett \n",
+ "7 hackett \n",
+ "8 hackett \n",
+ "9 hackett "
+ ]
+ },
+ "execution_count": 55,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Using binding dataset as the main table, JOIN dto_expanded to retrieve DTO statistics\n",
+ "# Filtering for vs. Hackett perturbation data, pvalue <= 0.01\n",
+ "harbison_hackett = vdb.query(\"\"\"\n",
+ " SELECT\n",
+ " h.sample_id,\n",
+ " h.regulator_symbol,\n",
+ " h.regulator_locus_tag,\n",
+ " h.condition,\n",
+ " h.carbon_source,\n",
+ " h.temperature_celsius,\n",
+ " d.dto_empirical_pvalue,\n",
+ " d.dto_fdr,\n",
+ " d.perturbation_id_id AS hackett_sample_id,\n",
+ " d.perturbation_id_source\n",
+ " FROM harbison_meta h\n",
+ " JOIN dto_expanded d\n",
+ " ON CAST(h.sample_id AS VARCHAR) = d.binding_id_id\n",
+ " AND d.binding_id_source = 'harbison'\n",
+ " WHERE d.perturbation_id_source = 'hackett'\n",
+ " AND d.dto_empirical_pvalue <= 0.01\n",
+ " ORDER BY d.dto_empirical_pvalue\n",
+ "\"\"\")\n",
+ "\n",
+ "print(f\"Number of records that meet the criteria: {len(harbison_hackett)}\")\n",
+ "harbison_hackett.head(10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 56,
+ "id": "60ae9b90",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Number of records that meet the criteria: 684\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " sample_id | \n",
+ " regulator_locus_tag | \n",
+ " carbon_source | \n",
+ " temperature_celsius | \n",
+ " dto_empirical_pvalue | \n",
+ " dto_fdr | \n",
+ " hackett_sample_id | \n",
+ " perturbation_id_source | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 671 | \n",
+ " YOR083W | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.002385 | \n",
+ " 1393 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 550 | \n",
+ " YMR039C | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.023965 | \n",
+ " 1132 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 154 | \n",
+ " YDR216W | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.082601 | \n",
+ " 304 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 392 | \n",
+ " YJL110C | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.124665 | \n",
+ " 799 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 700 | \n",
+ " YOR290C | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.079160 | \n",
+ " 1454 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 372 | \n",
+ " YIL131C | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.059436 | \n",
+ " 732 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 700 | \n",
+ " YOR290C | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.070062 | \n",
+ " 1453 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " 372 | \n",
+ " YIL131C | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.076569 | \n",
+ " 731 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " 700 | \n",
+ " YOR290C | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.093879 | \n",
+ " 1452 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " 372 | \n",
+ " YIL131C | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.108097 | \n",
+ " 730 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " sample_id regulator_locus_tag carbon_source temperature_celsius \\\n",
+ "0 671 YOR083W glucose 25 \n",
+ "1 550 YMR039C glucose 25 \n",
+ "2 154 YDR216W glucose 25 \n",
+ "3 392 YJL110C glucose 25 \n",
+ "4 700 YOR290C glucose 25 \n",
+ "5 372 YIL131C glucose 25 \n",
+ "6 700 YOR290C glucose 25 \n",
+ "7 372 YIL131C glucose 25 \n",
+ "8 700 YOR290C glucose 25 \n",
+ "9 372 YIL131C glucose 25 \n",
+ "\n",
+ " dto_empirical_pvalue dto_fdr hackett_sample_id perturbation_id_source \n",
+ "0 0.0 0.002385 1393 hackett \n",
+ "1 0.0 0.023965 1132 hackett \n",
+ "2 0.0 0.082601 304 hackett \n",
+ "3 0.0 0.124665 799 hackett \n",
+ "4 0.0 0.079160 1454 hackett \n",
+ "5 0.0 0.059436 732 hackett \n",
+ "6 0.0 0.070062 1453 hackett \n",
+ "7 0.0 0.076569 731 hackett \n",
+ "8 0.0 0.093879 1452 hackett \n",
+ "9 0.0 0.108097 730 hackett "
+ ]
+ },
+ "execution_count": 56,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "rossi_hackett = vdb.query(\"\"\"\n",
+ " SELECT\n",
+ " r.sample_id,\n",
+ " r.regulator_locus_tag,\n",
+ " r.carbon_source,\n",
+ " r.temperature_celsius,\n",
+ " d.dto_empirical_pvalue,\n",
+ " d.dto_fdr,\n",
+ " d.perturbation_id_id AS hackett_sample_id,\n",
+ " d.perturbation_id_source\n",
+ " FROM (\n",
+ " SELECT DISTINCT\n",
+ " sample_id,\n",
+ " regulator_locus_tag,\n",
+ " carbon_source,\n",
+ " temperature_celsius\n",
+ " FROM rossi_2021_af_combined_meta\n",
+ " ) r\n",
+ " JOIN dto_expanded d\n",
+ " ON CAST(r.sample_id AS VARCHAR) = d.binding_id_id\n",
+ " AND d.binding_id_source = 'rossi_2021_af_combined'\n",
+ " WHERE d.perturbation_id_source = 'hackett'\n",
+ " AND d.dto_empirical_pvalue <= 0.01\n",
+ " ORDER BY d.dto_empirical_pvalue\n",
+ "\"\"\")\n",
+ "\n",
+ "print(f\"Number of records that meet the criteria: {len(rossi_hackett)}\")\n",
+ "rossi_hackett.head(10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 57,
+ "id": "9e8e4616",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Number of records that meet the criteria: 946\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " sample_id | \n",
+ " regulator_locus_tag | \n",
+ " regulator_symbol | \n",
+ " condition | \n",
+ " dto_empirical_pvalue | \n",
+ " dto_fdr | \n",
+ " hackett_sample_id | \n",
+ " perturbation_id_source | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 1 | \n",
+ " YBL005W | \n",
+ " PDR3 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.004227 | \n",
+ " 82 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 1 | \n",
+ " YBL005W | \n",
+ " PDR3 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.025297 | \n",
+ " 83 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 1 | \n",
+ " YBL005W | \n",
+ " PDR3 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.040956 | \n",
+ " 84 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 1 | \n",
+ " YBL005W | \n",
+ " PDR3 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.031786 | \n",
+ " 85 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 1 | \n",
+ " YBL005W | \n",
+ " PDR3 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.018509 | \n",
+ " 86 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 1 | \n",
+ " YBL005W | \n",
+ " PDR3 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.017014 | \n",
+ " 87 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 1 | \n",
+ " YBL005W | \n",
+ " PDR3 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.016319 | \n",
+ " 88 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " 100 | \n",
+ " YJL056C | \n",
+ " ZAP1 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.000000 | \n",
+ " 817 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " 100 | \n",
+ " YJL056C | \n",
+ " ZAP1 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.000915 | \n",
+ " 818 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " 100 | \n",
+ " YJL056C | \n",
+ " ZAP1 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.000760 | \n",
+ " 819 | \n",
+ " hackett | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " sample_id regulator_locus_tag regulator_symbol condition \\\n",
+ "0 1 YBL005W PDR3 standard \n",
+ "1 1 YBL005W PDR3 standard \n",
+ "2 1 YBL005W PDR3 standard \n",
+ "3 1 YBL005W PDR3 standard \n",
+ "4 1 YBL005W PDR3 standard \n",
+ "5 1 YBL005W PDR3 standard \n",
+ "6 1 YBL005W PDR3 standard \n",
+ "7 100 YJL056C ZAP1 standard \n",
+ "8 100 YJL056C ZAP1 standard \n",
+ "9 100 YJL056C ZAP1 standard \n",
+ "\n",
+ " dto_empirical_pvalue dto_fdr hackett_sample_id perturbation_id_source \n",
+ "0 0.0 0.004227 82 hackett \n",
+ "1 0.0 0.025297 83 hackett \n",
+ "2 0.0 0.040956 84 hackett \n",
+ "3 0.0 0.031786 85 hackett \n",
+ "4 0.0 0.018509 86 hackett \n",
+ "5 0.0 0.017014 87 hackett \n",
+ "6 0.0 0.016319 88 hackett \n",
+ "7 0.0 0.000000 817 hackett \n",
+ "8 0.0 0.000915 818 hackett \n",
+ "9 0.0 0.000760 819 hackett "
+ ]
+ },
+ "execution_count": 57,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "mahendrawada_hackett = vdb.query(\"\"\"\n",
+ " SELECT\n",
+ " m.sample_id,\n",
+ " m.regulator_locus_tag,\n",
+ " m.regulator_symbol,\n",
+ " m.condition,\n",
+ " d.dto_empirical_pvalue,\n",
+ " d.dto_fdr,\n",
+ " d.perturbation_id_id AS hackett_sample_id,\n",
+ " d.perturbation_id_source\n",
+ " FROM (\n",
+ " SELECT DISTINCT\n",
+ " sample_id,\n",
+ " regulator_locus_tag,\n",
+ " regulator_symbol,\n",
+ " condition\n",
+ " FROM chec_mahendrawada_m2025_af_combined_meta\n",
+ " ) m\n",
+ " JOIN dto_expanded d\n",
+ " ON CAST(m.sample_id AS VARCHAR) = d.binding_id_id\n",
+ " AND d.binding_id_source LIKE '%mahendrawada%af_combined%'\n",
+ " WHERE d.perturbation_id_source = 'hackett'\n",
+ " AND d.dto_empirical_pvalue <= 0.01\n",
+ " ORDER BY d.dto_empirical_pvalue\n",
+ "\"\"\")\n",
+ "\n",
+ "print(f\"Number of records that meet the criteria: {len(mahendrawada_hackett)}\")\n",
+ "mahendrawada_hackett.head(10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 58,
+ "id": "a4f7ee52",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Total number of records after merging: 2540\n",
+ "\n",
+ "Distribution of each dataset:\n",
+ "source_dataset\n",
+ "mahendrawada 946\n",
+ "harbison 910\n",
+ "rossi 684\n",
+ "Name: count, dtype: int64\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " sample_id | \n",
+ " regulator_locus_tag | \n",
+ " dto_empirical_pvalue | \n",
+ " dto_fdr | \n",
+ " hackett_sample_id | \n",
+ " perturbation_id_source | \n",
+ " source_dataset | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 16 | \n",
+ " YBR083W | \n",
+ " 0.0 | \n",
+ " 0.141768 | \n",
+ " 91 | \n",
+ " hackett | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 174 | \n",
+ " YJL056C | \n",
+ " 0.0 | \n",
+ " 0.005249 | \n",
+ " 818 | \n",
+ " hackett | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 38 | \n",
+ " YDL106C | \n",
+ " 0.0 | \n",
+ " 0.263801 | \n",
+ " 190 | \n",
+ " hackett | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 248 | \n",
+ " YMR016C | \n",
+ " 0.0 | \n",
+ " 0.065595 | \n",
+ " 1098 | \n",
+ " hackett | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 50 | \n",
+ " YDR043C | \n",
+ " 0.0 | \n",
+ " 0.167487 | \n",
+ " 249 | \n",
+ " hackett | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 50 | \n",
+ " YDR043C | \n",
+ " 0.0 | \n",
+ " 0.241330 | \n",
+ " 248 | \n",
+ " hackett | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 323 | \n",
+ " YPL049C | \n",
+ " 0.0 | \n",
+ " 0.031633 | \n",
+ " 1598 | \n",
+ " hackett | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " 281 | \n",
+ " YNL199C | \n",
+ " 0.0 | \n",
+ " 0.001701 | \n",
+ " 1251 | \n",
+ " hackett | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " 86 | \n",
+ " YER040W | \n",
+ " 0.0 | \n",
+ " 0.099947 | \n",
+ " 434 | \n",
+ " hackett | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " 282 | \n",
+ " YNL199C | \n",
+ " 0.0 | \n",
+ " 0.047443 | \n",
+ " 1251 | \n",
+ " hackett | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " sample_id regulator_locus_tag dto_empirical_pvalue dto_fdr \\\n",
+ "0 16 YBR083W 0.0 0.141768 \n",
+ "1 174 YJL056C 0.0 0.005249 \n",
+ "2 38 YDL106C 0.0 0.263801 \n",
+ "3 248 YMR016C 0.0 0.065595 \n",
+ "4 50 YDR043C 0.0 0.167487 \n",
+ "5 50 YDR043C 0.0 0.241330 \n",
+ "6 323 YPL049C 0.0 0.031633 \n",
+ "7 281 YNL199C 0.0 0.001701 \n",
+ "8 86 YER040W 0.0 0.099947 \n",
+ "9 282 YNL199C 0.0 0.047443 \n",
+ "\n",
+ " hackett_sample_id perturbation_id_source source_dataset \n",
+ "0 91 hackett harbison \n",
+ "1 818 hackett harbison \n",
+ "2 190 hackett harbison \n",
+ "3 1098 hackett harbison \n",
+ "4 249 hackett harbison \n",
+ "5 248 hackett harbison \n",
+ "6 1598 hackett harbison \n",
+ "7 1251 hackett harbison \n",
+ "8 434 hackett harbison \n",
+ "9 1251 hackett harbison "
+ ]
+ },
+ "execution_count": 58,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import pandas as pd\n",
+ "\n",
+ "common_cols = [\n",
+ " \"sample_id\", \"regulator_locus_tag\",\n",
+ " \"dto_empirical_pvalue\", \"dto_fdr\",\n",
+ " \"hackett_sample_id\", \"perturbation_id_source\"\n",
+ "]\n",
+ "\n",
+ "harbison_hackett[\"source_dataset\"] = \"harbison\"\n",
+ "rossi_hackett[\"source_dataset\"] = \"rossi\"\n",
+ "mahendrawada_hackett[\"source_dataset\"] = \"mahendrawada\"\n",
+ "\n",
+ "hackett_all = pd.concat([\n",
+ " harbison_hackett[common_cols + [\"source_dataset\"]],\n",
+ " rossi_hackett[common_cols + [\"source_dataset\"]],\n",
+ " mahendrawada_hackett[common_cols + [\"source_dataset\"]],\n",
+ "], ignore_index=True)\n",
+ "\n",
+ "print(f\"Total number of records after merging: {len(hackett_all)}\")\n",
+ "print(f\"\\nDistribution of each dataset:\")\n",
+ "print(hackett_all[\"source_dataset\"].value_counts())\n",
+ "hackett_all.head(10)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ae37e5c8",
+ "metadata": {},
+ "source": [
+ "## Step2-Obtain the intersection of the binding dataset and kemmern"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 59,
+ "id": "61741f38",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Number of records that meet the criteria: 224\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " sample_id | \n",
+ " regulator_symbol | \n",
+ " regulator_locus_tag | \n",
+ " condition | \n",
+ " carbon_source | \n",
+ " temperature_celsius | \n",
+ " dto_empirical_pvalue | \n",
+ " dto_fdr | \n",
+ " kemmeren_sample_id | \n",
+ " perturbation_id_source | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 70 | \n",
+ " SUM1 | \n",
+ " YDR310C | \n",
+ " YPD | \n",
+ " glucose | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.013631 | \n",
+ " 299 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 151 | \n",
+ " STE12 | \n",
+ " YHR084W | \n",
+ " Alpha | \n",
+ " glucose | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.128768 | \n",
+ " 622 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 319 | \n",
+ " MET31 | \n",
+ " YPL038W | \n",
+ " SM | \n",
+ " unspecified | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.021299 | \n",
+ " 1367 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 70 | \n",
+ " SUM1 | \n",
+ " YDR310C | \n",
+ " YPD | \n",
+ " glucose | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.006238 | \n",
+ " 299 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 151 | \n",
+ " STE12 | \n",
+ " YHR084W | \n",
+ " Alpha | \n",
+ " glucose | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.117883 | \n",
+ " 622 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 242 | \n",
+ " GAL80 | \n",
+ " YML051W | \n",
+ " YPD | \n",
+ " glucose | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.000000 | \n",
+ " 1006 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 319 | \n",
+ " MET31 | \n",
+ " YPL038W | \n",
+ " SM | \n",
+ " unspecified | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.026317 | \n",
+ " 1367 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " 323 | \n",
+ " DIG1 | \n",
+ " YPL049C | \n",
+ " BUT90 | \n",
+ " glucose | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.236502 | \n",
+ " 1372 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " 49 | \n",
+ " NRG1 | \n",
+ " YDR043C | \n",
+ " H2O2Hi | \n",
+ " glucose | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.230039 | \n",
+ " 221 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " 198 | \n",
+ " RGT1 | \n",
+ " YKL038W | \n",
+ " YPD | \n",
+ " glucose | \n",
+ " 30.0 | \n",
+ " 0.0 | \n",
+ " 0.003463 | \n",
+ " 786 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " sample_id regulator_symbol regulator_locus_tag condition carbon_source \\\n",
+ "0 70 SUM1 YDR310C YPD glucose \n",
+ "1 151 STE12 YHR084W Alpha glucose \n",
+ "2 319 MET31 YPL038W SM unspecified \n",
+ "3 70 SUM1 YDR310C YPD glucose \n",
+ "4 151 STE12 YHR084W Alpha glucose \n",
+ "5 242 GAL80 YML051W YPD glucose \n",
+ "6 319 MET31 YPL038W SM unspecified \n",
+ "7 323 DIG1 YPL049C BUT90 glucose \n",
+ "8 49 NRG1 YDR043C H2O2Hi glucose \n",
+ "9 198 RGT1 YKL038W YPD glucose \n",
+ "\n",
+ " temperature_celsius dto_empirical_pvalue dto_fdr kemmeren_sample_id \\\n",
+ "0 30.0 0.0 0.013631 299 \n",
+ "1 30.0 0.0 0.128768 622 \n",
+ "2 30.0 0.0 0.021299 1367 \n",
+ "3 30.0 0.0 0.006238 299 \n",
+ "4 30.0 0.0 0.117883 622 \n",
+ "5 30.0 0.0 0.000000 1006 \n",
+ "6 30.0 0.0 0.026317 1367 \n",
+ "7 30.0 0.0 0.236502 1372 \n",
+ "8 30.0 0.0 0.230039 221 \n",
+ "9 30.0 0.0 0.003463 786 \n",
+ "\n",
+ " perturbation_id_source \n",
+ "0 kemmeren \n",
+ "1 kemmeren \n",
+ "2 kemmeren \n",
+ "3 kemmeren \n",
+ "4 kemmeren \n",
+ "5 kemmeren \n",
+ "6 kemmeren \n",
+ "7 kemmeren \n",
+ "8 kemmeren \n",
+ "9 kemmeren "
+ ]
+ },
+ "execution_count": 59,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "harbison_kemmeren = vdb.query(\"\"\"\n",
+ " SELECT\n",
+ " h.sample_id,\n",
+ " h.regulator_symbol,\n",
+ " h.regulator_locus_tag,\n",
+ " h.condition,\n",
+ " h.carbon_source,\n",
+ " h.temperature_celsius,\n",
+ " d.dto_empirical_pvalue,\n",
+ " d.dto_fdr,\n",
+ " d.perturbation_id_id AS kemmeren_sample_id,\n",
+ " d.perturbation_id_source\n",
+ " FROM harbison_meta h\n",
+ " JOIN dto_expanded d\n",
+ " ON CAST(h.sample_id AS VARCHAR) = d.binding_id_id\n",
+ " AND d.binding_id_source = 'harbison'\n",
+ " WHERE d.perturbation_id_source = 'kemmeren'\n",
+ " AND d.dto_empirical_pvalue <= 0.01\n",
+ " ORDER BY d.dto_empirical_pvalue\n",
+ "\"\"\")\n",
+ "\n",
+ "print(f\"Number of records that meet the criteria: {len(harbison_kemmeren)}\")\n",
+ "harbison_kemmeren.head(10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 60,
+ "id": "cd3e4a4c",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Number of records that meet the criteria: 389\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " sample_id | \n",
+ " regulator_locus_tag | \n",
+ " carbon_source | \n",
+ " temperature_celsius | \n",
+ " dto_empirical_pvalue | \n",
+ " dto_fdr | \n",
+ " kemmeren_sample_id | \n",
+ " perturbation_id_source | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 478 | \n",
+ " YLR182W | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.084524 | \n",
+ " 913 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 291 | \n",
+ " YGL237C | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.010760 | \n",
+ " 521 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 208 | \n",
+ " YEL018W | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.218327 | \n",
+ " 361 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 487 | \n",
+ " YLR256W | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.000000 | \n",
+ " 932 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 269 | \n",
+ " YGL071W | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.174709 | \n",
+ " 471 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 32 | \n",
+ " YBR010W | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.240309 | \n",
+ " 60 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 470 | \n",
+ " YLR098C | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.000020 | \n",
+ " 894 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " 467 | \n",
+ " YLR085C | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.252903 | \n",
+ " 889 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " 639 | \n",
+ " YOL004W | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.215319 | \n",
+ " 1233 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " 21 | \n",
+ " YBL021C | \n",
+ " glucose | \n",
+ " 25 | \n",
+ " 0.0 | \n",
+ " 0.056864 | \n",
+ " 39 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " sample_id regulator_locus_tag carbon_source temperature_celsius \\\n",
+ "0 478 YLR182W glucose 25 \n",
+ "1 291 YGL237C glucose 25 \n",
+ "2 208 YEL018W glucose 25 \n",
+ "3 487 YLR256W glucose 25 \n",
+ "4 269 YGL071W glucose 25 \n",
+ "5 32 YBR010W glucose 25 \n",
+ "6 470 YLR098C glucose 25 \n",
+ "7 467 YLR085C glucose 25 \n",
+ "8 639 YOL004W glucose 25 \n",
+ "9 21 YBL021C glucose 25 \n",
+ "\n",
+ " dto_empirical_pvalue dto_fdr kemmeren_sample_id perturbation_id_source \n",
+ "0 0.0 0.084524 913 kemmeren \n",
+ "1 0.0 0.010760 521 kemmeren \n",
+ "2 0.0 0.218327 361 kemmeren \n",
+ "3 0.0 0.000000 932 kemmeren \n",
+ "4 0.0 0.174709 471 kemmeren \n",
+ "5 0.0 0.240309 60 kemmeren \n",
+ "6 0.0 0.000020 894 kemmeren \n",
+ "7 0.0 0.252903 889 kemmeren \n",
+ "8 0.0 0.215319 1233 kemmeren \n",
+ "9 0.0 0.056864 39 kemmeren "
+ ]
+ },
+ "execution_count": 60,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "rossi_kemmeren = vdb.query(\"\"\"\n",
+ " SELECT\n",
+ " r.sample_id,\n",
+ " r.regulator_locus_tag,\n",
+ " r.carbon_source,\n",
+ " r.temperature_celsius,\n",
+ " d.dto_empirical_pvalue,\n",
+ " d.dto_fdr,\n",
+ " d.perturbation_id_id AS kemmeren_sample_id,\n",
+ " d.perturbation_id_source\n",
+ " FROM (\n",
+ " SELECT DISTINCT\n",
+ " sample_id,\n",
+ " regulator_locus_tag,\n",
+ " carbon_source,\n",
+ " temperature_celsius\n",
+ " FROM rossi_2021_af_combined_meta\n",
+ " ) r\n",
+ " JOIN dto_expanded d\n",
+ " ON CAST(r.sample_id AS VARCHAR) = d.binding_id_id\n",
+ " AND d.binding_id_source = 'rossi_2021_af_combined'\n",
+ " WHERE d.perturbation_id_source = 'kemmeren'\n",
+ " AND d.dto_empirical_pvalue <= 0.01\n",
+ " ORDER BY d.dto_empirical_pvalue\n",
+ "\"\"\")\n",
+ "\n",
+ "print(f\"Number of records that meet the criteria: {len(rossi_kemmeren)}\")\n",
+ "rossi_kemmeren.head(10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 61,
+ "id": "6071cf05",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Number of records that meet the criteria: 262\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " sample_id | \n",
+ " regulator_locus_tag | \n",
+ " regulator_symbol | \n",
+ " condition | \n",
+ " dto_empirical_pvalue | \n",
+ " dto_fdr | \n",
+ " kemmeren_sample_id | \n",
+ " perturbation_id_source | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 1 | \n",
+ " YBL005W | \n",
+ " PDR3 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.077667 | \n",
+ " 31 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 5 | \n",
+ " YBR083W | \n",
+ " TEC1 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.065859 | \n",
+ " 74 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 100 | \n",
+ " YJL056C | \n",
+ " ZAP1 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.302421 | \n",
+ " 709 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 101 | \n",
+ " YJL110C | \n",
+ " GZF3 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.117351 | \n",
+ " 723 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 102 | \n",
+ " YJL176C | \n",
+ " SWI3 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.127255 | \n",
+ " 736 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 9 | \n",
+ " YBR239C | \n",
+ " ERT1 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.147725 | \n",
+ " 106 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 104 | \n",
+ " YJR060W | \n",
+ " CBF1 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.166077 | \n",
+ " 754 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " 106 | \n",
+ " YJR140C | \n",
+ " HIR3 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.358890 | \n",
+ " 772 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " 90 | \n",
+ " YHR178W | \n",
+ " STB5 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.315486 | \n",
+ " 642 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " 11 | \n",
+ " YBR289W | \n",
+ " SNF5 | \n",
+ " standard | \n",
+ " 0.0 | \n",
+ " 0.133379 | \n",
+ " 120 | \n",
+ " kemmeren | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " sample_id regulator_locus_tag regulator_symbol condition \\\n",
+ "0 1 YBL005W PDR3 standard \n",
+ "1 5 YBR083W TEC1 standard \n",
+ "2 100 YJL056C ZAP1 standard \n",
+ "3 101 YJL110C GZF3 standard \n",
+ "4 102 YJL176C SWI3 standard \n",
+ "5 9 YBR239C ERT1 standard \n",
+ "6 104 YJR060W CBF1 standard \n",
+ "7 106 YJR140C HIR3 standard \n",
+ "8 90 YHR178W STB5 standard \n",
+ "9 11 YBR289W SNF5 standard \n",
+ "\n",
+ " dto_empirical_pvalue dto_fdr kemmeren_sample_id perturbation_id_source \n",
+ "0 0.0 0.077667 31 kemmeren \n",
+ "1 0.0 0.065859 74 kemmeren \n",
+ "2 0.0 0.302421 709 kemmeren \n",
+ "3 0.0 0.117351 723 kemmeren \n",
+ "4 0.0 0.127255 736 kemmeren \n",
+ "5 0.0 0.147725 106 kemmeren \n",
+ "6 0.0 0.166077 754 kemmeren \n",
+ "7 0.0 0.358890 772 kemmeren \n",
+ "8 0.0 0.315486 642 kemmeren \n",
+ "9 0.0 0.133379 120 kemmeren "
+ ]
+ },
+ "execution_count": 61,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "mahendrawada_kemmeren = vdb.query(\"\"\"\n",
+ " SELECT\n",
+ " m.sample_id,\n",
+ " m.regulator_locus_tag,\n",
+ " m.regulator_symbol,\n",
+ " m.condition,\n",
+ " d.dto_empirical_pvalue,\n",
+ " d.dto_fdr,\n",
+ " d.perturbation_id_id AS kemmeren_sample_id,\n",
+ " d.perturbation_id_source\n",
+ " FROM (\n",
+ " SELECT DISTINCT\n",
+ " sample_id,\n",
+ " regulator_locus_tag,\n",
+ " regulator_symbol,\n",
+ " condition\n",
+ " FROM chec_mahendrawada_m2025_af_combined_meta\n",
+ " ) m\n",
+ " JOIN dto_expanded d\n",
+ " ON CAST(m.sample_id AS VARCHAR) = d.binding_id_id\n",
+ " AND d.binding_id_source LIKE '%mahendrawada%af_combined%'\n",
+ " WHERE d.perturbation_id_source = 'kemmeren'\n",
+ " AND d.dto_empirical_pvalue <= 0.01\n",
+ " ORDER BY d.dto_empirical_pvalue\n",
+ "\"\"\")\n",
+ "\n",
+ "print(f\"Number of records that meet the criteria: {len(mahendrawada_kemmeren)}\")\n",
+ "mahendrawada_kemmeren.head(10)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 62,
+ "id": "274eab77",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Total number of records after merging: 875\n",
+ "\n",
+ "Distribution among datasets:\n",
+ "source_dataset\n",
+ "rossi 389\n",
+ "mahendrawada 262\n",
+ "harbison 224\n",
+ "Name: count, dtype: int64\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " sample_id | \n",
+ " regulator_locus_tag | \n",
+ " dto_empirical_pvalue | \n",
+ " dto_fdr | \n",
+ " kemmeren_sample_id | \n",
+ " perturbation_id_source | \n",
+ " source_dataset | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 70 | \n",
+ " YDR310C | \n",
+ " 0.0 | \n",
+ " 0.013631 | \n",
+ " 299 | \n",
+ " kemmeren | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 151 | \n",
+ " YHR084W | \n",
+ " 0.0 | \n",
+ " 0.128768 | \n",
+ " 622 | \n",
+ " kemmeren | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 319 | \n",
+ " YPL038W | \n",
+ " 0.0 | \n",
+ " 0.021299 | \n",
+ " 1367 | \n",
+ " kemmeren | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 70 | \n",
+ " YDR310C | \n",
+ " 0.0 | \n",
+ " 0.006238 | \n",
+ " 299 | \n",
+ " kemmeren | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 151 | \n",
+ " YHR084W | \n",
+ " 0.0 | \n",
+ " 0.117883 | \n",
+ " 622 | \n",
+ " kemmeren | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 242 | \n",
+ " YML051W | \n",
+ " 0.0 | \n",
+ " 0.000000 | \n",
+ " 1006 | \n",
+ " kemmeren | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 319 | \n",
+ " YPL038W | \n",
+ " 0.0 | \n",
+ " 0.026317 | \n",
+ " 1367 | \n",
+ " kemmeren | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " 323 | \n",
+ " YPL049C | \n",
+ " 0.0 | \n",
+ " 0.236502 | \n",
+ " 1372 | \n",
+ " kemmeren | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " 49 | \n",
+ " YDR043C | \n",
+ " 0.0 | \n",
+ " 0.230039 | \n",
+ " 221 | \n",
+ " kemmeren | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " 198 | \n",
+ " YKL038W | \n",
+ " 0.0 | \n",
+ " 0.003463 | \n",
+ " 786 | \n",
+ " kemmeren | \n",
+ " harbison | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " sample_id regulator_locus_tag dto_empirical_pvalue dto_fdr \\\n",
+ "0 70 YDR310C 0.0 0.013631 \n",
+ "1 151 YHR084W 0.0 0.128768 \n",
+ "2 319 YPL038W 0.0 0.021299 \n",
+ "3 70 YDR310C 0.0 0.006238 \n",
+ "4 151 YHR084W 0.0 0.117883 \n",
+ "5 242 YML051W 0.0 0.000000 \n",
+ "6 319 YPL038W 0.0 0.026317 \n",
+ "7 323 YPL049C 0.0 0.236502 \n",
+ "8 49 YDR043C 0.0 0.230039 \n",
+ "9 198 YKL038W 0.0 0.003463 \n",
+ "\n",
+ " kemmeren_sample_id perturbation_id_source source_dataset \n",
+ "0 299 kemmeren harbison \n",
+ "1 622 kemmeren harbison \n",
+ "2 1367 kemmeren harbison \n",
+ "3 299 kemmeren harbison \n",
+ "4 622 kemmeren harbison \n",
+ "5 1006 kemmeren harbison \n",
+ "6 1367 kemmeren harbison \n",
+ "7 1372 kemmeren harbison \n",
+ "8 221 kemmeren harbison \n",
+ "9 786 kemmeren harbison "
+ ]
+ },
+ "execution_count": 62,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "import pandas as pd\n",
+ "\n",
+ "common_cols = [\n",
+ " \"sample_id\", \"regulator_locus_tag\",\n",
+ " \"dto_empirical_pvalue\", \"dto_fdr\",\n",
+ " \"kemmeren_sample_id\", \"perturbation_id_source\"\n",
+ "]\n",
+ "\n",
+ "harbison_kemmeren[\"source_dataset\"] = \"harbison\"\n",
+ "rossi_kemmeren[\"source_dataset\"] = \"rossi\"\n",
+ "mahendrawada_kemmeren[\"source_dataset\"] = \"mahendrawada\"\n",
+ "\n",
+ "kemmeren_all = pd.concat([\n",
+ " harbison_kemmeren[common_cols + [\"source_dataset\"]],\n",
+ " rossi_kemmeren[common_cols + [\"source_dataset\"]],\n",
+ " mahendrawada_kemmeren[common_cols + [\"source_dataset\"]],\n",
+ "], ignore_index=True)\n",
+ "\n",
+ "print(f\"Total number of records after merging: {len(kemmeren_all)}\")\n",
+ "print(f\"\\nDistribution among datasets:\")\n",
+ "print(kemmeren_all[\"source_dataset\"].value_counts())\n",
+ "kemmeren_all.head(10)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "adad7e17",
+ "metadata": {},
+ "source": [
+ "## Step3-Take the intersection of Hackett and Kemmern"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 63,
+ "id": "437193f8",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Number of significant samples in Hackett: 404\n",
+ "Number of significant samples in Kemmeren: 472\n",
+ "Intersection (active set): 278\n",
+ "\n",
+ "Distribution among datasets:\n",
+ "source_dataset\n",
+ "mahendrawada 104\n",
+ "harbison 96\n",
+ "rossi 78\n",
+ "Name: count, dtype: int64\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " source_dataset | \n",
+ " sample_id | \n",
+ " regulator_locus_tag | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " harbison | \n",
+ " 16 | \n",
+ " YBR083W | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " harbison | \n",
+ " 248 | \n",
+ " YMR016C | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " harbison | \n",
+ " 50 | \n",
+ " YDR043C | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " harbison | \n",
+ " 323 | \n",
+ " YPL049C | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " harbison | \n",
+ " 281 | \n",
+ " YNL199C | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " harbison | \n",
+ " 86 | \n",
+ " YER040W | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " harbison | \n",
+ " 282 | \n",
+ " YNL199C | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " harbison | \n",
+ " 18 | \n",
+ " YBR083W | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " harbison | \n",
+ " 7 | \n",
+ " YBL103C | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " harbison | \n",
+ " 225 | \n",
+ " YLR176C | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " source_dataset sample_id regulator_locus_tag\n",
+ "0 harbison 16 YBR083W\n",
+ "1 harbison 248 YMR016C\n",
+ "2 harbison 50 YDR043C\n",
+ "3 harbison 323 YPL049C\n",
+ "4 harbison 281 YNL199C\n",
+ "5 harbison 86 YER040W\n",
+ "6 harbison 282 YNL199C\n",
+ "7 harbison 18 YBR083W\n",
+ "8 harbison 7 YBL103C\n",
+ "9 harbison 225 YLR176C"
+ ]
+ },
+ "execution_count": 63,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Use (source_dataset, sample_id) to uniquely identify a binding sample\n",
+ "hackett_keys = hackett_all[[\"source_dataset\", \"sample_id\", \"regulator_locus_tag\"]].drop_duplicates()\n",
+ "kemmeren_keys = kemmeren_all[[\"source_dataset\", \"sample_id\", \"regulator_locus_tag\"]].drop_duplicates()\n",
+ "\n",
+ "# Inner join = intersection\n",
+ "active_set = pd.merge(\n",
+ " hackett_keys,\n",
+ " kemmeren_keys,\n",
+ " on=[\"source_dataset\", \"sample_id\", \"regulator_locus_tag\"],\n",
+ " how=\"inner\"\n",
+ ")\n",
+ "\n",
+ "print(f\"Number of significant samples in Hackett: {len(hackett_keys)}\")\n",
+ "print(f\"Number of significant samples in Kemmeren: {len(kemmeren_keys)}\")\n",
+ "print(f\"Intersection (active set): {len(active_set)}\")\n",
+ "print(f\"\\nDistribution among datasets:\")\n",
+ "print(active_set[\"source_dataset\"].value_counts())\n",
+ "active_set.head(10)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "db6ea6c8",
+ "metadata": {},
+ "source": [
+ "## Step4-Statistics"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 64,
+ "id": "6f262b24",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "There are 119 different regulators in the active set.\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " regulator_locus_tag | \n",
+ " n_active_samples | \n",
+ " datasets | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " YEL009C | \n",
+ " 18 | \n",
+ " harbison, mahendrawada, rossi | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " YHR206W | \n",
+ " 6 | \n",
+ " harbison, mahendrawada, rossi | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " YBL103C | \n",
+ " 6 | \n",
+ " harbison, mahendrawada, rossi | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " YPL049C | \n",
+ " 6 | \n",
+ " harbison, mahendrawada, rossi | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " YDR043C | \n",
+ " 5 | \n",
+ " harbison, mahendrawada, rossi | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " YDL056W | \n",
+ " 5 | \n",
+ " harbison, mahendrawada, rossi | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " YHR084W | \n",
+ " 5 | \n",
+ " harbison, mahendrawada, rossi | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " YMR037C | \n",
+ " 5 | \n",
+ " harbison, mahendrawada | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " YNL068C | \n",
+ " 5 | \n",
+ " harbison, mahendrawada, rossi | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " YER040W | \n",
+ " 4 | \n",
+ " harbison, mahendrawada, rossi | \n",
+ "
\n",
+ " \n",
+ " | 10 | \n",
+ " YNL314W | \n",
+ " 4 | \n",
+ " harbison, mahendrawada | \n",
+ "
\n",
+ " \n",
+ " | 11 | \n",
+ " YJR060W | \n",
+ " 4 | \n",
+ " harbison, mahendrawada, rossi | \n",
+ "
\n",
+ " \n",
+ " | 12 | \n",
+ " YIR023W | \n",
+ " 4 | \n",
+ " harbison, mahendrawada | \n",
+ "
\n",
+ " \n",
+ " | 13 | \n",
+ " YOR028C | \n",
+ " 4 | \n",
+ " harbison, rossi | \n",
+ "
\n",
+ " \n",
+ " | 14 | \n",
+ " YPL038W | \n",
+ " 4 | \n",
+ " harbison, mahendrawada, rossi | \n",
+ "
\n",
+ " \n",
+ " | 15 | \n",
+ " YKR099W | \n",
+ " 4 | \n",
+ " harbison, mahendrawada, rossi | \n",
+ "
\n",
+ " \n",
+ " | 16 | \n",
+ " YLR451W | \n",
+ " 4 | \n",
+ " harbison, mahendrawada, rossi | \n",
+ "
\n",
+ " \n",
+ " | 17 | \n",
+ " YOR358W | \n",
+ " 4 | \n",
+ " harbison, mahendrawada, rossi | \n",
+ "
\n",
+ " \n",
+ " | 18 | \n",
+ " YBR083W | \n",
+ " 4 | \n",
+ " harbison, mahendrawada | \n",
+ "
\n",
+ " \n",
+ " | 19 | \n",
+ " YDR310C | \n",
+ " 3 | \n",
+ " harbison, mahendrawada, rossi | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " regulator_locus_tag n_active_samples datasets\n",
+ "0 YEL009C 18 harbison, mahendrawada, rossi\n",
+ "1 YHR206W 6 harbison, mahendrawada, rossi\n",
+ "2 YBL103C 6 harbison, mahendrawada, rossi\n",
+ "3 YPL049C 6 harbison, mahendrawada, rossi\n",
+ "4 YDR043C 5 harbison, mahendrawada, rossi\n",
+ "5 YDL056W 5 harbison, mahendrawada, rossi\n",
+ "6 YHR084W 5 harbison, mahendrawada, rossi\n",
+ "7 YMR037C 5 harbison, mahendrawada\n",
+ "8 YNL068C 5 harbison, mahendrawada, rossi\n",
+ "9 YER040W 4 harbison, mahendrawada, rossi\n",
+ "10 YNL314W 4 harbison, mahendrawada\n",
+ "11 YJR060W 4 harbison, mahendrawada, rossi\n",
+ "12 YIR023W 4 harbison, mahendrawada\n",
+ "13 YOR028C 4 harbison, rossi\n",
+ "14 YPL038W 4 harbison, mahendrawada, rossi\n",
+ "15 YKR099W 4 harbison, mahendrawada, rossi\n",
+ "16 YLR451W 4 harbison, mahendrawada, rossi\n",
+ "17 YOR358W 4 harbison, mahendrawada, rossi\n",
+ "18 YBR083W 4 harbison, mahendrawada\n",
+ "19 YDR310C 3 harbison, mahendrawada, rossi"
+ ]
+ },
+ "execution_count": 64,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "regulator_counts = (\n",
+ " active_set\n",
+ " .groupby(\"regulator_locus_tag\")\n",
+ " .agg(\n",
+ " n_active_samples=(\"sample_id\", \"nunique\"),\n",
+ " datasets=(\"source_dataset\", lambda x: \", \".join(sorted(x.unique())))\n",
+ " )\n",
+ " .sort_values(\"n_active_samples\", ascending=False)\n",
+ " .reset_index()\n",
+ ")\n",
+ "\n",
+ "print(f\"There are {len(regulator_counts)} different regulators in the active set.\")\n",
+ "regulator_counts.head(20)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 65,
+ "id": "53a236f7",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAA90AAAHpCAYAAACful8UAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQAAfLRJREFUeJzt3Xd4FNX79/HPJiGFVAKBAIEQem8BIbTQI00QlCJ+KdKUIFUpNoogRSmCFEEFLHQEKdKrIB1CUUA60msSQg+Z5w+e7I8lhSxmWQLv13XtdWXOzJy5Z3Y2yb3nzDkmwzAMAQAAAACAVOdg7wAAAAAAAHhRkXQDAAAAAGAjJN0AAAAAANgISTcAAAAAADZC0g0AAAAAgI2QdAMAAAAAYCMk3QAAAAAA2AhJNwAAAAAANkLSDQAAAACAjZB0A8BTGjBggEwm0zM5VtWqVVW1alXz8vr162UymTRv3rxncvw2bdooV65cz+RYTysmJkbt27eXv7+/TCaTunfvbtd4Tp48KZPJpGnTptk1jrTiWX6eAAB4lki6AUDStGnTZDKZzC9XV1dly5ZNYWFhGjt2rG7cuJEqxzl37pwGDBigiIiIVKkvNT3PsaXEF198oWnTpum9997TTz/9pP/973/P5LgzZszQmDFjnsmx8OJI6583e2nTpo3F7+qkXm3atJH08AvLpLY5dOiQfU8GwEvDyd4BAMDzZNCgQQoKCtL9+/d14cIFrV+/Xt27d9eoUaO0aNEiFS9e3LztJ598or59+1pV/7lz5zRw4EDlypVLJUuWTPF+K1eutOo4TyO52KZMmaK4uDibx/BfrF27VuXLl1f//v2f6XFnzJihAwcOJGhZDwwM1O3bt5UuXbpnGg/Shqf9XfCy69Spk2rWrGlePnHihD777DN17NhRlStXNpfnyZPH/HNAQICGDh2aoK5s2bLZNlgA+P9IugHgEXXq1FGZMmXMy/369dPatWtVv359vfbaazp48KDc3NwkSU5OTnJysu2v0Vu3bil9+vRydna26XGeJC0kjpcuXVLhwoXtHYZZfI8J4EVx8+ZNubu72zWGkJAQhYSEmJd37typzz77TCEhIXr77bcT3cfb2zvJdQDwLNC9HACeoHr16vr000916tQp/fzzz+byxJ5BXbVqlSpVqiQfHx95eHioQIEC+uijjyQ9fA67bNmykqS2bduauzjGP/NbtWpVFS1aVLt27VKVKlWUPn16876PP9Md78GDB/roo4/k7+8vd3d3vfbaa/r3338ttsmVK5e5q+WjHq3zSbEl9kz3zZs31atXL+XIkUMuLi4qUKCAvvrqKxmGYbGdyWRSly5dtHDhQhUtWlQuLi4qUqSIli9fnvgFf8ylS5fUrl07ZcmSRa6uripRooSmT59uXh//fPuJEye0dOlSc+wnT55Mss6pU6eqevXqypw5s1xcXFS4cGFNnDgx0W2XLVum0NBQeXp6ysvLS2XLltWMGTPM13Dp0qU6deqU+bjx1+nxZ7q/+uormUwmnTp1KsEx+vXrJ2dnZ12/ft1ctm3bNr366qvy9vZW+vTpFRoaqs2bN6fomo0bN05FihRR+vTplSFDBpUpU8YcsySdOnVKnTt3VoECBeTm5qaMGTPqzTffTHDN4h+72LRpk7p27So/Pz/5+PioU6dOunfvniIjI9WqVStlyJBBGTJkUO/evS3e//hr8NVXX2n06NEKDAyUm5ubQkNDdeDAgRSdy88//6zg4GC5ubnJ19dXzZs3T3CPJ+Xs2bNq166dsmXLJhcXFwUFBem9997TvXv3zNscP35cb775pnx9fZU+fXqVL19eS5cuTfQ6PH594u+99evXm8viP8d///23qlWrpvTp0yt79uwaMWKExX7Jfd6OHDmiJk2ayN/fX66urgoICFDz5s0VFRWV7Pn+8ccfevPNN5UzZ065uLgoR44c6tGjh27fvp1g20OHDqlp06by8/OTm5ubChQooI8//ti8Pv73299//6233npLGTJkUKVKlSRJsbGx+vzzz5UnTx65uLgoV65c+uijj3T37l2LY+zcuVNhYWHKlCmT3NzcFBQUpHfeecdim1mzZik4ONj8+SpWrJi+/vrrZM8ztd2/f18DBw5Uvnz55OrqqowZM6pSpUpatWrVM40DwIuLlm4ASIH//e9/+uijj7Ry5Up16NAh0W3++usv1a9fX8WLF9egQYPk4uKio0ePmhOlQoUKadCgQQm6QlaoUMFcx9WrV1WnTh01b95cb7/9trJkyZJsXEOGDJHJZFKfPn106dIljRkzRjVr1lRERIS5RT4lUhLbowzD0GuvvaZ169apXbt2KlmypFasWKEPP/xQZ8+e1ejRoy2237Rpk3799Vd17txZnp6eGjt2rJo0aaLT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Gih//vwvXcJtGIbu3LkjNzc3m9TftGlTvfnmmzp+/Lhy585tk2MAgDXoXg4AqeDEiRPat2+fatasmeJ9MmbMqFmzZsnJyUlDhgyx+phnzpzR999/r+rVq1sk3PHCw8NVrVo1fffddzpz5ozV9Ts4OJgT/ZMnT6ZonyNHjmjMmDGqVauWRVIyb948lS1b1iIJLliwoGrUqKE5c+YkW2d0dLRWrVqlt99+25xwS1KrVq3k4eFhsb+Li4v8/f1TFGtiEnum22QyqUuXLlq4cKGKFi0qFxcXFSlSRMuXL09xvQ8ePNBHH30kf39/ubu767XXXtO///6bYLu5c+cqODhYbm5uypQpk95++22dPXvWvL5NmzYaP368Oa741+MmT56sPHnyyMXFRWXLltWOHTtSHKs1fvvtN9WrV0/ZsmWTi4uL8uTJo88//1wPHjxIsO22bdtUt25dZciQQe7u7ipevLi+/vrrZOuPiIiQn5+fqlatan6U4OzZs3rnnXeUJUsW83vxww8/mPdZv369+T5r27at+RpNmzZNVatW1dKlS3Xq1Clzea5cuZKNIX67x2dYdXFxScklStQff/yhevXqKW/evFq9enWCnh7Lli1T5cqV5e7uLk9PT9WrV09//fWXxTbx3f1Pnz6t+vXry8PDQ9mzZzffH/v371f16tXl7u6uwMBAzZgxw2L/adOmyWQyadOmTeratav8/Pzk4+OjTp066d69e4qMjFSrVq2UIUMGZciQQb17905wDeLi4jRmzBgVKVJErq6uypIlizp16qTr169bbJcrVy7Vr19fK1asUJkyZeTm5qZvv/1W0sNeNd27d1eOHDnk4uKivHnzavjw4RbjYjw6XkFK7u3438O//fabNW8LANgMX+cDQCr4888/JUmlS5e2ar+cOXMqNDRU69atU3R0tEVS+STLli3TgwcP1KpVqyS3adWqldatW6fly5dbdFtPqWPHjklSkt2/7927pw0bNmjp0qX6/fffdeTIEbm4uKhq1apydHSU9PAf83379umdd95JsP8rr7yilStX6saNG/L09Ez0GPv371dsbKzKlCljUe7s7KySJUtqz549Vp+XtTZt2qRff/1VnTt3lqenp8aOHasmTZro9OnTT+waL0lDhgyRyWRSnz59dOnSJY0ZM0Y1a9ZURESEubVv2rRpatu2rcqWLauhQ4fq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v/76S5988onWrl2b4IudqKgoSf/3iEJi02U97s6dO6pXr56Cg4M1Z84ci0HtLl++rMjISE2ePFmTJ09OdP9Lly498RjW2Lp1qxYsWKA5c+YoKChIy5cvV4UKFVSzZk398ccfypIliw4cOCAnJycFBwc/sb68efOqVatW6tOnj1q0aKG5c+eaH8OQHo6JIEnVq1dPdP/HE3VXV1f5+flZlHl7eysgICDBFxre3t6J3gOP3y/e3t6SpBw5ciS7/5EjRxQVFaXMmTMnGuvj78Xj3drj69i3b1+Cc0iqDmvubcMwEv1SBwDsgaQbAFJBxowZFRsbm+yzyUk5cOCAHB0dE/2nNDnxU4jt27cvwbRI8fbt2ydJKly48BPrc3R0fOJAcBUrVtS+fft0+vRpLV26VEuXLtXnn3+ujz76SAEBAapXr57q1q2rGjVqmFu8fX195eLiovPnzyeoL74suZHRs2bNarHt4/v/l1HVU+rRxOhRxmMDSz0PnlWskZGRCg0NlZeXlwYNGqQ8efLI1dVVu3fvVp8+fSwGwkopFxcX1a1bV7/99puWL1+u+vXrm9fF1/f222+rdevWie6f1Bc/Tyt+rIby5ctLevil04oVK1SpUiXVqlVL69ev1+TJk1W3bt0ErfhJ6d27t65evaoRI0aoQ4cO+v77783JYfw5/vTTT4kOCPj4yPpJvdfW3APW1PHo/nFxccqcObN++eWXRPd/PJFO7MuxuLg41apVS7179060jvz586co1sTO6/r16wmelwcAeyHpBoBUULBgQUkPRzG35h//06dPa8OGDQoJCbE6Wa9Tp44cHR31008/JTmY2o8//ignJye9+uqrVtX9JDlz5tR7772n9957T7dv39batWvNSfi3334rFxcXRUdHy9nZWQ4ODipWrJh27tyZoJ5t27Ypd+7cyZ570aJF5eTkpJ07d1p0mb13754iIiIsyp5X8S2Y8QzD0NGjR833SmBgoKSHg0093sp5+PBh83op8S7Z9rB+/XpdvXpVv/76q6pUqWIuP3HihMV28d3yDxw48MQvdUwmk3755Rc1bNhQb775ppYtW2YeQd/Pz0+enp568OBBiup5mnVJbfvvv/+aW37ju/vXqFFDwcHBOn36tHkk7pQaPny4rl27pu+++04ZMmTQyJEjJf3ftcqcObNVMyHYQ548ebR69WpVrFjx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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "dist = regulator_counts[\"n_active_samples\"].value_counts().sort_index()\n",
+ "\n",
+ "fig, ax = plt.subplots(figsize=(10, 5))\n",
+ "dist.plot(kind=\"bar\", ax=ax)\n",
+ "ax.set_xlabel(\"Number of active samples per regulator\")\n",
+ "ax.set_ylabel(\"Number of regulators (TFs)\")\n",
+ "ax.set_title(\"Distribution of active sample counts across TFs\\n(DTO P≤0.01 in both Hackett & Kemmeren)\")\n",
+ "ax.set_xticklabels(ax.get_xticklabels(), rotation=0)\n",
+ "\n",
+ "for i, (x, y) in enumerate(zip(dist.index, dist.values)):\n",
+ " ax.text(i, y + 0.5, str(y), ha=\"center\", fontsize=9)\n",
+ "\n",
+ "plt.tight_layout()\n",
+ "plt.show()"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": ".venv",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.13"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/tfbpapi/datasets.yaml b/tfbpapi/datasets.yaml
new file mode 100644
index 0000000..2d3044a
--- /dev/null
+++ b/tfbpapi/datasets.yaml
@@ -0,0 +1,139 @@
+repositories:
+ BrentLab/harbison_2004:
+ dataset:
+ # binding
+ harbison_2004:
+ db_name: harbison
+ sample_id:
+ field: sample_id
+ carbon_source:
+ field: condition
+ path: media.carbon_source.compound
+ temperature_celsius:
+ field: condition
+ path: temperature_celsius
+ dtype: numeric
+ regulator_locus_tag:
+ field: regulator_locus_tag
+ regulator_symbol:
+ field: regulator_symbol
+
+ BrentLab/rossi_2021:
+ # binding
+ carbon_source:
+ path: experimental_conditions.media.carbon_source.compound
+ temperature_celsius:
+ path: experimental_conditions.temperature_celsius
+ dataset:
+ rossi_2021_af_combined:
+ sample_id:
+ field: sample_id
+ regulator_locus_tag:
+ field: regulator_locus_tag
+ target_locus_tag:
+ field: target_locus_tag
+
+ BrentLab/mahendrawada_2025:
+ temperature_celsius:
+ path: experimental_conditions.temperature_celsius
+ dataset:
+ # binding
+ chec_mahendrawada_m2025_af_combined_meta:
+ sample_id:
+ field: sample_id
+ regulator_locus_tag:
+ field: regulator_locus_tag
+ regulator_symbol:
+ field: regulator_symbol
+
+
+ BrentLab/hughes_2006:
+ dataset:
+ # perturbation
+ overexpression:
+ sample_id:
+ field: sample_id
+ carbon_source:
+ path: experimental_conditions.media.carbon_source.compound
+ temperature_celsius:
+ path: experimental_conditions.temperature_celsius
+ regulator_locus_tag:
+ field: regulator_locus_tag
+ regulator_symbol:
+ field: regulator_symbol
+ # perturbation
+ knockout:
+ sample_id:
+ field: sample_id
+ carbon_source:
+ path: experimental_conditions.media.carbon_source.compound
+ temperature_celsius:
+ path: experimental_conditions.temperature_celsius
+ regulator_locus_tag:
+ field: regulator_locus_tag
+ regulator_symbol:
+ field: regulator_symbol
+
+ BrentLab/kemmeren_2014:
+ dataset:
+ # perturbation
+ kemmeren_2014:
+ db_name: kemmeren
+ sample_id:
+ field: sample_id
+ carbon_source:
+ path: experimental_conditions.media.carbon_source.compound
+ temperature_celsius:
+ path: experimental_conditions.temperature_celsius
+ regulator_locus_tag:
+ field: regulator_locus_tag
+ regulator_symbol:
+ field: regulator_symbol
+
+ BrentLab/hackett_2020:
+ dataset:
+ # perturbation
+ hackett_2020:
+ db_name: hackett
+ sample_id:
+ field: sample_id
+ carbon_source:
+ path: experimental_conditions.media.carbon_source.compound
+ temperature_celsius:
+ path: experimental_conditions.temperature_celsius
+ dtype: numeric
+ regulator_locus_tag:
+ field: regulator_locus_tag
+ regulator_symbol:
+ field: regulator_symbol
+
+ BrentLab/yeast_comparative_analysis:
+ dataset:
+ dto:
+ dto_pvalue:
+ field: dto_empirical_pvalue
+ dto_fdr:
+ field: dto_fdr
+ links:
+ binding_id:
+ - [BrentLab/harbison_2004, harbison_2004]
+ - [BrentLab/rossi_2021, rossi_2021_af_combined]
+ - [BrentLab/mahendrawada_2025, chec_mahendrawada_m2025_af_combined_meta]
+ perturbation_id:
+ - [BrentLab/kemmeren_2014, kemmeren_2014]
+ - [BrentLab/hackett_2020, hackett_2020]
+ - [BrentLab/hughes_2006, overexpression]
+ - [BrentLab/hughes_2006, knockout]
+
+factor_aliases:
+ carbon_source:
+ glucose: [D-glucose, dextrose, glu]
+ galactose: [D-galactose, gal]
+ raffinose: [D-raffinose]
+
+missing_value_labels:
+ carbon_source: unspecified
+
+description:
+ carbon_source: The carbon source provided during growth
+ temperature_celsius: Growth temperature in degrees Celsius