<jupyter_start><jupyter_text>Obtain Uniprot IDs for all human kinasesThe definition of _kinase_ is not as straightforward as one could think. Throughout the literature you can find several manuscripts that list an authoritative list of kinases to query in an assay or include in domain-specific database. Surprisingly, the criteria used to nominate how a kinase makes it to the list or not is not consistent or obvious, and this results into slightly divergent definitions of what the human kinome really represents. In this notebook we aim to discuss these discrepancies and figure out a way to consistently agree on a definition for our future kinase-centric studies.> To that avail, we will query online databases, web services and documents using `urllib`, `requests`, `beautifulsoup4` and `pandas`.<jupyter_code># Some imports and helper globals
import urllib.request
from pathlib import Path

import requests
import bs4
import pandas as pd
from matplotlib import pyplot as plt

REPO = (Path(_dh[-1]) / "..").resolve()
DATA = REPO / 'data'

SOURCES = {}<jupyter_output><empty_output><jupyter_text>Enumerate all possible sources for human kinasesThere are several nomenclatures commonly used to refer to kinases: xName, Manning, HGNC... While there are some overlaps, there's no uniquely identifying naming system, so instead we will use Uniprot's identifiers as our primary keys. These can be mapped to other identifiers whenever available.There are several sources that can be used to identify the human kinome in Uniprot:* __A)__ [KinHub](http://kinhub.org/kinases.html) (based on Eid, 2017)* __B)__ [KLIFS](https://klifs.vu-compmedchem.nl/) (based on Kooistra, 2015 and Linden 2013)* __C)__ [Pkinfam](https://www.uniprot.org/docs/pkinfam.txt) - Uniprot's _Human and mouse protein kinases: classification and index_.* __D1)__ Dunbrack's structurally validated kinase alignment  (based on Dunbrack, 2019)* __D2)__ Dunbrack's `kincore` webserver (based on Dunbrack, 2019)* __E)__  Kinbase (based on Manning, 2002)* __F)__ Handcrafted UniProt queryOther possible resources we have not checked yet:* Kanev, 2019 "The Landscape of Atypical and Eukaryotic Protein Kinases"* Barton, 2007 "Classification and functional annotation of eukaryotic protein kinases" -- maybe uninformative* Hunter, 2000 "Signaling-2000 and Beyond" -- maybe uninformativeThese online references might help shed light on this issue:* https://www.biostars.org/p/131138/* https://github.com/macarthur-lab/gene_lists  A) KinHub[Kinhub.org](http://kinhub.org/kinases.html) maintains a HTML table in its webpage that can be retrieved with `requests` and `beautifulsoup`.> __Citation__:> <NAME>., <NAME>., <NAME>., <NAME>., and <NAME>. (2017)> KinMap: a web-based tool for interactive navigation through human kinome data. BMC Bioinformatics, 18:16. [DOI: 10.1186/s12859-016-1433-7 ](https://bmcbioinformatics.biomedcentral.com/articles/10.1186/s12859-016-1433-7)<jupyter_code>r = requests.get("http://kinhub.org/kinases.html")
r.raise_for_status()
html = bs4.BeautifulSoup(r.text)
table = html.find('table')
columns = [cell.text.strip() for cell in table.find('thead').find_all('th')]
records = [[cell.text.strip() for cell in row.find_all('td')] for row in table.find('tbody').find_all('tr')]
kinhub = SOURCES['kinhub'] = pd.DataFrame.from_records(records, columns=columns).sort_values(by="xName")
kinhub<jupyter_output><empty_output><jupyter_text>B) KLIFS[KLIFS](https://klifs.vu-compmedchem.nl/) maintains their own internal list of kinase names as part of their database. This can be retrieved via their JSON API as follows. It requires two steps: 1) getting the list of names, 2) getting the metadata associated to each name. All of this is then dumped into a dataframe.> __Citations__> > <NAME>, <NAME>, <NAME>, <NAME>, and <NAME>* (2013). KLIFS: A Knowledge-Based Structural Database To Navigate Kinase–Ligand Interaction Space. J. Med. Chem. 2014, 57, 2, 249–277. [DOI: 10.1021/jm400378w](https://doi.org/10.1021/jm400378w)> > <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, <NAME> (2015). KLIFS: a structural kinase-ligand interaction database. Nucleic Acids Research, Volume 44, Issue D1, 4 January 2016, Pages D365–D371. [DOI: 10.1093/nar/gkv1082](https://doi.org/10.1093/nar/gkv1082)>> <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, <NAME>, <NAME> (2019). The Landscape of Atypical and Eukaryotic Protein Kinases. Trends in Pharmacological Sciences, Volume 40, Issue 11, November 2019, Pages 818-832. [DOI: 10.1016/j.tips.2019.09.002](https://doi.org/10.1016/j.tips.2019.09.002)<jupyter_code>r = requests.get("https://klifs.net/api/kinase_names?species=HUMAN")
r.raise_for_status()
data = r.json()
all_ids = [record["kinase_ID"] for record in data]
r = requests.get(f"https://klifs.net/api/kinase_information?kinase_ID={','.join(map(str, all_ids))}")
r.raise_for_status()
data = r.json()
items = []
for record in data:
    items.append({
        "KLIFS Name": record["name"],
        "HGNC Name": record["HGNC"],
        "Family": record["family"],
        "Group": record["group"],
        "Class": record["kinase_class"],
        "Kinase Name": record["full_name"],
        "UniprotID": record["uniprot"],
        "IUPHAR": record["iuphar"],
        "Pocket": record["pocket"],
        "KLIFS ID": record["kinase_ID"]
    })
klifs = SOURCES['KLIFS'] = pd.DataFrame.from_dict(items).sort_values(by="KLIFS Name")
klifs
klifs.Group.unique()<jupyter_output><empty_output><jupyter_text>C) PkinfamUniProt maintains [a txt file](https://www.uniprot.org/docs/pkinfam.txt) with a kinase index: `pkinfam`. We can try to parse it and see what information we have there.> References:> > >> <NAME>.> Signaling -- 2000 and beyond.> Cell 100:113-127(2000).>> <NAME>., <NAME>., <NAME>., <NAME>., <NAME>.> The protein kinase complement of the human genome.> Science 298:1912-1934(2002).>> <NAME>., <NAME>.> "Classification and functional annotation of eukaryotic protein> kinases.> Proteins 68:893-914(2007).<jupyter_code>r = requests.get("https://www.uniprot.org/docs/pkinfam.txt")
r.raise_for_status()
text = r.text
items = []
current_category = None
lines = iter(text.splitlines())
for line in lines:
    if line.startswith("==="):  # this is a header
        line = next(lines)
        current_category = line.strip()
        next(lines)
        next(lines)
        continue
    if not line.strip() or not current_category or '_HUMAN' not in line:
        continue
    if line.startswith("---") and current_category:
        break
    
    fields = line.split()
    name = fields[0]
    uniprot_id = fields[2].replace("(", "").replace(")", "")
    items.append({
        'Name': name,
        'Family': current_category,
        'UniprotID': uniprot_id,
    })
pkinfam = SOURCES['pkinfam'] = pd.DataFrame.from_dict(items).sort_values(by="Name")
pkinfam
pkinfam.Family.unique()<jupyter_output><empty_output><jupyter_text>D1) Dunbrack's structurally validated kinase alignmentDataset extracted from:> <NAME>., <NAME>. A Structurally-Validated Multiple Sequence Alignment of 497 Human Protein Kinase Domains. Sci Rep 9, 19790 (2019). https://doi.org/10.1038/s41598-019-56499-4<jupyter_code>url = "https://static-content.springer.com/esm/art%3A10.1038%2Fs41598-019-56499-4/MediaObjects/41598_2019_56499_MOESM4_ESM.txt"
dunbrack_msa = SOURCES["dunbrack_msa"] = pd.read_csv(url, sep=r"\s+").rename(columns={'5_Uni_acc': "UniprotID"})
dunbrack_msa<jupyter_output><empty_output><jupyter_text>D2) Dunbrack's `kincore` webserverThe [Kinase Conformation Resource](http://dunbrack3.fccc.edu/kincore/) (`kincore`) is the accompanying website for 2019's kinase-focused works by <NAME> Dunbrack:> Defining a new nomenclature for the structures of active and inactive kinases. <NAME> and <NAME>, PNAS 2019, 116(14) 6818-6827.> Structurally-Validated Multiple Sequence Alignment of 497 Human Protein Kinase Domains. <NAME> and <NAME>, Sci Rep 2019, 9, 19790.All kinases thereby listed are programmably accessible via a TSV file in this url:```http://dunbrack3.fccc.edu/kincore/static/downloads/text-files/Human_Allgroups_Allspatials_Alldihedrals_All.tab```<jupyter_code>url = "http://dunbrack3.fccc.edu/kincore/static/downloads/text-files/Human_Allgroups_Allspatials_Alldihedrals_All.tab"
dunbrack_kincore = SOURCES["dunbrack_kincore"] = pd.read_csv(url, sep="\t")
dunbrack_kincore<jupyter_output><empty_output><jupyter_text>Unfortunately, this database only contains kinases for which structural data is available, so the number of unique UniprotIDs is considerably smaller, so we won't include it in our analysis.<jupyter_code>dunbrack_kincore["UniprotID"].unique().shape[0]<jupyter_output><empty_output><jupyter_text>E) KinBaseOld website for kinase.com provides a `kinbase` dataset in form of Fasta sequences. However, it doesn't provide identifiers such as UniprotIDs, so we won't be able to use it directly. We can map the Gene names though...The kinase.com project history can be found [here](http://kinase.com/web/current/about/). The main publication they refer to is:> <NAME>, <NAME>, <NAME>, <NAME>, <NAME> (2002).> The Protein Kinase Complement of the Human Genome.> Science 298:1912-1934. [DOI: 10.1126/science.1075762](http://doi.org/10.1126/science.1075762)<jupyter_code>r = requests.get("http://kinase.com/kinbase/FastaFiles/Human_kinase_protein.fasta")
r.raise_for_status()
header = ["Gene", "Comment", "Sequence"]
records = []
for line in r.text.splitlines():
    line = line.strip()
    if not line:
        continue
    if line.startswith(">"):
        name, comment = line.split(None, 1)
        records.append({"Gene": name[1:], "Comment": comment, "sequence": ""})
    else:
        records[-1]["sequence"] += line
kinbase = pd.DataFrame.from_dict(records)
kinbase
kinbase.Comment.unique()<jupyter_output><empty_output><jupyter_text>Fortunately, in their new website, they do provide more information in an Excel spreadsheet. This doesn't include Uniprot IDs, but other identifies that can potentially be mapped to (in `Entrez_dbXrefs`).<jupyter_code>kinbasex = pd.read_excel("http://kinase.com/static/colt/data/human/kinome/tables/Kincat_Hsap.08.02.xls")
kinbasex<jupyter_output><empty_output><jupyter_text>All Entrez-validated protein coding kinase genes:<jupyter_code>kinbasex[kinbasex["Entrez_gene_type"] == "protein-coding"]["Name"].unique().shape[0]<jupyter_output><empty_output><jupyter_text>F) Handcrafted UniProt querySearching UniProt for all [human proteins with confirmed _protein_ kinase activity](https://www.uniprot.org/uniprot/?query=family%3A%22protein+kinase+superfamily%22+AND+reviewed%3Ayes+AND+organism%3A%22Homo+sapiens+%28Human%29+%5B9606%5D%22&sort=score) shows 493 entries (queried on 2021.02.16). Programmatically, we can use the URL API for now.> Info: [More details on how to write URL queries](https://www.uniprot.org/help/uniprotkb_column_names)> We might want to refine the query to provide more precise GO annotations / activity profiles. <NAME> (KLIFS) generously provided some hints over email correspondence:* "For the atypical kinases we tried to capture all that were present in the “new kinbase” at kinase.com. Next we extended the list with closely related new proteins in the same family from UniProt and/or the Guide to pharmacology."* "For the eukaryotic protein kinases the main criterium was the presence of a catalytic kinase domain. To create this list we started with the listing from Manning and extended via UniProt based on the PFAM PF00069 motif (PF00069). In addition we also tried to capture some annotations from the new kinbase."* "All in all, it wasn’t an exact science, but several rounds of manual annotation".* "... you have to update all the UniProt codes to the most recent version (using the UniProt API or their website). [...] there are always a few that are updated/merged/deprecated etc."<jupyter_code>from urllib.parse import quote
url = ("https://www.uniprot.org/uniprot/?query="
       + quote(r'family:"protein kinase superfamily" AND reviewed:yes AND organism:"Homo sapiens (Human) [9606]"') +
       "&format=tab&force=true&columns=id,entry%20name,reviewed,protein%20names,genes&sort=name")
uniprot = pd.read_csv(url, sep="\t").rename(columns={"Entry": "UniprotID"})
reviewed_uniprot = SOURCES["our_uniprot"] = uniprot[uniprot.Status=="reviewed"].drop("Status", axis=1)
reviewed_uniprot
reviewed_uniprot[reviewed_uniprot["Protein names"].str.contains("atypical", case=False)]<jupyter_output><empty_output><jupyter_text>Inspect the results included in each sourceAll relevant datasets have been included in the `SOURCES` dictionary for easy comparison. Let's see how many unique UniprotIDs each dataset suggests:  Unique entries per dataset<jupyter_code>y = []
labels = []
for key, source in SOURCES.items():
    entries = source["UniprotID"].unique().shape[0]
    y.append(entries)
    labels.append(key)
    diff = source["UniprotID"].shape[0] - source["UniprotID"].unique().shape[0]
    if diff:
        print(f"{key} contained {diff} duplicate entries")<jupyter_output>kinhub contained 14 duplicate entries
KLIFS contained 13 duplicate entries
dunbrack_msa contained 13 duplicate entries
dunbrack_kincore contained 7623 duplicate entries<jupyter_text>Interestingly, some datasets include the same Uniprot ID several times (?)> TODO: Gather details on why!<jupyter_code>plt.bar(labels, y)
plt.xticks(rotation=45)
plt.title("Number of unique Uniprot IDs in each source");<jupyter_output><empty_output><jupyter_text>Most datasets sit around the ~500 mark, with the exception of Dunbrack's Kincore, which has less since it only considers Uniprot IDs for which structural information is available.As a result, we won't use Kincore for now since it's probably a subset of something else.Let's continue by analyzing the overlaps.  Dataset overlap<jupyter_code>datasets = {
    "kinhub": kinhub,
    "klifs": klifs,
    "pkinfam": pkinfam,
    "reviewed_uniprot": reviewed_uniprot,
    "dunbrack_msa": dunbrack_msa
}
uniprot_ids = {key: set(df.UniprotID.tolist()) for key, df in datasets.items()}<jupyter_output><empty_output><jupyter_text>With the dictionary above (`name --> set of Uniprot IDs`), we can now analyze the overlap between sets:<jupyter_code>import venn
from venn import venn as plot_venn
v = plot_venn(uniprot_ids)
v;
def compute_petals(dict_of_datasets):
    """
    Function adapted from `venn._venn.generate_petal_labels`:
        https://github.com/LankyCyril/pyvenn/blob/master/venn/_venn.py#L56
    """
    from venn._venn import generate_logics
    labels = list(dict_of_datasets.keys())
    datasets = list(dict_of_datasets.values())
    n_sets = len(datasets)
    dataset_union = set.union(*datasets)
    universe_size = len(dataset_union)
    petal_labels = {}
    for logic in generate_logics(n_sets):
        included_sets = [datasets[i] for i in range(n_sets) if logic[i] == "1"]
        excluded_sets = [datasets[i] for i in range(n_sets) if logic[i] == "0" ]
        involved_labels = tuple([label for label, i in zip(labels, list(logic)) if i == "1"])
        petal_labels[involved_labels] = (dataset_union & set.intersection(*included_sets)) - set.union(set(), *excluded_sets)
    return petal_labels
petals = compute_petals(uniprot_ids)
for tag, values in sorted(petals.items(), key=lambda kv: len(kv[0]), reverse=True):
    if not values:
        continue
    print(f"{len(values):4d} unique Uniprot IDs in ({len(tag)}-way overlap) {', '.join(tag)}")<jupyter_output>473 unique Uniprot IDs in (5-way overlap) kinhub, klifs, pkinfam, reviewed_uniprot, dunbrack_msa
   4 unique Uniprot IDs in (4-way overlap) klifs, pkinfam, reviewed_uniprot, dunbrack_msa
   5 unique Uniprot IDs in (4-way overlap) kinhub, klifs, pkinfam, dunbrack_msa
  14 unique Uniprot IDs in (4-way overlap) kinhub, klifs, pkinfam, reviewed_uniprot
   2 unique Uniprot IDs in (3-way overlap) pkinfam, reviewed_uniprot, dunbrack_msa
  10 unique Uniprot IDs in (3-way overlap) kinhub, klifs, pkinfam
   5 unique Uniprot IDs in (2-way overlap) klifs, pkinfam
   1 unique Uniprot IDs in (2-way overlap) kinhub, pkinfam
  12 unique Uniprot IDs in (2-way overlap) kinhub, klifs
  19 unique Uniprot IDs in (1-way overlap) klifs
   7 unique Uniprot IDs in (1-way overlap) kinhub<jupyter_text>We can observe several interesting points here:* There's a set of 473 kinases on which all datasets agree.  Overlap for eukaryotic kinases onlyIt might be that the disagreements are reduced if we only consider eukaryotic kinases.<jupyter_code>e_datasets = {
    "kinhub": kinhub[kinhub.Group != "Atypical"],
    "klifs": klifs[klifs.Group != "Atypical"],
    "pkinfam": pkinfam[~pkinfam.Family.str.contains("atypical", case=False)],
    "reviewed_uniprot": reviewed_uniprot[~reviewed_uniprot["Protein names"].str.contains("atypical", case=False)],
    "dunbrack_msa": dunbrack_msa[~dunbrack_msa["14_Group_in_Manning"].str.contains("atypical", case=False)]
}
e_uniprot_ids = {key: set(df.UniprotID.tolist()) for key, df in e_datasets.items()}
plot_venn(e_uniprot_ids);
epetals = compute_petals(e_uniprot_ids)
for tag, values in sorted(epetals.items(), key=lambda kv: len(kv[0]), reverse=True):
    if not values:
        continue
    print(f"{len(values):4d} unique Uniprot IDs in ({len(tag)}-way overlap) {', '.join(tag)}")<jupyter_output>470 unique Uniprot IDs in (5-way overlap) kinhub, klifs, pkinfam, reviewed_uniprot, dunbrack_msa
   4 unique Uniprot IDs in (4-way overlap) klifs, pkinfam, reviewed_uniprot, dunbrack_msa
   8 unique Uniprot IDs in (4-way overlap) kinhub, klifs, pkinfam, dunbrack_msa
   2 unique Uniprot IDs in (3-way overlap) pkinfam, reviewed_uniprot, dunbrack_msa
  12 unique Uniprot IDs in (1-way overlap) reviewed_uniprot
   2 unique Uniprot IDs in (1-way overlap) klifs<jupyter_text>Overlap for atypical kinases only<jupyter_code>a_datasets = {
    "kinhub": kinhub[kinhub.Group == "Atypical"],
    "klifs": klifs[klifs.Group == "Atypical"],
    "pkinfam": pkinfam[pkinfam.Family.str.contains("atypical", case=False)],
    "reviewed_uniprot": reviewed_uniprot[reviewed_uniprot["Protein names"].str.contains("atypical", case=False)],
    "dunbrack_msa": dunbrack_msa[dunbrack_msa["14_Group_in_Manning"].str.contains("atypical", case=False)]
}
a_uniprot_ids = {key: set(df.UniprotID.tolist()) for key, df in a_datasets.items()}
plot_venn(a_uniprot_ids);
apetals = compute_petals(a_uniprot_ids)
for tag, values in sorted(apetals.items(), key=lambda kv: len(kv[0]), reverse=True):
    if not values:
        continue
    print(f"{len(values):4d} unique Uniprot IDs in ({len(tag)}-way overlap) {', '.join(tag)}")<jupyter_output>2 unique Uniprot IDs in (4-way overlap) kinhub, klifs, pkinfam, reviewed_uniprot
  22 unique Uniprot IDs in (3-way overlap) kinhub, klifs, pkinfam
   5 unique Uniprot IDs in (2-way overlap) klifs, pkinfam
   1 unique Uniprot IDs in (2-way overlap) kinhub, pkinfam
  12 unique Uniprot IDs in (2-way overlap) kinhub, klifs
   3 unique Uniprot IDs in (1-way overlap) reviewed_uniprot
  17 unique Uniprot IDs in (1-way overlap) klifs
   7 unique Uniprot IDs in (1-way overlap) kinhub<jupyter_text>Dissect the contents of each petalLet's try to obtain information on the solitary leaves that include exclusive entries in each dataset. We can query the `petals` dictionary for information on the specific IDs. For example, which are those 3 unique IDs in KLIFS?> Note: You need to query using _tuples_ of the dataset keys, even for single-set petals<jupyter_code>print(*petals[("klifs",)])<jupyter_output>Q9H6X2 P35557 Q8TBX8 O60331 Q8TCG2 O00750 Q8N8J0 A4QPH2 O14986 O43921 Q99755 O75747 P78356 Q9BTU6 Q9UBF8 P42356 Q9UJY1 Q8NEB9 P48426<jupyter_text>Thanks to the Uniprot API we can check the GO annotations if we parse the lines starting with `DR   GO` that also contain `F:` (for function-related annotations):<jupyter_code>def query_uniprot_for_go(*uniprot_ids):
    for i, entry in enumerate(uniprot_ids, 1):
        r = requests.get(fr"https://www.uniprot.org/uniprot/{entry}.txt")
        r.raise_for_status()
        print(i, entry)
        for line in r.text.splitlines():
            if line.startswith(("ID", "DE")):
                print(line)
            elif line.startswith("DR   GO;") and "; F:" in line:
                print(line)
        print()
query_uniprot_for_go(*petals[("klifs",)])<jupyter_output>1 Q9H6X2
ID   ANTR1_HUMAN             Reviewed;         564 AA.
DE   RecName: Full=Anthrax toxin receptor 1 {ECO:0000305};
DE   AltName: Full=Tumor endothelial marker 8 {ECO:0000303|PubMed:10947988};
DE   Flags: Precursor;
DR   GO; GO:0051015; F:actin filament binding; IDA:UniProtKB.
DR   GO; GO:0005518; F:collagen binding; IDA:UniProtKB.
DR   GO; GO:0046872; F:metal ion binding; IEA:UniProtKB-KW.
DR   GO; GO:0004888; F:transmembrane signaling receptor activity; IDA:UniProtKB.

2 P35557
ID   HXK4_HUMAN              Reviewed;         465 AA.
DE   RecName: Full=Hexokinase-4 {ECO:0000305};
DE            Short=HK4 {ECO:0000305};
DE            EC=2.7.1.1 {ECO:0000269|PubMed:11916951, ECO:0000269|PubMed:15277402, ECO:0000269|PubMed:17082186, ECO:0000269|PubMed:18322640, ECO:0000269|PubMed:19146401, ECO:0000269|PubMed:25015100, ECO:0000269|PubMed:8325892};
DE   AltName: Full=Glucokinase {ECO:0000303|PubMed:1354840};
DE   AltName: Full=Hexokinase type IV {ECO:0000250|UniProtKB:P17712};
DE     [...]<jupyter_text>Dissect eukariotic petals<jupyter_code>print(*epetals[("klifs",)])
query_uniprot_for_go(*epetals[("klifs",)])<jupyter_output>1 O43921
ID   EFNA2_HUMAN             Reviewed;         213 AA.
DE   RecName: Full=Ephrin-A2;
DE   AltName: Full=EPH-related receptor tyrosine kinase ligand 6;
DE            Short=LERK-6;
DE   AltName: Full=HEK7 ligand;
DE            Short=HEK7-L;
DE   Flags: Precursor;
DR   GO; GO:0046875; F:ephrin receptor binding; IBA:GO_Central.

2 P35557
ID   HXK4_HUMAN              Reviewed;         465 AA.
DE   RecName: Full=Hexokinase-4 {ECO:0000305};
DE            Short=HK4 {ECO:0000305};
DE            EC=2.7.1.1 {ECO:0000269|PubMed:11916951, ECO:0000269|PubMed:15277402, ECO:0000269|PubMed:17082186, ECO:0000269|PubMed:18322640, ECO:0000269|PubMed:19146401, ECO:0000269|PubMed:25015100, ECO:0000269|PubMed:8325892};
DE   AltName: Full=Glucokinase {ECO:0000303|PubMed:1354840};
DE   AltName: Full=Hexokinase type IV {ECO:0000250|UniProtKB:P17712};
DE            Short=HK IV {ECO:0000250|UniProtKB:P17712};
DE   AltName: Full=Hexokinase-D {ECO:0000250|UniProtKB:P17712};
DR   GO; GO:0005524; F:ATP bindi[...]<jupyter_text>Dissect atypical petals<jupyter_code>print(*apetals[("klifs",)])
query_uniprot_for_go(*apetals[("klifs",)])<jupyter_output>1 Q9H6X2
ID   ANTR1_HUMAN             Reviewed;         564 AA.
DE   RecName: Full=Anthrax toxin receptor 1 {ECO:0000305};
DE   AltName: Full=Tumor endothelial marker 8 {ECO:0000303|PubMed:10947988};
DE   Flags: Precursor;
DR   GO; GO:0051015; F:actin filament binding; IDA:UniProtKB.
DR   GO; GO:0005518; F:collagen binding; IDA:UniProtKB.
DR   GO; GO:0046872; F:metal ion binding; IEA:UniProtKB-KW.
DR   GO; GO:0004888; F:transmembrane signaling receptor activity; IDA:UniProtKB.

2 Q8N8J0
ID   PI4P1_HUMAN             Reviewed;         262 AA.
DE   RecName: Full=Putative inactive phosphatidylinositol 4-kinase alpha-like protein P1;
DR   GO; GO:0004430; F:1-phosphatidylinositol 4-kinase activity; IBA:GO_Central.
DR   GO; GO:0052742; F:phosphatidylinositol kinase activity; IBA:GO_Central.

3 O75747
ID   P3C2G_HUMAN             Reviewed;        1445 AA.
DE   RecName: Full=Phosphatidylinositol 3-kinase C2 domain-containing subunit gamma {ECO:0000305};
DE            Short=PI3K-C2-gamma;
DE    [...]<jupyter_text>Interactive Venn diagrams<jupyter_code>from ipywidgets import SelectMultiple, HBox, HTML, interact, fixed, Output
def interactive_venn(datasets, showkey=None):
    petals = {tuple(sorted(k)): v for (k, v) in compute_petals(datasets).items()}
    key = tuple(sorted(showkey))
    
    value = "Clickable UniprotIDs will appear here when you click on one more datasets"
    if showkey:
        uniprotids = list(petals[key])
        lines = [
            f"<b>{','.join(key)} ({len(uniprotids)})</b>:<br/>", "<ul>"
        ]
        lines += [f"<li><a href='https://www.uniprot.org/uniprot/{i}' target='_blank'>{i}</a></li>" for i in uniprotids]
        lines.append("</ul>")
        value = "".join(lines)
    text = HTML(
        value=value,
        placeholder="Clickable UniprotIDs will appear here when you click on one more datasets",
        disabled=True,
        layout={"height": "95%"}
    )
    
    out = Output()
    with out:
        plot = plot_venn(datasets)
        plt.show()

    display(HBox([out, text], layout={"height": "100%"}))
selection = SelectMultiple(
    options=list(uniprot_ids.keys()),
    value=[],
    description="Datasets",
)
interact(interactive_venn, datasets=fixed(uniprot_ids), showkey=selection);<jupyter_output><empty_output><jupyter_text>Discussion Looks like KLIFS is selecting some non-protein kinases like:* phosphatidylinositol kinases* saccharide kinases* other proteins that bind ATP> TODO: Why?  Generate outputsSince there'no agreement to what a kinase *is*, we will output everything already considered by the five listings we have analyzed. Let's build the final dataframe with all kinases:<jupyter_code>kinases = pd.concat(
    [
        kinhub[["HGNC Name", "UniprotID"]].rename(columns={"HGNC Name": "Name"}).assign(kinhub=1), 
        klifs[["HGNC Name", "UniprotID"]].rename(columns={"HGNC Name": "Name"}).assign(klifs=1), 
        pkinfam[["Name", "UniprotID"]].assign(pkinfam=1), 
        reviewed_uniprot[["Entry name", "UniprotID"]].rename(columns={"Entry name": "Name"}).assign(reviewed_uniprot=1),
        dunbrack_msa[["4_Uni_entry", "UniprotID"]].rename(columns={"4_Uni_entry": "Name"}).assign(dunbrack_msa=1)
    ]
)
kinases<jupyter_output><empty_output><jupyter_text>Since there are different names assigned to each Uniprot ID depending on the source, we will just concatenate them in the same column<jupyter_code>keys = ["kinhub", "klifs", "pkinfam", "reviewed_uniprot", "dunbrack_msa"]
kinases["Name"] = kinases.transform({'Name': lambda v: v.replace("_HUMAN", "")})
boolsum = lambda v: v.sum() > 0
joinset = lambda v: '|'.join([x for x in set(v) if x])
grouped = kinases.groupby(["UniprotID"], as_index=False).agg(dict(**{'Name': joinset}, **{k: boolsum for k in keys}))
grouped
# example Uniprot ID with different names
grouped[grouped.UniprotID == "Q96LW2"]<jupyter_output><empty_output><jupyter_text>We'll export the multi-kinase dataframe to a CSV in the repo:<jupyter_code>grouped.to_csv(DATA / "human_kinases.aggregated.csv")<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12241754939523702, 'fraction_numerical': 0.045563819397490796, 'mean_word_length': 4.9426339285714285, 'pattern_counts': {'":': 35, '<': 146, '<?xml version=': 0, '>': 187, 'https://': 21, 'lorem ipsum': 0, 'www.': 9, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '25', 'dir': 'jupyter-structured-clean-dedup', 'id': '262105', 'license': 'MIT', 'n_tokens_mistral': 10206, 'n_tokens_neox': 8982, 'n_words': 2483, 'path': 'human-kinases/human_kinases.ipynb', 'repo_name': 'openkinome/datascripts', 'size': '26909'}