{
  "filename": "plot_4.png",
  "iteration": 3,
  "description": "Create final comprehensive 4-panel evidence summary figure for NPLOC4 pseudo-DUB analysis",
  "timestamp": "2026-06-22 02:21:42",
  "code": "\nimport matplotlib.pyplot as plt\nimport matplotlib.patches as mpatches\nimport numpy as np\n\nfig = plt.figure(figsize=(18, 14))\n\n# Create a 3-panel figure\ngs = fig.add_gridspec(3, 2, hspace=0.35, wspace=0.3, height_ratios=[1.2, 1, 1.2])\n\n# ============================================================\n# Panel A: MPN domain architecture comparison\n# ============================================================\nax1 = fig.add_subplot(gs[0, :])\n\nproteins_viz = [\n    ('PSMD14/RPN11', 310, [(31, 166, 'MPN+', '#27ae60')], True, 'Active JAMM DUB', 'Zn in MPN: YES'),\n    ('BRCC3/BRCC36', 316, [(12, 179, 'MPN+', '#27ae60')], True, 'Active JAMM DUB', 'Zn in MPN: YES'),\n    ('PSMD7/RPN8', 324, [(9, 144, 'MPN-', '#e74c3c')], False, 'Pseudo-DUB', 'No Zn in MPN'),\n    ('CSN6', 327, [(41, 174, 'MPN-', '#e74c3c')], False, 'Pseudo-DUB', 'No Zn in MPN'),\n    ('NPLOC4/NPL4', 608, [(105, 225, 'ZF', '#3498db'), (226, 363, 'MPN-', '#e74c3c'), (580, 608, 'ZF', '#3498db')], False, 'Pseudo-DUB', 'Zn in ZF only'),\n]\n\nfor i, (name, length, domains, is_active, label, zn_note) in enumerate(proteins_viz):\n    y = len(proteins_viz) - 1 - i\n    ax1.barh(y, length, height=0.5, color='#f0f0f0', edgecolor='#bdc3c7', linewidth=0.5)\n    \n    for start, end, dtype, color in domains:\n        ax1.barh(y, end - start, left=start, height=0.5, color=color, edgecolor='black', linewidth=1)\n        ax1.text((start + end) / 2, y, dtype, ha='center', va='center', fontsize=7, fontweight='bold', color='white')\n    \n    if is_active:\n        for start, end, dtype, color in domains:\n            if 'MPN' in dtype:\n                jamm_pos = start + (end - start) * 0.6\n                ax1.plot(jamm_pos, y + 0.3, 'v', color='gold', markersize=10, markeredgecolor='black', zorder=5)\n    \n    ax1.text(-10, y, name, ha='right', va='center', fontsize=9, fontweight='bold')\n    ax1.text(length + 5, y, f'{zn_note}', ha='left', va='center', fontsize=8, style='italic',\n             color='#27ae60' if 'YES' in zn_note else '#e74c3c')\n\nax1.set_xlim(-130, 700)\nax1.set_ylim(-0.5, len(proteins_viz) - 0.5)\nax1.set_xlabel('Residue position', fontsize=10)\nax1.set_yticks([])\nax1.set_title('A. MPN Domain Architecture: Active DUBs vs Pseudo-DUBs', fontsize=13, fontweight='bold')\n\nlegend_elements = [\n    mpatches.Patch(facecolor='#27ae60', edgecolor='black', label='MPN+ (JAMM active)'),\n    mpatches.Patch(facecolor='#e74c3c', edgecolor='black', label='MPN- (pseudo-DUB)'),\n    mpatches.Patch(facecolor='#3498db', edgecolor='black', label='Zinc finger'),\n    plt.Line2D([0], [0], marker='v', color='w', markerfacecolor='gold', markeredgecolor='black', markersize=8, label='JAMM motif'),\n]\nax1.legend(handles=legend_elements, loc='lower right', fontsize=8)\n\n# ============================================================\n# Panel B: JAMM motif residue alignment\n# ============================================================\nax2 = fig.add_subplot(gs[1, :])\nax2.axis('off')\n\ntable_data = [\n    ['Protein', 'Status', 'GW+1', 'GW+2\\n(H\u2081?)', 'GW+3\\n(S?)', 'GW+4\\n(H\u2082?)', 'GW+15\\n(D?)', 'JAMM\\nIntact?', 'Zn in MPN\\n(PDB)'],\n    ['PSMD14', 'MPN+', 'Y', 'H \u2713', 'S \u2713', 'H \u2713', 'D \u2713', 'YES \u2713', 'YES'],\n    ['BRCC3', 'MPN+', 'Y', 'H \u2713', 'S \u2713', 'H \u2713', 'D \u2713', 'YES \u2713', 'YES'],\n    ['PSMD7', 'MPN-', 'Y', 'H', 'T', 'G', 'N', 'NO \u2717', 'NO'],\n    ['CSN6', 'MPN-', 'Y', 'T', 'T', 'G', 'D', 'NO \u2717', 'NO'],\n    ['EIF3F', 'MPN-', 'Y', 'A', 'T', 'G', 'S', 'NO \u2717', 'N/A'],\n    ['NPLOC4', 'MPN-', 'I *', 'F \u2717', 'T \u2717', 'D \u2717', 'V \u2717', 'NO \u2717', 'NO (7WWP)'],\n    ['Npl4-yeast', 'MPN-', 'R', 'Y', 'T', 'G', 'Y', 'NO \u2717', 'NO (6JWH)'],\n]\n\ntable = ax2.table(cellText=table_data[1:], colLabels=table_data[0],\n                  cellLoc='center', loc='center',\n                  colWidths=[0.12, 0.08, 0.08, 0.09, 0.08, 0.09, 0.09, 0.10, 0.12])\n\ntable.auto_set_font_size(False)\ntable.set_fontsize(8)\ntable.scale(1, 1.6)\n\nfor j in range(9):\n    table[0, j].set_facecolor('#2c3e50')\n    table[0, j].set_text_props(color='white', fontweight='bold')\n\nfor i in range(1, 8):\n    for j in range(9):\n        cell = table[i, j]\n        text = cell.get_text().get_text()\n        if i <= 2:  # Active DUBs\n            if j >= 3 and j <= 6 and '\u2713' in text:\n                cell.set_facecolor('#d5f5e3')\n            elif j == 7 and 'YES' in text:\n                cell.set_facecolor('#27ae60')\n                cell.set_text_props(color='white', fontweight='bold')\n            elif j == 8 and 'YES' in text:\n                cell.set_facecolor('#d5f5e3')\n        elif i == 6:  # NPLOC4 row\n            cell.set_text_props(fontweight='bold')\n            if '\u2717' in text:\n                cell.set_facecolor('#fadbd8')\n            elif j == 7:\n                cell.set_facecolor('#e74c3c')\n                cell.set_text_props(color='white', fontweight='bold')\n        else:  # Other pseudo-DUBs\n            if j == 7 and 'NO' in text:\n                cell.set_facecolor('#fadbd8')\n\nax2.set_title('B. JAMM Catalytic Residue Comparison (GW-anchored alignment)', fontsize=13, fontweight='bold', pad=15)\n\n# ============================================================\n# Panel C: Evidence convergence summary\n# ============================================================\nax3 = fig.add_subplot(gs[2, 0])\nax3.axis('off')\n\nevidence_lines = [\n    ('Sequence Analysis', 'No H[ST]H, no HxH, GWI not GWY\\nF-T-D at JAMM positions', '#e74c3c', '\u2717 ABSENT'),\n    ('Crystal Structures\\n(3 species)', 'Zero zinc in MPN domain\\n(PDB: 7WWP, 6JWH, 6CDD)', '#e74c3c', '\u2717 NO Zn'),\n    ('Groove Function\\n(Sato 2019)', 'JAMM groove occupied by Ufd1\\n(PMID:31836717)', '#e74c3c', '\u2717 REPURPOSED'),\n    ('Database Consensus', 'No DUB/protease terms in\\nUniProt, MEROPS, QuickGO', '#e74c3c', '\u2717 NOT CLASSIFIED'),\n    ('Functional Literature', 'Complex uses separate DUBs\\n(Bodnar 2017, Twomey 2019)', '#e74c3c', '\u2717 NOT DUB'),\n]\n\nfor i, (source, finding, color, verdict) in enumerate(evidence_lines):\n    y = 0.88 - i * 0.18\n    \n    # Arrow pointing to verdict\n    rect = mpatches.FancyBboxPatch((0.0, y - 0.06), 0.35, 0.12,\n                                    boxstyle=\"round,pad=0.02\", facecolor='#f8f9fa',\n                                    edgecolor='#bdc3c7', transform=ax3.transAxes)\n    ax3.add_patch(rect)\n    ax3.text(0.175, y + 0.02, source, ha='center', va='center', fontsize=8,\n             fontweight='bold', transform=ax3.transAxes)\n    ax3.text(0.175, y - 0.03, finding, ha='center', va='center', fontsize=6.5,\n             color='#555', transform=ax3.transAxes)\n    \n    # Verdict box\n    rect2 = mpatches.FancyBboxPatch((0.55, y - 0.04), 0.4, 0.08,\n                                     boxstyle=\"round,pad=0.02\", facecolor=color,\n                                     edgecolor='darkred', alpha=0.9, transform=ax3.transAxes)\n    ax3.add_patch(rect2)\n    ax3.text(0.75, y, verdict, ha='center', va='center', fontsize=9,\n             fontweight='bold', color='white', transform=ax3.transAxes)\n    \n    # Connecting arrow\n    ax3.annotate('', xy=(0.55, y), xytext=(0.38, y),\n                 arrowprops=dict(arrowstyle='->', color='#555', lw=1.5),\n                 transform=ax3.transAxes)\n\nax3.set_title('C. Evidence Convergence', fontsize=12, fontweight='bold')\n\n# ============================================================\n# Panel D: GO decision summary\n# ============================================================\nax4 = fig.add_subplot(gs[2, 1])\nax4.axis('off')\n\n# GO decision box\ndecision_box = mpatches.FancyBboxPatch((0.05, 0.55), 0.9, 0.35,\n                                        boxstyle=\"round,pad=0.03\",\n                                        facecolor='#fadbd8', edgecolor='#c0392b',\n                                        linewidth=2, transform=ax4.transAxes)\nax4.add_patch(decision_box)\n\nax4.text(0.5, 0.82, 'GO:0004843', ha='center', va='center', fontsize=14,\n         fontweight='bold', color='#c0392b', transform=ax4.transAxes)\nax4.text(0.5, 0.74, 'cysteine-type deubiquitinase activity', ha='center', va='center',\n         fontsize=10, style='italic', color='#c0392b', transform=ax4.transAxes)\nax4.text(0.5, 0.63, 'DO NOT ANNOTATE', ha='center', va='center', fontsize=16,\n         fontweight='bold', color='#c0392b', transform=ax4.transAxes)\n\n# Reasons box\nreasons = [\n    '1. NPLOC4 is MPN- (pseudo-DUB) \u2014 no catalytic activity',\n    '2. Wrong mechanism: JAMM=metalloprotease \u2260 cysteine-type',\n    '3. No DUB domain of ANY class in NPLOC4',\n    '4. Not currently annotated (correctly absent)',\n    '5. Core function: ubiquitin-binding cofactor of p97',\n]\n\nfor i, reason in enumerate(reasons):\n    y = 0.45 - i * 0.09\n    ax4.text(0.08, y, reason, ha='left', va='center', fontsize=8,\n             transform=ax4.transAxes, color='#2c3e50')\n\n# Verdict stamp\nstamp = mpatches.FancyBboxPatch((0.15, 0.01), 0.7, 0.08,\n                                 boxstyle=\"round,pad=0.02\",\n                                 facecolor='#27ae60', edgecolor='#1a7a3a',\n                                 linewidth=2, transform=ax4.transAxes)\nax4.add_patch(stamp)\nax4.text(0.5, 0.05, 'VERDICT: SUPPORTED \u2014 NPLOC4 is a pseudo-DUB',\n         ha='center', va='center', fontsize=10, fontweight='bold',\n         color='white', transform=ax4.transAxes)\n\nax4.set_title('D. GO Curation Decision', fontsize=12, fontweight='bold')\n\nplt.suptitle('NPLOC4 MPN Domain Analysis: Pseudo-DUB Classification and GO:0004843 Assessment',\n             fontsize=15, fontweight='bold', y=0.98)\n\nplt.savefig('nploc4_comprehensive_summary.png', dpi=150, bbox_inches='tight')\nplt.show()\nprint(\"Comprehensive summary figure saved\")\n",
  "plot_number": 4
}