Map dms scores onto pdb structure¶

In [1]:
# Imports
import os
import pandas as pd
import polyclonal

File paths for data:

In [2]:
# this cell is tagged as `parameters` for papermill parameterization
pdb_file = None

dms_scores = None
cell_entry_diffs = None
pdb_dir = None
In [3]:
# Parameters
dms_scores = "results/summaries/cell_entry_and_pH_stability.csv"
cell_entry_diffs = "results/compare_cell_entry/site_diffs.csv"
pdb_file = "data/9MT6.pdb"
pdb_dir = "results/mapped_scores_onto_pdb/"
In [4]:
# # Uncomment for running interactive
# pdb_file = "../data/9MT6.pdb"

# dms_scores = "../results/summaries/cell_entry_and_pH_stability.csv"
# cell_entry_diffs = "../results/compare_cell_entry/site_diffs.csv"
# pdb_dir = "../results/mapped_scores_onto_pdb/"

Map functional scores onto PDB structure

In [5]:
def scores_to_b_factors(
    scores,
    stat_col,
    input_pdb_file, 
    output_pdb_file_dir, 
    chain_mappings,
    functional_cutoff = None,
    df_processed = False,
    pdb_name = None,
    floor = False,
):
    """
    Function to map dms scores to a pdb structure
    using mut_escape_pdb_b_factor function from polyclonal.
    """
    

    scores = pd.read_csv(scores)
    print(f"Processing {stat_col} DMS scores:")

    # Filter for minimum func score
    if functional_cutoff != None:
        scores = scores.loc[scores["entry in C musculinus TfR1 cells"] >= functional_cutoff]

    # Floor data if selected
    if floor != False:
        scores[stat_col] = scores[stat_col].clip(lower=0)

    # Aggregate site averages
    if stat_col != "Jensen-Shannon divergence":
        scores = (
            scores.groupby(["site", "wildtype"])
            .aggregate({
                stat_col : "mean"
            })
            .reset_index()
        )

    # Scores greater than 0
    max_scores = scores.loc[scores[stat_col] > 0]["site"].tolist()
    print(f"Sites greater than 0: {max_scores}")
    
    scores_aA = scores.copy()
    scores_bB = scores.copy()
    scores_cC = scores.copy()
    
    def site_mapping(site, mappings):
        if site < 59:
            return mappings[0]
        elif site >= 59 and site <= 251:
            return mappings[1]
        else:
            return mappings[2]
    
    scores_aA["chain"] = (
        scores_aA.apply(lambda x: site_mapping(x["site"], chain_mappings[0]), axis=1)
    )
    
    scores_bB["chain"] = (
        scores_bB.apply(lambda x: site_mapping(x["site"], chain_mappings[1]), axis=1)
    )
    
    scores_cC["chain"] = (
        scores_cC.apply(lambda x: site_mapping(x["site"], chain_mappings[2]), axis=1)
    )
    
    scores = (
        pd.concat([
            scores_aA,
            scores_bB,
            scores_cC,
        ], ignore_index=True)
    )

    scores = scores.astype({"site" : "int"}) 

    print(f"50th percentile of averaged scores: {scores[stat_col].quantile(0.50)}")
    print(f"Score range: {scores[stat_col].min()} to {scores[stat_col].max()}")
    print()

    # Create name of output file
    name = None
    if stat_col == "entry in C musculinus TfR1 cells":
        name = "C_musculinus_func"
    elif stat_col == "entry in C callosus TfR1 cells":
        name = "C_callosus_func"
    elif stat_col == "pH stability" and floor == False:
        name = "pH"
    elif stat_col == "pH stability" and floor == True:
        name = "positive_pH"
    elif stat_col == "Jensen-Shannon divergence":
        name = "JS-div"
    else:
        print(f"{stat_col} not recognized!")

    
    if pdb_name != None:
            polyclonal.pdb_utils.reassign_b_factor(
            input_pdbfile=input_pdb_file,
            output_pdbfile=output_pdb_file_dir+name+"_"+pdb_name+"_mapped_pdb.pdb",
            df=scores,
            metric_col=stat_col,
            site_col="site",
            chain_col="chain",
        )
    else:
        polyclonal.pdb_utils.reassign_b_factor(
            input_pdbfile=input_pdb_file,
            output_pdbfile=output_pdb_file_dir+name+"_mapped_pdb.pdb",
            df=scores,
            metric_col=stat_col,
            site_col="site",
            chain_col="chain",
        )
In [6]:
effects = [
    "entry in C musculinus TfR1 cells",
    "entry in C callosus TfR1 cells",
    "pH stability",
]

chain_mappings = [
    ["A", "E", "F"],
    ["D", "H", "I"],
    ["G", "B", "C"],
]

# Make output dir if doesn't exist
if not os.path.exists(pdb_dir):
    os.mkdir(pdb_dir)

for effect in effects:
    if effect == "pH stability":
        scores_to_b_factors(
            dms_scores,
            effect,
            pdb_file, 
            pdb_dir,
            chain_mappings,
            functional_cutoff=-5,
            pdb_name="9MT6",
        )
    else:
        scores_to_b_factors(
            dms_scores,
            effect,
            pdb_file, 
            pdb_dir,
            chain_mappings,
            pdb_name="9MT6",
        )

# map cell diffs onto structure
scores_to_b_factors(
    cell_entry_diffs,
    "Jensen-Shannon divergence",
    pdb_file, 
    pdb_dir,
    chain_mappings,
    pdb_name="9MT6",
)
Processing entry in C musculinus TfR1 cells DMS scores:
Sites greater than 0: [137]
50th percentile of averaged scores: -2.62882
Score range: -5.45645 to 0.005708947368421063

Processing entry in C callosus TfR1 cells DMS scores:
Sites greater than 0: [184]
50th percentile of averaged scores: -2.9343969999999997
Score range: -5.43005 to 0.044010499999999994

Processing pH stability DMS scores:
Sites greater than 0: [24, 30, 33, 34, 37, 40, 45, 74, 105, 108, 110, 111, 114, 115, 119, 122, 130, 133, 139, 142, 145, 146, 147, 154, 157, 165, 169, 170, 175, 184, 191, 216, 217, 230, 235, 238, 240, 241, 253, 254, 261, 262, 263, 264, 266, 267, 268, 269, 278, 279, 280, 281, 282, 286, 287, 288, 291, 311, 318, 321, 322, 323, 324, 329, 331, 333, 334, 339, 381, 389, 431, 434, 442, 446, 454]
50th percentile of averaged scores: -0.014547868750000002
Score range: -1.0349814285714285 to 0.3345186666666667

Processing Jensen-Shannon divergence DMS scores:
Sites greater than 0: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 90, 91, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 160, 161, 162, 163, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 177, 178, 179, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 202, 203, 204, 205, 206, 208, 209, 210, 211, 212, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 227, 228, 230, 231, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 285, 286, 287, 288, 289, 290, 291, 292, 294, 295, 296, 297, 298, 299, 301, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 343, 344, 347, 348, 349, 350, 351, 352, 353, 354, 359, 360, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 376, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 460, 461, 462, 463, 464, 465, 466, 468, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485]
50th percentile of averaged scores: 0.006
Score range: 0.0 to 0.339

In [7]:
# Map just positive scores onto pdb
scores_to_b_factors(
    dms_scores,
    "pH stability",
    pdb_file, 
    pdb_dir,
    chain_mappings,
    functional_cutoff=-5,
    pdb_name="9MT6",
    floor = True,
)
Processing pH stability DMS scores:
Sites greater than 0: [2, 3, 4, 6, 8, 9, 11, 14, 15, 16, 17, 19, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 58, 59, 60, 61, 63, 67, 69, 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 82, 83, 84, 86, 87, 90, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 113, 114, 115, 116, 117, 119, 121, 122, 124, 125, 127, 128, 129, 130, 131, 132, 133, 134, 136, 137, 138, 139, 140, 141, 142, 143, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 162, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 177, 179, 181, 182, 183, 184, 185, 186, 187, 189, 190, 191, 192, 193, 195, 196, 198, 199, 200, 203, 204, 206, 208, 209, 210, 211, 212, 214, 215, 216, 217, 218, 219, 220, 221, 222, 224, 225, 227, 230, 233, 235, 238, 239, 240, 241, 242, 245, 246, 247, 249, 251, 252, 253, 254, 255, 257, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 272, 273, 274, 275, 277, 278, 279, 280, 281, 282, 283, 286, 287, 288, 289, 290, 291, 295, 297, 299, 306, 307, 308, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 339, 340, 341, 343, 347, 350, 351, 352, 353, 365, 366, 368, 369, 370, 376, 378, 379, 380, 381, 382, 383, 384, 386, 387, 388, 389, 390, 392, 393, 394, 396, 397, 400, 401, 403, 404, 406, 408, 409, 410, 412, 415, 418, 419, 422, 425, 426, 427, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 441, 442, 444, 445, 446, 448, 449, 450, 451, 452, 453, 454, 457, 458, 460, 461, 462, 463, 464, 466, 468, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484]
50th percentile of averaged scores: 0.00229125
Score range: 0.0 to 0.4533057894736842