{
  "filename": "zfp_tree.png",
  "iteration": 2,
  "description": "All-vs-all identity distance matrix + UPGMA tree to place C6T1A2 within the ZFP subfamily",
  "timestamp": "2026-07-08 20:58:25",
  "code": "\nimport requests, numpy as np\nfrom scipy.cluster.hierarchy import linkage, dendrogram\nfrom scipy.spatial.distance import squareform\nimport matplotlib\nmatplotlib.use(\"Agg\"); import matplotlib.pyplot as plt\n\nC6=\"MTFIREDDDDQVDDDHDHDHVDGGGSQNSASNITEIVTTPEGENLGEWLSLGLKGDINMPAEEQNSSSRPLHSNNNKVFSCNFCMRKFYSSQALGGHQNAHKREREAARSYHQSHHHRIGFSYTTSLATRSLGIKPHSLVHRPNRERSAMVARFSSSDAINVGVGSVASSWTPFMLEQAVDFYWPGSFRGDLLPKQESSDVKKIDLDLRL\"\n\naccs={\"ZFP1\":\"Q42485\",\"ZFP2\":\"Q39261\",\"ZFP3\":\"Q39262\",\"ZFP4\":\"Q39263\",\n      \"ZFP5\":\"Q39264\",\"ZFP6\":\"Q39265\",\"ZFP7\":\"Q39266\",\"ZAT10\":\"Q96289\",\"ZAT6\":\"O22533\"}\nseqs={\"C6T1A2\":C6}\nfor n,a in accs.items():\n    seqs[n]=requests.get(f\"https://rest.uniprot.org/uniprotkb/{a}.fasta\",timeout=60).text.split(\"\\n\",1)[1].replace(\"\\n\",\"\")\n\ndef nw(a,b,match=2,mismatch=-1,gap=-2):\n    n,m=len(a),len(b); H=np.zeros((n+1,m+1))\n    for i in range(n+1):H[i][0]=i*gap\n    for j in range(m+1):H[0][j]=j*gap\n    for i in range(1,n+1):\n        ai=a[i-1]\n        for j in range(1,m+1):\n            s=match if ai==b[j-1] else mismatch\n            H[i][j]=max(H[i-1][j-1]+s,H[i-1][j]+gap,H[i][j-1]+gap)\n    # identity via traceback\n    i,j=n,m;ident=al=0\n    while i>0 and j>0:\n        s=match if a[i-1]==b[j-1] else mismatch\n        if H[i][j]==H[i-1][j-1]+s:\n            al+=1; ident+= (a[i-1]==b[j-1]); i-=1;j-=1\n        elif H[i][j]==H[i-1][j]+gap: i-=1\n        else: j-=1\n    return ident/al*100\n\nnames=list(seqs)\nn=len(names); D=np.zeros((n,n))\nfor i in range(n):\n    for j in range(i+1,n):\n        pid=nw(seqs[names[i]],seqs[names[j]])\n        D[i,j]=D[j,i]=100-pid\nprint(\"Distance = 100 - %identity\")\nprint(\"      \"+\" \".join(f\"{x[:5]:>6}\" for x in names))\nfor i in range(n):\n    print(f\"{names[i]:>6} \"+\" \".join(f\"{D[i,j]:6.1f}\" for j in range(n)))\n\nZ=linkage(squareform(D),method=\"average\")\nplt.figure(figsize=(8,4))\ndendrogram(Z,labels=names,leaf_rotation=45)\nplt.title(\"UPGMA tree of C6T1A2 vs Arabidopsis ZFP subfamily (1 - %identity)\")\nplt.ylabel(\"distance (100 - %id)\"); plt.tight_layout()\nplt.savefig(\"zfp_tree.png\",dpi=120)\nprint(\"\\nsaved zfp_tree.png\")\n\n# nearest neighbors of C6T1A2\nci=names.index(\"C6T1A2\")\norder=sorted([(D[ci,j],names[j]) for j in range(n) if j!=ci])\nprint(\"\\nC6T1A2 nearest neighbours (dist, %id):\")\nfor d,nm in order: print(f\"  {nm:6} dist={d:5.1f}  id={100-d:5.1f}%\")\n"
}