From 31cfca97f4463986b6af97963e6b8a515d25f48e Mon Sep 17 00:00:00 2001 From: Kien Date: Thu, 16 May 2024 11:16:25 +0200 Subject: [PATCH 01/12] added implementation of ontology normalization --- tracex_project/db.sqlite3 | Bin 356352 -> 356352 bytes .../logic/modules/module_cohort_tagger.py | 25 ++++++++++++++-- ...4_cohort_condition_snomed_code_and_more.py | 22 ++++++++++++++ tracex_project/extraction/models.py | 2 ++ tracex_project/tracex/logic/constants.py | 13 +++++++++ tracex_project/tracex/logic/utils.py | 27 ++++++++++++++++-- 6 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 tracex_project/extraction/migrations/0024_cohort_condition_snomed_code_and_more.py diff --git a/tracex_project/db.sqlite3 b/tracex_project/db.sqlite3 index a806f66d1221412311ff060fdfbed8022f717f56..d37bd597d0faf922e21d02bd95b97f513c35a428 100644 GIT binary patch delta 2818 zcmai0YmD4h6<*sr+0Axmb|ccHkF@NDq)OAy#?Kjh0|C$bWzW-N&mfrf_%$!vGqz{O zGYB?q)0T>g(r(L0h(3N$Bq|UI+iC=rDE#A3OL?dgDiV?SQ6WTB9zP;gRCv_}TA-?q zK40tJ&-WakbM8Io;?M?^b5kx{82(k@h+X%IVkuZiL`=37g!fm&lyZHzd1pl*hLm4TC1Kqp#?iLDM-9yd= zfzx}9bH@N-Z*=Yv;Ovj!pI+G0&808!NGf>OA#kHs zFSPDKa_xes5Rz?UT`eXv%^1dvdN!ILOP~3$ZJv1uxfQ0c5Kir%G=Br1U-!JSz2ZGC z_*T|_zi@Q*`a&S?zp^$DJQmmpbk;uQj|6__f5ZRI>h(1}@b20Zffv_Oe$D@=|BihG z{>3VL3St0Lbw|Axg0yvaf|xk2P6-v!oUUU|Ir8!X!nuNh;J7J8EAf zjFEcm#tF zqIJU~VT44E|MxPyjl$bFzJ=jo7>AF|fBjD&27+sE>>s)K@)~ex{@XP$u>k~T^mE`{ z`=5jF4tQ}C*Ei>nUI4!ifNQUMycZ96zsiH;I`GnbWd|Is0pFe7XM(3^ubALnAkv(_ zW`g1M7uwTaIzR~HirG!?osHRyVd$~c3Vj`g?(QgWhn4z*^ zQ^V?%2=^3(EKvDLr#1;IC_zg}!tJ?{Si04kL~Iu=CEAe|Zqvm$yQ^1XL@bxf3r<(! zTG3{99HUg6j&U&2EN&xqSRlvSQinyck%^3xj@D9obi7v{HjwbRPIavg6C_7PjxR|i z+>Mww9Q?nzfB*TTKIW2-Zg&P)sBhz4LvGpgcP>LVwEIZ;n2&japg-;eZz&nKT8%p+ zbV@UgwiBPCI!akhnX;pF%B)3-I2nuBd^;zGCiQrG!l8|tN>QnSriVB;lSo^n5L9Fx zw<`%&tu@pjk7U?gVuU#qnT*&1K2#EIj21I-jH4aK>{rA=Fg$?^2{oI>u&mzbG>4eN z#VJf3HGAP;uo(=i7^RiMW>$^YQ)Ge=`-TK3Td@FYlEO%lDy1C8bbB2nSjDk+ zw-cJmsVt9F*?P3Ti>Tp(kW5USY_urH+lth7Q9WO;H)_#%Thm!i>5)jbBxLi&`n1OJ zZoMFv4ZD#RDjA)3N{xPT(i~FoFf*tNR8dMO3Nap=WiE&yV}{Mk93pDNm=?0>xYJ{^ zi0t&yYRociIDs0>ZmT|3>&aMEOf@qV*%DK2Zd4J{Ay_YHM$s%JE0c0HI3~){s7LVi zAU2GbOL7=*2@$91NR4qY%npP30u^PbOmZj(bKQEf%8wi?ljp*&ma4*)aej;x+qffD zxK4$Nb|Y#8tss3NsbRYjty-KoY-A{x7Bjg5i5OCG5RKy{il&F{q}EK}PEo@P zkzuETlm&d+GU-S};Ck)dYEEp$%9b(ckH>?&HHHz&b_;A4YYU3S8#L2(wL+K8@QFMsj=4-b!En`3*QxVLPpXz;l~H1lWG8rNP$)X-Uam%I zL?KZtTY0Mysai0emz?gjMVFFkmk_H#l{LgPTgfMrJu#*-G+Rif!{uh*(ex}ajpl?% zGNz|81C2u&j*sPdMMG-tF4+usMw#KDGodS{qa;#jZ%X6tRFI-^8P|yMAThA`b|His z@sS-$xPu3e)Drpw4hvSTJD zSiTq>1>qte&-EOc8RDaqHEtH#?f!76)Fn)!#uXW}CT@Wv^suYj#Lyno3X|a{Xw`JJ zDd%V?lIk*J!^&_it!0xi-AFkSHYri5&XjV4`3_7A2Uj1@z}w|gs3Ro0Riqe z$y}Px7M)^k(jjuaaHXH@r!yRCaorDIeIKst^Ea;&_|%V~i*sSsYXj$7 z>f+gNod`Vq(el)e@61cz_FeP8Uts?f@SWT|&3R4Qc@I?&2R&`VL(apQ_i@S_H|GfK K`{ieWg?|CHfN*&L delta 836 zcmYk5TSyd97{}+FGvn&&%&g+wP1agNv)!GUbzSd;x9mcirddAddfU`?XH#2L5HGA{ zP^m38SUw1qkPv9AoeE0pJu3qt43r=t0jYFN)|*icMx z14U8i2xkfYg!{vX&7fhr`T>s;=}fOmQ|c3iFUXe}IvE{l3=2jESl`~(VykUyl$}-e z?s{h%iuG<8C9vWZO$MO%R++-V39s999V9*xUS)S%C4n4$iB%{vOQ{zMDsoSn%N>Qe zEmEnySzle|QJC#oy*;_(Ims-XPw?SzpfMH$Tye+ODX^fgQWX z!A8Jvaez`i3259r2}T)Ge27(3zz(o$8W{gqAH4vT78JrRDyj_-Pi~uF@#0^Q2Ytb= zc^)tEFi%IaEgZg)4Q~OGea_>LMKDDJCa}61x_L0C^vW<^S&(4_6l;_T86L!6WvJ6c z&>p06(4K(H0kMG!*T;0Kd)WnM6Ki{*0=+JcsAZzTIAM&yG=ULj9~dUwq=*doY#I;1 z9uLd_kg|Gh8ne33Evq6-CeR;)U-m&K0EyUf4PH$JRm$cZe6Os|!)#?^9%^yyYxpCO zJW;i~gqF8(P@>6pwX+N=33^&b8zJuJP&YtP{_BcLgUrO`j6YtFL!|At8NTO-e-+TdQ7FXEsPNTvd^q^M zH>lCwAV$tZzX;;45 Date: Thu, 16 May 2024 11:44:04 +0200 Subject: [PATCH 02/12] fix import order --- tracex_project/tracex/logic/utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tracex_project/tracex/logic/utils.py b/tracex_project/tracex/logic/utils.py index 9c9a7017..37232b8c 100644 --- a/tracex_project/tracex/logic/utils.py +++ b/tracex_project/tracex/logic/utils.py @@ -1,5 +1,8 @@ """Module providing various utility functions for the project.""" import os +import requests +import json + import base64 import tempfile import functools @@ -7,8 +10,6 @@ import pandas as pd import pm4py import numpy as np -import requests -import json from io import StringIO from pathlib import Path From 83e5bc99682ffd33ee48bb53dcbffb45003f589c Mon Sep 17 00:00:00 2001 From: Kien Date: Thu, 16 May 2024 11:50:27 +0200 Subject: [PATCH 03/12] return none if noramlization is not possible --- tracex_project/extraction/logic/orchestrator.py | 2 ++ tracex_project/tracex/logic/utils.py | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tracex_project/extraction/logic/orchestrator.py b/tracex_project/extraction/logic/orchestrator.py index 36d6363f..12898926 100644 --- a/tracex_project/extraction/logic/orchestrator.py +++ b/tracex_project/extraction/logic/orchestrator.py @@ -246,7 +246,9 @@ def set_default_values(self): "gender": None, "origin": None, "condition": None, + "condition_snomed_code": None, "preexisting_condition": None, + "preexisting_condition_snomed_code": None, } self.set_cohort(cohort_default_values) diff --git a/tracex_project/tracex/logic/utils.py b/tracex_project/tracex/logic/utils.py index 37232b8c..6a73f10a 100644 --- a/tracex_project/tracex/logic/utils.py +++ b/tracex_project/tracex/logic/utils.py @@ -117,8 +117,13 @@ def get_snomed_ct_info(term): SNOMED_CT_API_URL, params=SNOMED_CT_PARAMS, headers=SNOMED_CT_HEADERS ) data = json.loads(response.text) - term = data["items"][0]["term"] - code = data["items"][0]["concept"]["conceptId"] + + term = None + code = None + + if data["items"]: + term = data["items"][0]["term"] + code = data["items"][0]["concept"]["conceptId"] return term, code From 8f5a640917fa24f454fc75667e8efd4b0a494400 Mon Sep 17 00:00:00 2001 From: Kien Date: Thu, 16 May 2024 11:52:22 +0200 Subject: [PATCH 04/12] fix import ordering --- tracex_project/tracex/logic/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracex_project/tracex/logic/utils.py b/tracex_project/tracex/logic/utils.py index 6a73f10a..ed8b0aa3 100644 --- a/tracex_project/tracex/logic/utils.py +++ b/tracex_project/tracex/logic/utils.py @@ -1,6 +1,5 @@ """Module providing various utility functions for the project.""" import os -import requests import json import base64 @@ -13,6 +12,7 @@ from io import StringIO from pathlib import Path +import requests from django.conf import settings from django.db.models import Q From 91bfd131d834eae5e8e6c99ccdd8fcff6cefc7c6 Mon Sep 17 00:00:00 2001 From: Kien Date: Thu, 16 May 2024 11:53:59 +0200 Subject: [PATCH 05/12] satisfy pylint --- tracex_project/tracex/logic/utils.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tracex_project/tracex/logic/utils.py b/tracex_project/tracex/logic/utils.py index ed8b0aa3..05e3b60d 100644 --- a/tracex_project/tracex/logic/utils.py +++ b/tracex_project/tracex/logic/utils.py @@ -6,12 +6,13 @@ import tempfile import functools import warnings -import pandas as pd -import pm4py -import numpy as np from io import StringIO from pathlib import Path + +import pandas as pd +import pm4py +import numpy as np import requests from django.conf import settings From c05c26563dd615ca66283eb3136933288abe1e20 Mon Sep 17 00:00:00 2001 From: "tkv29@yahoo.de" Date: Fri, 17 May 2024 11:05:28 +0200 Subject: [PATCH 06/12] remove testing --- tracex_project/tracex/logic/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracex_project/tracex/logic/utils.py b/tracex_project/tracex/logic/utils.py index 05e3b60d..c1e661f6 100644 --- a/tracex_project/tracex/logic/utils.py +++ b/tracex_project/tracex/logic/utils.py @@ -113,7 +113,7 @@ def calculate_linear_probability(logprob): def get_snomed_ct_info(term): """Get the first matched name and code of a SNOMED CT term.""" - SNOMED_CT_PARAMS["term"] = "covid" + SNOMED_CT_PARAMS["term"] = term response = requests.get( SNOMED_CT_API_URL, params=SNOMED_CT_PARAMS, headers=SNOMED_CT_HEADERS ) From 495bcb94c4b165de24adf316d919d63dde1979d0 Mon Sep 17 00:00:00 2001 From: "tkv29@yahoo.de" Date: Fri, 17 May 2024 12:10:56 +0200 Subject: [PATCH 07/12] added updated migrated db and requested cr --- tracex_project/db.sqlite3 | Bin 356352 -> 356352 bytes tracex_project/tracex/logic/utils.py | 2 -- 2 files changed, 2 deletions(-) diff --git a/tracex_project/db.sqlite3 b/tracex_project/db.sqlite3 index d37bd597d0faf922e21d02bd95b97f513c35a428..8df8009882e43a78ae96ad747a02b792f78a09d0 100644 GIT binary patch delta 13201 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 diff --git a/tracex_project/tracex/logic/utils.py b/tracex_project/tracex/logic/utils.py index 32f66d50..c6d9e76a 100644 --- a/tracex_project/tracex/logic/utils.py +++ b/tracex_project/tracex/logic/utils.py @@ -25,8 +25,6 @@ TEMPERATURE_SUMMARIZING, MODEL, oaik, -) -from tracex.logic.constants import ( SNOMED_CT_API_URL, SNOMED_CT_PARAMS, SNOMED_CT_HEADERS, From 762d36c757406459a27ca0fa78cf002b101cc9e6 Mon Sep 17 00:00:00 2001 From: "tkv29@yahoo.de" Date: Fri, 17 May 2024 12:51:18 +0200 Subject: [PATCH 08/12] limit api response --- tracex_project/tracex/logic/constants.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tracex_project/tracex/logic/constants.py b/tracex_project/tracex/logic/constants.py index 009f4aec..adb4b034 100644 --- a/tracex_project/tracex/logic/constants.py +++ b/tracex_project/tracex/logic/constants.py @@ -48,11 +48,11 @@ "https://browser.ihtsdotools.org/snowstorm/snomed-ct/browser/MAIN/descriptions" ) SNOMED_CT_PARAMS = params = { - "limit": 50, + "limit": 1, "conceptActive": "true", "lang": "english", "skipTo": 0, - "returnLimit": 100, + "returnLimit": 1, } SNOMED_CT_HEADERS = { "User-Agent": "browser", From cb5c979dbf0ee3577692a5b6f61631118c057498 Mon Sep 17 00:00:00 2001 From: "tkv29@yahoo.de" Date: Fri, 17 May 2024 13:00:39 +0200 Subject: [PATCH 09/12] catch bad request errors --- tracex_project/tracex/logic/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tracex_project/tracex/logic/utils.py b/tracex_project/tracex/logic/utils.py index c6d9e76a..73f35299 100644 --- a/tracex_project/tracex/logic/utils.py +++ b/tracex_project/tracex/logic/utils.py @@ -116,11 +116,11 @@ def get_snomed_ct_info(term): SNOMED_CT_API_URL, params=SNOMED_CT_PARAMS, headers=SNOMED_CT_HEADERS ) data = json.loads(response.text) - + term = None code = None - if data["items"]: + if data.get("items"): term = data["items"][0]["term"] code = data["items"][0]["concept"]["conceptId"] From 30c41faf1de2ffcae0f50258347879855365f1d4 Mon Sep 17 00:00:00 2001 From: "tkv29@yahoo.de" Date: Fri, 17 May 2024 13:01:46 +0200 Subject: [PATCH 10/12] remove trailing whitespace --- tracex_project/tracex/logic/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracex_project/tracex/logic/utils.py b/tracex_project/tracex/logic/utils.py index 73f35299..947401d6 100644 --- a/tracex_project/tracex/logic/utils.py +++ b/tracex_project/tracex/logic/utils.py @@ -116,7 +116,7 @@ def get_snomed_ct_info(term): SNOMED_CT_API_URL, params=SNOMED_CT_PARAMS, headers=SNOMED_CT_HEADERS ) data = json.loads(response.text) - + term = None code = None From 5b6a39de89e820b26a185f020d6e308fef398a7e Mon Sep 17 00:00:00 2001 From: "tkv29@yahoo.de" Date: Sun, 26 May 2024 10:04:24 +0200 Subject: [PATCH 11/12] fix migrations --- .../logic/modules/module_cohort_tagger.py | 2 +- .../extraction/logic/orchestrator.py | 11 ---- ...e_cohort_gender_add_snomed_trace_cohort.py | 53 +++++++++++++++++++ .../0023_remove_cohort_gender_cohort_sex.py | 22 ++++++++ ...4_cohort_condition_snomed_code_and_more.py | 22 -------- 5 files changed, 76 insertions(+), 34 deletions(-) create mode 100644 tracex_project/extraction/migrations/0022_remove_cohort_gender_add_snomed_trace_cohort.py create mode 100644 tracex_project/extraction/migrations/0023_remove_cohort_gender_cohort_sex.py delete mode 100644 tracex_project/extraction/migrations/0024_cohort_condition_snomed_code_and_more.py diff --git a/tracex_project/extraction/logic/modules/module_cohort_tagger.py b/tracex_project/extraction/logic/modules/module_cohort_tagger.py index 99dac8d3..d461782a 100644 --- a/tracex_project/extraction/logic/modules/module_cohort_tagger.py +++ b/tracex_project/extraction/logic/modules/module_cohort_tagger.py @@ -68,7 +68,7 @@ def __remove_placeholder(cohort_data) -> Optional[Dict[str, str]]: return cohort_dict @staticmethod - def normalize_coniditons_snomed(cohort_dict): + def normalize_coniditons_snomed(cohort_dict) -> Optional[Dict[str, str]]: """Normalizes conditions to a SNOMED code.""" condition = cohort_dict.get("condition") preexisting_condition = cohort_dict.get("preexisting_condition") diff --git a/tracex_project/extraction/logic/orchestrator.py b/tracex_project/extraction/logic/orchestrator.py index 14036d8b..fd59ed6a 100644 --- a/tracex_project/extraction/logic/orchestrator.py +++ b/tracex_project/extraction/logic/orchestrator.py @@ -266,17 +266,6 @@ def set_default_values(self) -> None: data["activity_relevance"] = None data["timestamp_correctness"] = None data["correctness_confidence"] = None - if "cohort_tagging" not in config_modules: - cohort_default_values = { - "age": None, - "gender": None, - "origin": None, - "condition": None, - "condition_snomed_code": None, - "preexisting_condition": None, - "preexisting_condition_snomed_code": None, - } - self.set_cohort(cohort_default_values) def update_progress(self, view, execution_step: int, module_name: str) -> None: """Update the progress of the extraction.""" diff --git a/tracex_project/extraction/migrations/0022_remove_cohort_gender_add_snomed_trace_cohort.py b/tracex_project/extraction/migrations/0022_remove_cohort_gender_add_snomed_trace_cohort.py new file mode 100644 index 00000000..50ed8aab --- /dev/null +++ b/tracex_project/extraction/migrations/0022_remove_cohort_gender_add_snomed_trace_cohort.py @@ -0,0 +1,53 @@ +# Generated by Django 4.2.13 on 2024-05-26 09:35 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('extraction', '0021_alter_event_event_type_alter_event_location_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='trace', + name='cohort', + ), + migrations.AddField( + model_name='cohort', + name='condition_snomed_code', + field=models.IntegerField(blank=True, null=True), + ), + migrations.AddField( + model_name='cohort', + name='preexisting_condition_snomed_code', + field=models.IntegerField(blank=True, null=True), + ), + migrations.AddField( + model_name='cohort', + name='trace', + field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='cohort', to='extraction.trace'), + ), + migrations.AlterField( + model_name='cohort', + name='age', + field=models.IntegerField(blank=True, null=True), + ), + migrations.AlterField( + model_name='cohort', + name='condition', + field=models.CharField(blank=True, max_length=50, null=True), + ), + migrations.AlterField( + model_name='cohort', + name='origin', + field=models.CharField(blank=True, max_length=50, null=True), + ), + migrations.AlterField( + model_name='cohort', + name='preexisting_condition', + field=models.CharField(blank=True, max_length=100, null=True), + ), + ] diff --git a/tracex_project/extraction/migrations/0023_remove_cohort_gender_cohort_sex.py b/tracex_project/extraction/migrations/0023_remove_cohort_gender_cohort_sex.py new file mode 100644 index 00000000..77b10097 --- /dev/null +++ b/tracex_project/extraction/migrations/0023_remove_cohort_gender_cohort_sex.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.13 on 2024-05-26 09:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('extraction', '0022_remove_cohort_gender_add_snomed_trace_cohort'), + ] + + operations = [ + migrations.RemoveField( + model_name='cohort', + name='gender', + ), + migrations.AddField( + model_name='cohort', + name='sex', + field=models.CharField(blank=True, max_length=25, null=True), + ), + ] diff --git a/tracex_project/extraction/migrations/0024_cohort_condition_snomed_code_and_more.py b/tracex_project/extraction/migrations/0024_cohort_condition_snomed_code_and_more.py deleted file mode 100644 index 307c2473..00000000 --- a/tracex_project/extraction/migrations/0024_cohort_condition_snomed_code_and_more.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.2.11 on 2024-05-16 11:03 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("extraction", "0023_alter_cohort_age_alter_cohort_condition_and_more"), - ] - - operations = [ - migrations.AddField( - model_name="cohort", - name="condition_snomed_code", - field=models.IntegerField(blank=True, null=True), - ), - migrations.AddField( - model_name="cohort", - name="preexisting_condition_snomed_code", - field=models.IntegerField(blank=True, null=True), - ), - ] From c3a257e963482ac152bcac419ce8797976af1bcb Mon Sep 17 00:00:00 2001 From: "tkv29@yahoo.de" Date: Sun, 26 May 2024 20:46:04 +0200 Subject: [PATCH 12/12] add migrated db --- tracex_project/db.sqlite3 | Bin 356352 -> 364544 bytes ...ort.py => 0022_add_snomed_trace_cohort.py} | 0 .../0023_remove_cohort_gender_cohort_sex.py | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename tracex_project/extraction/migrations/{0022_remove_cohort_gender_add_snomed_trace_cohort.py => 0022_add_snomed_trace_cohort.py} (100%) diff --git a/tracex_project/db.sqlite3 b/tracex_project/db.sqlite3 index 8df8009882e43a78ae96ad747a02b792f78a09d0..a509afbe93274e3fa59bcf288e4d77ac137fb21d 100644 GIT binary patch delta 18752 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