Upload db.py with huggingface_hub
Browse files
db.py
CHANGED
|
@@ -874,6 +874,102 @@ def get_dsa_mfi_comparison(chart_no, dsa_class=None):
|
|
| 874 |
return dates, out, pct_by_date, labels_by_rid
|
| 875 |
|
| 876 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 877 |
def delete_dsa_report(report_id):
|
| 878 |
backup_db()
|
| 879 |
conn = get_conn()
|
|
|
|
| 874 |
return dates, out, pct_by_date, labels_by_rid
|
| 875 |
|
| 876 |
|
| 877 |
+
def get_patients_with_both():
|
| 878 |
+
"""Patients having BOTH active PRA and DSA reports."""
|
| 879 |
+
conn = get_conn()
|
| 880 |
+
rows = conn.execute('''
|
| 881 |
+
SELECT p.id, p.patient_name, p.chart_no,
|
| 882 |
+
(SELECT COUNT(*) FROM reports WHERE patient_id=p.id AND COALESCE(is_deleted,0)=0) AS pra_count,
|
| 883 |
+
(SELECT COUNT(*) FROM dsa_reports WHERE patient_id=p.id AND COALESCE(is_deleted,0)=0) AS dsa_count,
|
| 884 |
+
(SELECT MAX(report_date) FROM reports WHERE patient_id=p.id AND COALESCE(is_deleted,0)=0) AS pra_latest,
|
| 885 |
+
(SELECT MAX(report_date) FROM dsa_reports WHERE patient_id=p.id AND COALESCE(is_deleted,0)=0) AS dsa_latest
|
| 886 |
+
FROM patients p
|
| 887 |
+
ORDER BY p.patient_name
|
| 888 |
+
''').fetchall()
|
| 889 |
+
conn.close()
|
| 890 |
+
out = []
|
| 891 |
+
for r in rows:
|
| 892 |
+
d = dict(r)
|
| 893 |
+
if d['pra_count'] > 0 and d['dsa_count'] > 0:
|
| 894 |
+
d['latest_date'] = max(d['pra_latest'] or '', d['dsa_latest'] or '')
|
| 895 |
+
out.append(d)
|
| 896 |
+
out.sort(key=lambda x: x['latest_date'], reverse=True)
|
| 897 |
+
return out
|
| 898 |
+
|
| 899 |
+
|
| 900 |
+
def get_combined_reports(chart_no):
|
| 901 |
+
"""Active PRA + DSA reports for a patient, interleaved by date."""
|
| 902 |
+
conn = get_conn()
|
| 903 |
+
pra_rows = conn.execute('''
|
| 904 |
+
SELECT r.id, r.report_date, r.pra_class AS class_label, r.pra_percent AS pct,
|
| 905 |
+
r.overall, r.specificity, r.comment, r.submitted_by,
|
| 906 |
+
'PRA' AS source
|
| 907 |
+
FROM reports r JOIN patients p ON p.id=r.patient_id
|
| 908 |
+
WHERE p.chart_no=? AND COALESCE(r.is_deleted,0)=0
|
| 909 |
+
''', (chart_no,)).fetchall()
|
| 910 |
+
dsa_rows = conn.execute('''
|
| 911 |
+
SELECT r.id, r.report_date, r.dsa_class AS class_label, r.pct_sa AS pct,
|
| 912 |
+
r.overall, r.specificity, r.comment, r.submitted_by,
|
| 913 |
+
'DSA' AS source
|
| 914 |
+
FROM dsa_reports r JOIN patients p ON p.id=r.patient_id
|
| 915 |
+
WHERE p.chart_no=? AND COALESCE(r.is_deleted,0)=0
|
| 916 |
+
''', (chart_no,)).fetchall()
|
| 917 |
+
pra_list = [{**dict(r), 'antibodies': []} for r in pra_rows]
|
| 918 |
+
dsa_list = [{**dict(r), 'antibodies': []} for r in dsa_rows]
|
| 919 |
+
# Pull antibodies for each
|
| 920 |
+
for r in pra_list:
|
| 921 |
+
ab = conn.execute('SELECT * FROM antibody_strength WHERE report_id=? ORDER BY id',
|
| 922 |
+
(r['id'],)).fetchall()
|
| 923 |
+
r['antibodies'] = [dict(a) for a in ab]
|
| 924 |
+
for r in dsa_list:
|
| 925 |
+
ab = conn.execute('SELECT * FROM dsa_antibody_strength WHERE report_id=? ORDER BY id',
|
| 926 |
+
(r['id'],)).fetchall()
|
| 927 |
+
r['antibodies'] = [dict(a) for a in ab]
|
| 928 |
+
conn.close()
|
| 929 |
+
all_rows = pra_list + dsa_list
|
| 930 |
+
all_rows.sort(key=lambda r: (r['report_date'], r['source'], r['class_label']), reverse=True)
|
| 931 |
+
return all_rows
|
| 932 |
+
|
| 933 |
+
|
| 934 |
+
def get_combined_mfi(chart_no, class_label='I'):
|
| 935 |
+
"""Combined (PRA + DSA) MFI trend for one Class.
|
| 936 |
+
Returns:
|
| 937 |
+
dates: sorted unique date labels from both sources
|
| 938 |
+
antigens: [{allele, antigen (sero), pra_mfi: {date: max_mfi}, dsa_mfi: {date: max_mfi}}, ...]
|
| 939 |
+
"""
|
| 940 |
+
pra_full = f'PRA Class {class_label}'
|
| 941 |
+
dsa_full = f'DSA Class {class_label}'
|
| 942 |
+
|
| 943 |
+
pra_dates, pra_ag, _, _ = get_mfi_comparison(chart_no, pra_full)
|
| 944 |
+
dsa_dates, dsa_ag, _, _ = get_dsa_mfi_comparison(chart_no, dsa_full)
|
| 945 |
+
|
| 946 |
+
combined = {}
|
| 947 |
+
for ag in pra_ag:
|
| 948 |
+
key = ag['allele']
|
| 949 |
+
rec = combined.setdefault(key, {'allele': key, 'antigen': ag['antigen'],
|
| 950 |
+
'pra_mfi': {}, 'dsa_mfi': {}})
|
| 951 |
+
rec['antigen'] = rec.get('antigen') or ag['antigen']
|
| 952 |
+
for d, v in ag['mfi_by_date'].items():
|
| 953 |
+
rec['pra_mfi'][d] = v.get('max_mfi')
|
| 954 |
+
for ag in dsa_ag:
|
| 955 |
+
key = ag['allele']
|
| 956 |
+
rec = combined.setdefault(key, {'allele': key, 'antigen': ag['antigen'],
|
| 957 |
+
'pra_mfi': {}, 'dsa_mfi': {}})
|
| 958 |
+
rec['antigen'] = rec.get('antigen') or ag['antigen']
|
| 959 |
+
for d, v in ag['mfi_by_date'].items():
|
| 960 |
+
rec['dsa_mfi'][d] = v.get('max_mfi')
|
| 961 |
+
|
| 962 |
+
import re as _re
|
| 963 |
+
def date_key(lbl):
|
| 964 |
+
parts = lbl.split(' ')[0].split('/')
|
| 965 |
+
try:
|
| 966 |
+
return (int(parts[0]), int(parts[1]), int(parts[2]), lbl)
|
| 967 |
+
except (IndexError, ValueError):
|
| 968 |
+
return (9999, 0, 0, lbl)
|
| 969 |
+
all_dates = sorted(set(pra_dates) | set(dsa_dates), key=date_key)
|
| 970 |
+
return all_dates, list(combined.values())
|
| 971 |
+
|
| 972 |
+
|
| 973 |
def delete_dsa_report(report_id):
|
| 974 |
backup_db()
|
| 975 |
conn = get_conn()
|