Package: pathling
Python API for PathlingThis is the Python API forPathling. It provides a
set of tools that aid the use of FHIR terminology services and FHIR data within
Python applications and data science workflows.View the API documentation →InstallationPrerequisites:Python 3.8+ with pipTo install, run this command:pipinstallpathlingEncodersThe Python library features a set of encoders for converting FHIR data into
Spark dataframes.Reading in NDJSONNDJSONis a format commonly used for bulk FHIR data, and
consists of files (one per resource type) that contains one JSON resource per
line.frompathlingimportPathlingContextpc=PathlingContext.create()# Read each line from the NDJSON into a row within a Spark data set.ndjson_dir='/some/path/ndjson/'json_resources=pc.spark.read.text(ndjson_dir)# Convert the data set of strings into a structured FHIR data set.patients=pc.encode(json_resources,'Patient')# Do some stuff.patients.select('id','gender','birthDate').show()Reading in BundlesThe FHIRBundleresource can contain a
collection of FHIR resources. It is often used to represent a set of related
resources, perhaps generated as part of the same event.frompathlingimportPathlingContextpc=PathlingContext.create()# Read each Bundle into a row within a Spark data set.bundles_dir='/some/path/bundles/'bundles=pc.spark.read.text(bundles_dir,wholetext=True)# Convert the data set of strings into a structured FHIR data set.patients=pc.encode_bundle(bundles,'Patient')# JSON is the default format, XML Bundles can be encoded using input type.# patients = pc.encodeBundle(bundles, 'Patient', inputType=MimeType.FHIR_XML)# Do some stuff.patients.select('id','gender','birthDate').show()Terminology functionsThe library also provides a set of functions for querying a FHIR terminology
server from within your queries and transformations.Value set membershipThemember_offunction can be used to test the membership of a code within aFHIR value set. This can be used with both
explicit value sets (i.e. those that have been pre-defined and loaded into the
terminology server) and implicit value sets (e.g. SNOMED CTExpression Constraint Language).In this example, we take a list of SNOMED CT diagnosis codes and
create a new column which shows which are viral infections. We use an ECL
expression to define viral infection as a disease with a pathological process
of "Infectious process", and a causative agent of "Virus".result=pc.member_of(csv,to_coding(csv.CODE,'http://snomed.info/sct'),to_ecl_value_set("""<< 64572001|Disease| : (<< 370135005|Pathological process| = << 441862004|Infectious process|,<< 246075003|Causative agent| = << 49872002|Virus|)"""),'VIRAL_INFECTION')result.select('CODE','DESCRIPTION','VIRAL_INFECTION').show()Results in:CODEDESCRIPTIONVIRAL_INFECTION65363002Otitis mediafalse16114001Fracture of anklefalse444814009Viral sinusitistrue444814009Viral sinusitistrue43878008Streptococcal sore throatfalseConcept translationThetranslatefunction can be used to translate codes from one code system to
another using maps that are known to the terminology server. In this example, we
translate our SNOMED CT diagnosis codes into Read CTV3.result=pc.translate(csv,to_coding(csv.CODE,'http://snomed.info/sct'),'http://snomed.info/sct/900000000000207008?fhir_cm=''900000000000497000',output_column_name='READ_CODE')result=result.withColumn('READ_CODE',result.READ_CODE.code)result.select('CODE','DESCRIPTION','READ_CODE').show()Results in:CODEDESCRIPTIONREAD_CODE65363002Otitis mediaX00ik16114001Fracture of ankleS34..444814009Viral sinusitisXUjp0444814009Viral sinusitisXUjp043878008Streptococcal sore throatA340.Subsumption testingSubsumption test is a fancy way of saying "is this code equal or a subtype of
this other code".For example, a code representing "ankle fracture" is subsumed
by another code representing "fracture". The "fracture" code is more general,
and using it with subsumption can help us find other codes representing
different subtypes of fracture.Thesubsumesfunction allows us to perform subsumption testing on codes within
our data. The order of the left and right operands can be reversed to query
whether a code is "subsumed by" another code.# 232208008 |Ear, nose and throat disorder|left_coding=Coding('http://snomed.info/sct','232208008')right_coding_column=to_coding(csv.CODE,'http://snomed.info/sct')result=pc.subsumes(csv,'IS_ENT',left_coding=left_coding,right_coding_column=right_coding_column)result.select('CODE','DESCRIPTION','IS_ENT').show()Results in:CODEDESCRIPTIONIS_ENT65363002Otitis mediatrue16114001Fracture of anklefalse444814009Viral sinusitistrueRetrieving propertiesSome terminologies contain additional properties that are associated with codes.
You can query these properties using theproperty_offunction.There is also adisplayfunction that can be used to retrieve the preferred
display term for each code.# Get the parent codes for each code in the dataset.parents=csv.withColumn("PARENTS",property_of(to_snomed_coding(csv.CODE),"parent",PropertyType.CODE),)# Split each parent code into a separate row.exploded_parents=parents.selectExpr("CODE","DESCRIPTION","explode_outer(PARENTS) AS PARENT")# Retrieve the preferred term for each parent code.with_displays=exploded_parents.withColumn("PARENT_DISPLAY",display(to_snomed_coding(exploded_parents.PARENT)))Results in:CODEDESCRIPTIONPARENTPARENT_DISPLAY65363002Otitis media43275000Otitis65363002Otitis media68996008Disorder of middle ear16114001Fracture of ankle125603006Injury of ankle16114001Fracture of ankle46866001Fracture of lower limb444814009Viral sinusitis36971009Sinusitis444814009Viral sinusitis281794004Viral upper respiratory tract infection444814009Viral sinusitis363166002Infective disorder of head444814009Viral sinusitis36971009Sinusitis444814009Viral sinusitis281794004Viral upper respiratory tract infection444814009Viral sinusitis363166002Infective disorder of headRetrieving designationsSome terminologies contain additional display terms for codes. These can be used
for language translations, synonyms, and more. You can query these terms using thedesignationfunction.# Get the synonyms for each code in the dataset.synonyms=csv.withColumn("SYNONYMS",designation(to_snomed_coding(csv.CODE),Coding.of_snomed("900000000000013009")),)# Split each synonyms into a separate row.exploded_synonyms=synonyms.selectExpr("CODE","DESCRIPTION","explode_outer(SYNONYMS) AS SYNONYM")Results in:CODEDESCRIPTIONSYNONYM65363002Otitis mediaOM - Otitis media16114001Fracture of ankleAnkle fracture16114001Fracture of ankleFracture of distal end of tibia and fibula444814009Viral sinusitis (disorder)NULL444814009Viral sinusitis (disorder)NULL43878008Streptococcal sore throat (disorder)Septic sore throat43878008Streptococcal sore throat (disorder)Strep throat43878008Streptococcal sore throat (disorder)Strept throat43878008Streptococcal sore throat (disorder)Streptococcal angina43878008Streptococcal sore throat (disorder)Streptococcal pharyngitisTerminology server authenticationPathling can be configured to connect to a protected terminology server by
supplying a set of OAuth2 client credentials and a token endpoint.Here is an example of how to authenticate to
theNHS terminology server:frompathlingimportPathlingContextpc=PathlingContext.create(terminology_server_url='https://ontology.nhs.uk/production1/fhir',token_endpoint='https://ontology.nhs.uk/authorisation/auth/realms/nhs-digital-terminology/protocol/openid-connect/token',client_id='[client ID]',client_secret='[client secret]')Installation in DatabricksTo make the Pathling library available within notebooks, navigate to the
"Compute" section and click on the cluster. Click on the "Libraries" tab, and
click "Install new".Install both thepathlingPyPI package, and
theau.csiro.pathling:library-apiMaven package. Once the cluster is restarted, the libraries should be available
for import and use within all notebooks.By default, Databricks uses Java 8 within its clusters, while Pathling requires
Java 11. To enable Java 11 support within your cluster, navigate toAdvanced
Options > Spark > Environment Variablesand add the following:JNAME=zulu11-ca-amd64See the Databricks documentation onLibrariesfor more
information.Spark cluster configurationIf you are running your own Spark cluster, or using a Docker image (such asjupyter/pyspark-notebook)
,
you will need to configure Pathling as a Spark package.You can do this by adding the following to yourspark-defaults.conffile:spark.jars.packages au.csiro.pathling:library-api:[some version]See theConfigurationpage of the Spark documentation for more information aboutspark.jars.packagesand other related configuration options.To create a Pathling notebook Docker image, yourDockerfilemight look like
this:FROMjupyter/pyspark-notebookUSERrootRUNecho"spark.jars.packages au.csiro.pathling:library-api:[some version]">>/usr/local/spark/conf/spark-defaults.confUSER${NB_UID}RUNpipinstall--quiet--no-cache-dirpathling&&\fix-permissions"${CONDA_DIR}"&&\fix-permissions"/home/${NB_USER}"Pathling is copyright © 2018-2023, Commonwealth Scientific and Industrial
Research Organisation
(CSIRO) ABN 41 687 119 230. Licensed under
theApache License, version 2.0.