-
Notifications
You must be signed in to change notification settings - Fork 1
/
README.html
813 lines (783 loc) · 47.8 KB
/
README.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
<meta charset="utf-8">
<meta name="generator" content="quarto-1.3.450">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>readme</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
ul.task-list li input[type="checkbox"] {
width: 0.8em;
margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */
vertical-align: middle;
}
/* CSS for syntax highlighting */
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
}
pre.numberSource { margin-left: 3em; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
</style>
<script src="README_files/libs/clipboard/clipboard.min.js"></script>
<script src="README_files/libs/quarto-html/quarto.js"></script>
<script src="README_files/libs/quarto-html/popper.min.js"></script>
<script src="README_files/libs/quarto-html/tippy.umd.min.js"></script>
<script src="README_files/libs/quarto-html/anchor.min.js"></script>
<link href="README_files/libs/quarto-html/tippy.css" rel="stylesheet">
<link href="README_files/libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles">
<script src="README_files/libs/bootstrap/bootstrap.min.js"></script>
<link href="README_files/libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
<link href="README_files/libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light">
</head>
<body class="fullcontent">
<div id="quarto-content" class="page-columns page-rows-contents page-layout-article">
<main class="content" id="quarto-document-content">
<!DOCTYPE html>
<h1>
Welcome to my training material test lab!
</h1>
<p>
</p>
<p>For an interactive view of the OMOP data dictionary, please visit <a href="https://dbjhu.github.io/OMOPDD.html">this link</a>.</p>
<section id="projects-best-suited-for-observational-research-and-ohdsi-network-studies" class="level1">
<h1>Projects Best Suited for Observational Research and OHDSI Network Studies</h1>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="AnalyticUseCases.png" class="img-fluid figure-img"></p>
<figcaption class="figure-caption">Source: https://www.ohdsi.org/wp-content/uploads/2023/01/SOS-challenge-intro-24jan2023.pdf</figcaption>
</figure>
</div>
<section id="this-is-the-exact-same-table-as-in-the-image-above-only-in-markdown" class="level2">
<h2 class="anchored" data-anchor-id="this-is-the-exact-same-table-as-in-the-image-above-only-in-markdown">(This is the exact same table as in the image above only in Markdown)</h2>
</section>
</section>
<section id="analytic-use-cases-and-examples" class="level1">
<h1>Analytic Use Cases and Examples</h1>
<table class="table">
<colgroup>
<col style="width: 25%">
<col style="width: 25%">
<col style="width: 25%">
<col style="width: 25%">
</colgroup>
<thead>
<tr class="header">
<th>Analytic use case</th>
<th>Type</th>
<th>Structure</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><strong>Clinical characterization</strong></td>
<td>Disease Natural History</td>
<td>Amongst patients who are diagnosed with <code><insert your favorite disease></code>, what are the patient’s characteristics from their medical history?</td>
<td>Amongst patients with rheumatoid arthritis, what are their demographics (age, gender), prior conditions, medications, and health service utilization behaviors?</td>
</tr>
<tr class="even">
<td></td>
<td>Treatment utilization</td>
<td>Amongst patients who have <code><insert your favorite disease></code>, which treatments were patients exposed to amongst <code><list of treatments for disease></code> and in which sequence?</td>
<td>Amongst patients with depression, which treatments were patients exposed to SSRI, SNRI, TCA, bupropion, esketamine and in which sequence?</td>
</tr>
<tr class="odd">
<td></td>
<td>Outcome incidence</td>
<td>Amongst patients who are new users of <code><insert your favorite drug></code>, how many patients experienced <code><insert your favorite known adverse event from the drug profile></code> within <code><time horizon following exposure start></code>?</td>
<td>Amongst patients who are new users of methylphenidate, how many patients experienced psychosis within 1 year of initiating treatment?</td>
</tr>
<tr class="even">
<td><strong>Population-level effect estimation</strong></td>
<td>Safety surveillance</td>
<td>Does exposure to <code><insert your favorite drug></code> increase the risk of experiencing <code><insert an adverse event></code> within <code><time horizon following exposure start></code>?</td>
<td>Does exposure to ACE inhibitor increase the risk of experiencing Angioedema within 1 month after exposure start?</td>
</tr>
<tr class="odd">
<td></td>
<td>Comparative effectiveness</td>
<td>Does exposure to <code><insert your favorite drug></code> have a different risk of experiencing <code><insert any outcome (safety or benefit)></code> within <code><time horizon following exposure start></code>, relative to <code><insert your comparator treatment></code>?</td>
<td>Does exposure to ACE inhibitor have a different risk of experiencing acute myocardial infarction while on treatment, relative to thiazide diuretic?</td>
</tr>
<tr class="even">
<td><strong>Patient level prediction</strong></td>
<td>Disease onset and progression</td>
<td>For a given patient who is diagnosed with <code><insert your favorite disease></code>, what is the probability that they will go on to have <code><another disease or related complication></code> within <code><time horizon from diagnosis></code>?</td>
<td>For a given patient who is newly diagnosed with atrial fibrillation, what is the probability that they will go onto to have ischemic stroke in next 3 years?</td>
</tr>
<tr class="odd">
<td></td>
<td>Treatment response</td>
<td>For a given patient who is a new user of <code><insert your favorite chronically-used drug></code>, what is the probability that they will <code><insert desired effect></code> in <code><time window></code>?</td>
<td>For a given patient with T2DM who start on metformin, what is the probability that they will maintain HbA1C<6.5% after 3 years?</td>
</tr>
<tr class="even">
<td></td>
<td>Treatment safety</td>
<td>For a given patient who is a new user of <code><insert your favorite drug></code>, what is the probability that they will experience <code><insert adverse event></code> within <code><time horizon following exposure></code>?</td>
<td>For a given patients who is a new user of warfarin, what is the probability that they will have GI bleed in 1 year?</td>
</tr>
</tbody>
</table>
<section id="incremental-loading" class="level2">
<h2 class="anchored" data-anchor-id="incremental-loading">Incremental Loading</h2>
<p>Incremental loading in the context of OHDSI refers to the process of adding new or updated data to an existing OHDSI database without the need to completely rebuild or refresh the entire dataset. This can be particularly useful for large datasets where full loads can be time-consuming and inefficient. The process involves extracting only the changes since the last load and then transforming and loading this delta of data into the existing OMOP Common Data Model (CDM) used by OHDSI tools.</p>
<p>For instance, in the development of an ETL (Extract, Transform, Load) process for the bulk and incremental load of German patient data into the OMOP CDM using FHIR as referenced by OHDSI, it suggests that the incremental loading is an essential part of keeping the database up-to-date in an efficient manner. <a href="https://ohdsi.org/2021-global-symposium-showcase-44/#:~:text=,Reinecke%2C%20Michele%20Zoch%2C%20Martin%20Sedlmayr">OHDSI Symposium Showcase #44</a></p>
<p>This is also described by Dr. DuWayne Willett, CMIO of UTSW, at around minute 30 of this video:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="https://www.youtube.com/watch?v=DPatSxFkIpI" title="OHDSI Symposium Presentation by Dr. DuWayne Willett"><img src="http://img.youtube.com/vi/DPatSxFkIpI/0.jpg" class="img-fluid figure-img"></a></p>
<figcaption class="figure-caption">OHDSI Symposium Presentation</figcaption>
</figure>
</div>
<p>…and in this OHDSI symposium presentation: <img src="https://www.ohdsi.org/wp-content/uploads/2023/10/10-Willett-Poster.png" class="img-fluid" alt="OHDSI Symposium Presentation">.</p>
</section>
<section id="the-collaboration-process" class="level2">
<h2 class="anchored" data-anchor-id="the-collaboration-process">The Collaboration Process</h2>
<section id="this-is-just-an-example-of-the-kinds-of-diagrams-we-can-make" class="level3">
<h3 class="anchored" data-anchor-id="this-is-just-an-example-of-the-kinds-of-diagrams-we-can-make">This is just an example of the kinds of diagrams we can make</h3>
<pre class="mermaid"><code>flowchart TD
A[PersonA receives a research request]
B[Person/group B sets up a meeting]
C[Iterative biomedical query mediation process begins]
D[Project outline is created and signed off by all parties]
E[Voucher/payment/estimate is produced including resource and timeframe]
F[Department head reviews/signs off on the voucher request]
G[Work begins]
H[First draft is produced with a notebook outlining results]
I[Meeting is scheduled to review results of the notebook]
J[Necessary modifications are made and returned to the researcher]
K[End of Process]
A --> B
B --> C
C --> D
D --> E
E --> F
F --> G
G --> H
H --> I
I --> J
J -.->|If modifications needed| G
J -->|If complete| K</code></pre>
</section>
</section>
</section>
<section id="section" class="level1">
<h1></h1>
<section id="current-cdm" class="level2">
<h2 class="anchored" data-anchor-id="current-cdm">Current CDM</h2>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://github.com/DBJHU/DBJHU.github.io/blob/main/cdm54.png" class="img-fluid figure-img"></p>
<figcaption class="figure-caption">CDM54 Image</figcaption>
</figure>
</div>
<p><em>Source: <a href="https://ohdsi.github.io/CommonDataModel/index.html">OHDSI Common Data Model</a></em></p>
<p><a href="https://github.com/DBJHU/DBJHU.github.io/blob/main/SelectOMOPDataDictionaryInteractivev2.html">Interactive (Select) OMOP Data Dictionary</a></p>
</section>
</section>
<section id="commonly-used-cdm-tables-overview" class="level1">
<h1>Commonly Used CDM Tables Overview</h1>
<p>The OMOP common data model (CDM) is a relational database made up of different tables that relate to each other by foreign keys (XXXX_ID values; e.g., PERSON_ID or PROVIDER_ID). The OMOP tables in your data export are as follows:</p>
<table class="table">
<colgroup>
<col style="width: 48%">
<col style="width: 51%">
</colgroup>
<thead>
<tr class="header">
<th>Table</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Person</td>
<td>Contains basic demographic information describing a participant, including biological sex, birth date, race, and ethnicity.</td>
</tr>
<tr class="even">
<td>Visit_occurrence</td>
<td>Captures encounters with healthcare providers or similar events. Contains the type of visit a person has (outpatient care, inpatient care, or long-term care), as well as the date and duration information. Rows in other tables can reference this table, for example, condition_occurrences related to a specific visit.</td>
</tr>
<tr class="odd">
<td>Condition_occurrence</td>
<td>Indicates the presence of a disease or medical condition stated as a diagnosis, a sign, or symptom, which is either observed by a provider or reported by the patient.</td>
</tr>
<tr class="even">
<td>Drug_exposure</td>
<td>Captures records about the utilization of a medication. Drug exposures include prescription and over-the-counter medicines, vaccines, and large-molecule biologic therapies. Radiological devices ingested or applied locally do not count as drugs. Drug exposure is inferred from clinical events associated with orders, prescriptions written, pharmacy dispensing, procedural administrations, and other patient-reported information.</td>
</tr>
<tr class="odd">
<td>Measurement</td>
<td>Contains both orders and results of a systematic and standardized examination or testing of a participant or participant’s sample, including laboratory tests, vital signs, quantitative findings from pathology reports, etc.</td>
</tr>
<tr class="even">
<td>Procedure_occurrence</td>
<td>Contains records of activities or processes ordered by or carried out by a healthcare provider on the patient to have a diagnostic or therapeutic purpose.</td>
</tr>
<tr class="odd">
<td>Observation</td>
<td>Captures clinical facts about a person obtained in the context of an examination, questioning, or a procedure. Any data that cannot be represented by another domain, such as social and lifestyle facts, medical history, and family history, are recorded here.</td>
</tr>
<tr class="even">
<td>Device_exposure</td>
<td>Captures information about a person’s exposure to a foreign physical object or instrument which is used for diagnostic or therapeutic purposes. Devices include implantable objects, blood transfusions, medical equipment and supplies, other instruments used in medical procedures, and material used in clinical care.</td>
</tr>
<tr class="odd">
<td>Death</td>
<td>Contains the clinical events surrounding how and when a participant dies.</td>
</tr>
</tbody>
</table>
<pre class="mermaid"><code>graph LR
ICD9("ICD9") -->|Transformation to OMOP CDM| SNOMED("STANDARD<br>Vocabulary Concept Code<br>SNOMED")
ICD10("ICD10") -->|Transformation to OMOP CDM| SNOMED</code></pre>
<table class="table">
<colgroup>
<col style="width: 31%">
<col style="width: 37%">
<col style="width: 31%">
</colgroup>
<thead>
<tr class="header">
<th>Domain</th>
<th>Source Vocabulary</th>
<th>Standard Vocabulary</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Conditions</td>
<td>ICD9, ICD10</td>
<td>SNOMED</td>
</tr>
<tr class="even">
<td>Measurements</td>
<td>LOINC or institutional specific codes</td>
<td>LOINC</td>
</tr>
<tr class="odd">
<td>Drugs</td>
<td>NDC</td>
<td>RxNORM</td>
</tr>
<tr class="even">
<td>Procedures</td>
<td>ICD9, ICD10, CPT</td>
<td>SNOMED</td>
</tr>
</tbody>
</table>
<ul>
<li>ICD = International Classification of Diseases</li>
<li>SNOMED = Systematized Nomenclature of Medicine</li>
<li>LOINC = Logical Observation Identifiers Names and Codes</li>
<li>NDC = National Drug Code</li>
<li>CPT = Current Procedural Terminology</li>
</ul>
</section>
<section id="analysis-tools" class="level1">
<h1>Analysis Tools</h1>
<p>R, SQL, Python, or any preferred data analysis software. Examples provided below are for R and SQL. [The Book of OHDSI Chapter 9] (https://ohdsi.github.io/TheBookOfOhdsi/SqlAndR.html) provides an overview of analysis of OHDSI data in R and SQL; note that you will not be able to avail yourselves of OHDSI software tools when analyzing your exported data for the reason explained above. < ## Jupyter Notebooks and programming [Source:NIH All of US Study] (https://support.researchallofus.org/hc/en-us/articles/360039690191-Jupyter-Notebooks-and-programming)</p>
<p>Below you will find links to helpful resources on using Jupyter Notebooks. Below you will find links to some of the most helpful resources that we have created and/or found on using Jupyter Notebooks. While we can’t teach you how to program, we have identified some online resources that can help get you started. ### OHDSI Resources Hello! Please familiarize yourself with the following tools and resources which will help you throughout this course and your OHDSI journey.</p>
<p>Check out the <a href="https://forums.ohdsi.org/"><strong>OHDSI Forums</strong></a> <em>Introduce yourself on the “Welcome to OHDSI” thread.</em></p>
<p>Bookmark <a href="https://ohdsi.github.io/TheBookOfOhdsi/"><strong>The Book of OHDSI</strong></a></p>
<p>Join the OHDSI <a href="https://forms.office.com/Pages/ResponsePage.aspx?id=lAAPoyCRq0q6TOVQkCOy1ZyG6Ud_r2tKuS0HcGnqiQZUQ05MOU9BSzEwOThZVjNQVVFGTDNZRENONiQlQCN0PWcu"><strong>Microsoft Teams</strong></a> environment.</p>
<p>Check out the <a href="https://physionet.org/content/mimic-iv-demo-omop/0.9/1_omop_data_csv/"><strong>MIMIC-IV demo data set</strong></a> in OMOP CDM format!</p>
<p>Register with <a href="https://academy.ehden.eu/"><strong>EHDEN Academy</strong></a></p>
<p>Visit the <a href="https://atlas-demo.ohdsi.org/"><strong>Atlas Demo</strong></a> and <a href="https://athena.ohdsi.org/search-terms/start"><strong>Athena</strong></a>.</p>
<p>Bookmark the <a href="https://youtube.com/playlist?list=PLpzbqK7kvfeXRQktX0PV-cRpb3EFA2e7Z"><strong>OHDSI YouTube tutorials and workshops</strong></a></p>
<p>Visit the <a href="https://dash.ohdsi.org/"><strong>OHDSI Community Dashboard</strong></a></p>
<p>Bookmark <a href="https://ohdsi.github.io/CommonDataModel/index.html"><strong>OMOP Common Data Model (ohdsi.github.io)</strong></a></p>
<p><a href="https://docs.github.com/en/get-started/quickstart/hello-world"><strong>Learn about GitHub</strong></a> if you don’t already know.</p>
<p>Plan to attend an <a href="https://ohdsi.org/community-calls/"><strong>OHDSI Community call</strong></a></p>
<p>Learn about OHDSI <a href="https://ohdsi.org/upcoming-working-group-calls/"><strong>Workgroups</strong></a></p>
<p>Follow OHDSI on social media: <a href="https://twitter.com/OHDSI"><strong>Twitter</strong></a> <a href="https://www.linkedin.com/company/ohdsi"><strong>LinkedIn</strong></a></p>
<p><a href="https://ohdsi.org/subscribe-to-our-newsletter/"><strong>Subscribe</strong></a> to the OHDSI Newsletter</p>
<p>Learn about past and <a href="https://ohdsi.org/2023-ohdsi-events/"><strong>upcoming OHDSI events</strong></a></p>
<p>Learn about OHDSI <a href="https://ohdsi.org/software-tools/"><strong>software</strong></a></p>
<p>Look up individual concepts in <a href="https://athena.ohdsi.org/">Athena</a></p>
<p>Check out useful OHDSI-related documentation here: <a href="https://support.researchallofus.org/hc/en-us/articles/360039585391-How-the-Observational-Medical-Outcomes-Partnership-OMOP-vocabulary-are-structured">NIH ALL of US OMOP Documentation</a></p>
</section>
<section id="recommended-trainings" class="level1">
<h1>Recommended Trainings</h1>
<section id="ohdsi-community" class="level2">
<h2 class="anchored" data-anchor-id="ohdsi-community">OHDSI Community</h2>
<p><strong>Broadsea3.0</strong><br>
By: Lee Evans<br>
<a href="https://youtu.be/CNlsZzY7VrM"><img src="https://img.youtube.com/vi/CNlsZzY7VrM/0.jpg" class="img-fluid" alt="Broadsea 3.0"></a></p>
</section>
<section id="tufts-bridge2ai-standards-module" class="level2">
<h2 class="anchored" data-anchor-id="tufts-bridge2ai-standards-module">Tufts Bridge2AI Standards Module</h2>
<ul>
<li><p><strong>June 15, 2023:</strong><br>
<strong>Data Quality Dashboard</strong><br>
By: Jared Houghtaling<br>
<a href="https://youtu.be/O2L1x0Sv3lc"><img src="https://img.youtube.com/vi/O2L1x0Sv3lc/0.jpg" class="img-fluid" alt="Data Quality Dashboard"></a></p></li>
<li><p><strong>July 6, 2023:</strong><br>
<strong>Data Quality Dashboard output demo</strong><br>
By: Jared Houghtaling<br>
<a href="https://youtu.be/qYDq5-dg-io"><img src="https://img.youtube.com/vi/qYDq5-dg-io/0.jpg" class="img-fluid" alt="Data Quality Dashboard output demo"></a></p></li>
<li><p><strong>July 13, 2023:</strong><br>
<strong>Achilles output demo</strong><br>
By: Jared Houghtaling<br>
<a href="https://youtu.be/bIRQVgcnAwI"><img src="https://img.youtube.com/vi/bIRQVgcnAwI/0.jpg" class="img-fluid" alt="Achilles output demo"></a></p></li>
<li><p><strong>July 27, 2023:</strong><br>
<strong>Flowsheet follow-up</strong><br>
By: Polina Talapova & Jared Houghtaling<br>
<a href="https://youtu.be/3cTT2XJZslI"><img src="https://img.youtube.com/vi/3cTT2XJZslI/0.jpg" class="img-fluid" alt="Flowsheet follow-up"></a></p></li>
<li><p><strong>August 3, 2023:</strong><br>
<strong>OMOP Standardized Vocabularies - Part 1</strong><br>
By: Jared Houghtaling and Polina Talapova<br>
<a href="https://youtu.be/4xnH7-oJxyo"><img src="https://img.youtube.com/vi/4xnH7-oJxyo/0.jpg" class="img-fluid" alt="OMOP Standardized Vocabularies - Part 1"></a></p></li>
<li><p><strong>August 17, 2023:</strong><br>
<strong>OMOP Standardized Vocabularies - Part 2</strong><br>
By: Polina Talapova<br>
<a href="https://youtu.be/1J7ISUASx6k"><img src="https://img.youtube.com/vi/1J7ISUASx6k/0.jpg" class="img-fluid" alt="OMOP Standardized Vocabularies - Part 2"></a></p></li>
<li><p><strong>August 24, 2023:</strong><br>
<strong>How to download and set-up a DDL (Demo)</strong><br>
By: Jared Houghtaling<br>
<a href="https://youtu.be/x9W3sa1xGoQ"><img src="https://img.youtube.com/vi/x9W3sa1xGoQ/0.jpg" class="img-fluid" alt="How to download and set-up a DDL (Demo)"></a></p></li>
<li><p><strong>August 31, 2023:</strong><br>
<strong>Demo of WhiteRabbit and RabbitInAHat</strong><br>
By: Jared Houghtaling<br>
<a href="https://youtu.be/gu1fQVwkBo8"><img src="https://img.youtube.com/vi/gu1fQVwkBo8/0.jpg" class="img-fluid" alt="Demo of WhiteRabbit and RabbitInAHat"></a></p></li>
<li><p><strong>September 7, 2023:</strong><br>
<strong>ARES usefulness for ETL at Tufts</strong><br>
By: Jared Houghtaling<br>
<a href="https://youtu.be/Czox3WT1pDM"><img src="https://img.youtube.com/vi/Czox3WT1pDM/0.jpg" class="img-fluid" alt="ARES usefulness for ETL at Tufts"></a></p></li>
<li><p><strong>September 14, 2023:</strong><br>
<strong>Google form introduction for site progress tracking</strong><br>
By: Jared Houghtaling<br>
<a href="https://youtu.be/ntZwikqhIcM"><img src="https://img.youtube.com/vi/ntZwikqhIcM/0.jpg" class="img-fluid" alt="Google form introduction for site progress tracking"></a></p></li>
<li><p><strong>September 21, 2023:</strong><br>
<strong>Sample ETL Process</strong><br>
By: Jared Houghtaling<br>
<a href="https://youtu.be/uX289BrzXM4"><img src="https://img.youtube.com/vi/uX289BrzXM4/0.jpg" class="img-fluid" alt="Sample ETL Process"></a></p></li>
</ul>
<p><strong>October 12, 2023:</strong><br>
<strong>Google Form for Site Progress Tracking</strong><br>
With Jared Houghtaling and Andrew Williams<br>
<a href="https://youtu.be/oTP6ISo8FWc"><img src="https://img.youtube.com/vi/oTP6ISo8FWc/0.jpg" class="img-fluid" alt="Google Form for Site Progress Tracking"></a></p>
<ul>
<li><p><strong>October 26, 2023:</strong><br>
<strong>Review and Prioritization of DQD Results, and Discussion of DQD Issue Severity</strong><br>
With Jared Houghtaling<br>
<a href="https://youtu.be/dJr5tkm-Ex4"><img src="https://img.youtube.com/vi/dJr5tkm-Ex4/0.jpg" class="img-fluid" alt="Review and Prioritization of DQD Results, and Discussion of DQD Issue Severity"></a></p></li>
<li><p><strong>November 2, 2023:</strong><br>
<strong>Principles of Mapping and Vocab Gaps Identification</strong><br>
With Polina Talapova<br>
<a href="https://youtu.be/jOKzb3x6hmo"><img src="https://img.youtube.com/vi/jOKzb3x6hmo/0.jpg" class="img-fluid" alt="Principles of Mapping and Vocab Gaps Identification"></a></p></li>
<li><p><strong>November 9, 2023:</strong><br>
<strong>Usagi & STCM Demo</strong><br>
With Polina Talapova & Jared Houghtailing<br>
<a href="https://youtu.be/hNhph-elrp4"><img src="https://img.youtube.com/vi/hNhph-elrp4/0.jpg" class="img-fluid" alt="Usagi & STCM Demo"></a></p></li>
</ul>
</section>
<section id="python-sql-and-r-programming-resources" class="level2">
<h2 class="anchored" data-anchor-id="python-sql-and-r-programming-resources">Python, SQL, and R Programming Resources</h2>
<ul>
<li><a href="https://jupyter.org/">Project Jupyter</a></li>
<li><a href="https://jupyter-notebook-beginner-guide.readthedocs.io/en/latest/what_is_jupyter.html">What is the Jupyter Notebook?</a></li>
<li><a href="https://bioinformatics.niaid.nih.gov/resources">NIAID NIH Informatics resources</a></li>
</ul>
<p>Software Carpentry is a website that provides free online lessons to researchers wanting to enhance their programming skills for data analysis. This website offers free online lessons on a variety of useful topics including:</p>
<ul>
<li><a href="http://swcarpentry.github.io/python-novice-inflammation/">Programming with Python</a></li>
<li><a href="http://swcarpentry.github.io/r-novice-inflammation/">Programming with R</a></li>
<li><a href="http://swcarpentry.github.io/sql-novice-survey/">Databases and SQL</a></li>
</ul>
<p>We have included additional resources for help with programming below.</p>
<ul>
<li><a href="http://www.datacamp.com/">DataCamp</a></li>
<li><a href="https://www.khanacademy.org/computing/computer-programming/sql/sql-basics/v/welcome-to-sql">Khan Academy</a></li>
<li><a href="https://www.codecademy.com/learn/learn-python">Codecademy - Learn Python 2</a></li>
<li><a href="https://jakevdp.github.io/PythonDataScienceHandbook/">Python Data Science Handbook</a></li>
<li><a href="https://r4ds.had.co.nz/">R for Data Science</a></li>
<li><a href="https://bioinformatics.niaid.nih.gov/resources%20-%2070.3.1">Introduction to Programming (NIAID, NIH)</a></li>
<li><a href="https://bioinformatics.niaid.nih.gov/resources%20-%2070.3.2">Python Programming (NIAID, NIH)</a></li>
<li><a href="https://bioinformatics.niaid.nih.gov/resources%20-%2070.3.3">Data Analysis with Python and Pandas (NIAID, NIH)</a></li>
<li><a href="https://bioinformatics.niaid.nih.gov/resources%20-%2070.3.4">Data Visualization with Python (NIAID, NIH)</a></li>
</ul>
</section>
<section id="analysis-with-sql" class="level2">
<h2 class="anchored" data-anchor-id="analysis-with-sql">Analysis with SQL</h2>
<p>The <a href="https://data.ohdsi.org/QueryLibrary/">OMOP Query Library</a> is a library of commonly-used SQL queries for the OMOP Common Data Model (CDM).</p>
</section>
<section id="analysis-with-r" class="level2">
<h2 class="anchored" data-anchor-id="analysis-with-r">Analysis with R</h2>
<p>Below are some sample R queries that demonstrate how to read in OMOP tables from CSV files, join them based on the <code>person_id</code> and <code>visit_occurrence_id</code> fields, and search for specific criteria.</p>
<p>Note: Adjust the file paths and column names accordingly based on the actual structure and location of your CSV files. The queries below are a generic representation and may need adjustments based on the specifics of your data set.</p>
<section id="reading-csv-files-into-r-data-frames" class="level3">
<h3 class="anchored" data-anchor-id="reading-csv-files-into-r-data-frames">Reading CSV files into R data frames:</h3>
<div class="sourceCode" id="cb3"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Read the CSV files into R data frames</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>person_df <span class="ot"><-</span> <span class="fu">read.csv</span>(<span class="st">"path_to_person_table.csv"</span>, <span class="at">header=</span><span class="cn">TRUE</span>, <span class="at">stringsAsFactors=</span><span class="cn">FALSE</span>)</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>visit_occurrence_df <span class="ot"><-</span> <span class="fu">read.csv</span>(<span class="st">"path_to_visit_occurrence_table.csv"</span>, <span class="at">header=</span><span class="cn">TRUE</span>, <span class="at">stringsAsFactors=</span><span class="cn">FALSE</span>)</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>condition_occurrence_df <span class="ot"><-</span> <span class="fu">read.csv</span>(<span class="st">"path_to_condition_occurrence_table.csv"</span>, <span class="at">header=</span><span class="cn">TRUE</span>, <span class="at">stringsAsFactors=</span><span class="cn">FALSE</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<p>Join tables based on <code>person_id</code>:</p>
<p>When a person has multiple visits in the <code>visit_occurrence</code> table, joining the <code>person</code> table with the <code>visit_occurrence</code> table will result in multiple rows for that person, each corresponding to a different visit. This is a standard one-to-many join operation.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="do">## Join person with visit_occurrence on 'person_id'</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>person_visit_df <span class="ot"><-</span> <span class="fu">merge</span>(person_df, visit_occurrence_df, <span class="at">by=</span><span class="st">"person_id"</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</section>
<section id="joining-the-person-visit-table-with-the-condition-occurrence-table" class="level3">
<h3 class="anchored" data-anchor-id="joining-the-person-visit-table-with-the-condition-occurrence-table">Joining the Person-Visit table with the Condition Occurrence table:</h3>
<div class="sourceCode" id="cb5"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Join the person-visit result with condition_occurrence on both 'person_id' and 'visit_occurrence_id'</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>full_df <span class="ot"><-</span> <span class="fu">merge</span>(person_visit_df, condition_occurrence_df, <span class="at">by=</span><span class="fu">c</span>(<span class="st">"person_id"</span>, <span class="st">"visit_occurrence_id"</span>))</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</section>
<section id="search-by-a-list-of-person_ids" class="level3">
<h3 class="anchored" data-anchor-id="search-by-a-list-of-person_ids">Search by a list of <code>person_ids</code>:</h3>
<div class="sourceCode" id="cb6"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Define a list of person_ids to search for</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>search_person_ids <span class="ot"><-</span> <span class="fu">c</span>(<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span>, <span class="dv">5</span>)</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="co"># Filter the data frame to only include rows with person_ids in the list</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>filtered_by_person_df <span class="ot"><-</span> <span class="fu">subset</span>(full_df, person_id <span class="sc">%in%</span> search_person_ids)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</section>
<section id="search-by-a-specific-condition-concept-code" class="level3">
<h3 class="anchored" data-anchor-id="search-by-a-specific-condition-concept-code">Search by a specific condition concept code:</h3>
<div class="sourceCode" id="cb7"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Define a specific condition concept code to search for</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>search_condition_concept_id <span class="ot"><-</span> <span class="dv">1234567</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="co"># Filter the data frame to only include rows with the specified condition concept code</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>filtered_by_condition_df <span class="ot"><-</span> <span class="fu">subset</span>(full_df, condition_concept_id <span class="sc">==</span> search_condition_concept_id)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
</section>
<section id="search-by-a-date-range" class="level3">
<h3 class="anchored" data-anchor-id="search-by-a-date-range">Search by a date range:</h3>
<div class="sourceCode" id="cb8"><pre class="sourceCode r code-with-copy"><code class="sourceCode r"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Define a date range to search for</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>start_date <span class="ot"><-</span> <span class="fu">as.Date</span>(<span class="st">"2020-01-01"</span>)</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>end_date <span class="ot"><-</span> <span class="fu">as.Date</span>(<span class="st">"2020-12-31"</span>)</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="do">## Filter the data frame to only include rows within the date range</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>filtered_by_date_df <span class="ot"><-</span> <span class="fu">subset</span>(full_df, visit_start_date <span class="sc">>=</span> start_date <span class="sc">&</span> visit_start_date <span class="sc"><=</span> end_date)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div>
<!--TBD
## Analysis with Python
### Required Python Libraries:
To execute the Python queries, you'll need to install the pandas library. -->
<!--- WIP
# OMOP ETL Process: Common Problems and Solutions
## Design and Planning
| Problem | Suggestion |
| ------- | ---------- |
| Different Coding Schemes in Databases | Standardize structures, conventions, and content during ETL to align different coding schemes. |
| Designing ETL with Expert Collaboration | Collaborate between data and CDM experts for efficient design. |
| Inadequate Source Data Documentation | Use White Rabbit to scan and understand source data thoroughly. |
| Mapping Source Data to CDM | Use Rabbit-in-a-Hat tool for interactive mapping and documentation. |
| Mapping Non-OMOP Coding Systems | Focus on frequently used codes and utilize existing mappings where possible. |
| Handling Post Coordinated SNOMED Codes | Address challenges with codes or conditions occurring multiple times. |
| Integration of New Data Sources | Develop a flexible ETL process to integrate new data sources. |
| Handling Various Data Formats | Create processes to handle different data formats effectively. |
| Custom Code Development for ETL | Develop custom code when necessary for specific ETL requirements. |
| Adapting to CDM Updates | Adapt ETL processes to accommodate updates in the CDM. |
## Implementation and Technology
| Problem | Suggestion |
| ------- | ---------- |
| ETL Implementation | Utilize existing code and community resources for efficient ETL process implementation. |
| Choosing ETL Implementation Technology | Select technology based on site expertise (SQL, SAS, C#, Java, etc.). |
| Data Transformation Logic | Clearly define and document the logic for data transformations. |
| ETL Performance Optimization | Continuously monitor and optimize ETL performance. |
| Scalability of ETL Processes | Ensure that ETL processes are scalable to accommodate growing data. |
| Data Mapping Complexities | Address complexities in mapping data from various sources to the CDM. |
| Updating and Maintenance of ETL Scripts | Regularly update and maintain ETL scripts for consistency. |
| Managing ETL Dependencies | Identify and manage dependencies in the ETL process. |
| Cross-Database Compatibility | Ensure compatibility of ETL processes across different databases. |
| Optimizing Data Load Processes | Optimize data load processes to enhance performance. |
## Data Quality and Security
| Problem | Suggestion |
| ------- | ---------- |
| Data Quality Issues | Implement thorough quality control measures to ensure data integrity. |
| Large Dataset Handling | Optimize ETL processes for handling large datasets efficiently. |
| Missing or Incomplete Data | Develop strategies to handle missing or incomplete data elements. |
| Handling Data Anomalies | Develop procedures to identify and resolve data anomalies. |
| Data Security and Compliance | Maintain strict adherence to data security and compliance standards. |
| Data Validation Processes | Implement robust data validation processes to ensure accuracy. |
| Error Handling in ETL Process | Develop comprehensive error handling mechanisms. |
| Source Data Version Control | Maintain version control for source data to track changes. |
| Data Cleansing Procedures | Establish data cleansing procedures to improve data quality. |
| Complex Transformation Rules | Manage complex transformation rules efficiently. |
## Operational Management
| Problem | Suggestion |
| ------- | ---------- |
| Automation of ETL Processes | Explore opportunities to automate repetitive ETL tasks. |
| Resource Allocation for ETL Tasks | Allocate sufficient resources for ETL tasks. |
| Maintaining Data Lineage | Keep track of data lineage throughout the ETL process. |
| Balancing ETL Speed and Accuracy | Balance the need for speed with accuracy in ETL processes. |
| Training for ETL Team | Provide comprehensive training for the ETL team. |
| Standardizing ETL Practices | Standardize ETL practices across various projects. |
| Monitoring ETL Processes | Implement monitoring tools to oversee ETL processes. |
| Dealing with Data Duplication | Develop strategies to handle data duplication issues. |
| Dynamic Data Source Integration | Integrate dynamic data sources effectively into the ETL process. |
| Data Transformation Standardization | Standardize data transformation rules across different datasets. |
| Collaboration and Communication | Foster collaboration and communication among all stakeholders involved in the ETL process. |
-->
</section>
</section>
</section>
</main>
<!-- /main column -->
<script id="quarto-html-after-body" type="application/javascript">
window.document.addEventListener("DOMContentLoaded", function (event) {
const toggleBodyColorMode = (bsSheetEl) => {
const mode = bsSheetEl.getAttribute("data-mode");
const bodyEl = window.document.querySelector("body");
if (mode === "dark") {
bodyEl.classList.add("quarto-dark");
bodyEl.classList.remove("quarto-light");
} else {
bodyEl.classList.add("quarto-light");
bodyEl.classList.remove("quarto-dark");
}
}
const toggleBodyColorPrimary = () => {
const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
if (bsSheetEl) {
toggleBodyColorMode(bsSheetEl);
}
}
toggleBodyColorPrimary();
const icon = "";
const anchorJS = new window.AnchorJS();
anchorJS.options = {
placement: 'right',
icon: icon
};
anchorJS.add('.anchored');
const isCodeAnnotation = (el) => {
for (const clz of el.classList) {
if (clz.startsWith('code-annotation-')) {
return true;
}
}
return false;
}
const clipboard = new window.ClipboardJS('.code-copy-button', {
text: function(trigger) {
const codeEl = trigger.previousElementSibling.cloneNode(true);
for (const childEl of codeEl.children) {
if (isCodeAnnotation(childEl)) {
childEl.remove();
}
}
return codeEl.innerText;
}
});
clipboard.on('success', function(e) {
// button target
const button = e.trigger;
// don't keep focus
button.blur();
// flash "checked"
button.classList.add('code-copy-button-checked');
var currentTitle = button.getAttribute("title");
button.setAttribute("title", "Copied!");
let tooltip;
if (window.bootstrap) {
button.setAttribute("data-bs-toggle", "tooltip");
button.setAttribute("data-bs-placement", "left");
button.setAttribute("data-bs-title", "Copied!");
tooltip = new bootstrap.Tooltip(button,
{ trigger: "manual",
customClass: "code-copy-button-tooltip",
offset: [0, -8]});
tooltip.show();
}
setTimeout(function() {
if (tooltip) {
tooltip.hide();
button.removeAttribute("data-bs-title");
button.removeAttribute("data-bs-toggle");
button.removeAttribute("data-bs-placement");
}
button.setAttribute("title", currentTitle);
button.classList.remove('code-copy-button-checked');
}, 1000);
// clear code selection
e.clearSelection();
});
function tippyHover(el, contentFn) {
const config = {
allowHTML: true,
content: contentFn,
maxWidth: 500,
delay: 100,
arrow: false,
appendTo: function(el) {
return el.parentElement;
},
interactive: true,
interactiveBorder: 10,
theme: 'quarto',
placement: 'bottom-start'
};
window.tippy(el, config);
}
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
for (var i=0; i<noterefs.length; i++) {
const ref = noterefs[i];
tippyHover(ref, function() {
// use id or data attribute instead here
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
try { href = new URL(href).hash; } catch {}
const id = href.replace(/^#\/?/, "");
const note = window.document.getElementById(id);
return note.innerHTML;
});
}
let selectedAnnoteEl;
const selectorForAnnotation = ( cell, annotation) => {
let cellAttr = 'data-code-cell="' + cell + '"';
let lineAttr = 'data-code-annotation="' + annotation + '"';
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
return selector;
}
const selectCodeLines = (annoteEl) => {
const doc = window.document;
const targetCell = annoteEl.getAttribute("data-target-cell");
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
const lineIds = lines.map((line) => {
return targetCell + "-" + line;
})
let top = null;
let height = null;
let parent = null;
if (lineIds.length > 0) {
//compute the position of the single el (top and bottom and make a div)
const el = window.document.getElementById(lineIds[0]);
top = el.offsetTop;
height = el.offsetHeight;
parent = el.parentElement.parentElement;
if (lineIds.length > 1) {
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
height = bottom - top;
}
if (top !== null && height !== null && parent !== null) {
// cook up a div (if necessary) and position it
let div = window.document.getElementById("code-annotation-line-highlight");
if (div === null) {
div = window.document.createElement("div");
div.setAttribute("id", "code-annotation-line-highlight");
div.style.position = 'absolute';
parent.appendChild(div);
}
div.style.top = top - 2 + "px";
div.style.height = height + 4 + "px";
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
if (gutterDiv === null) {
gutterDiv = window.document.createElement("div");
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
gutterDiv.style.position = 'absolute';
const codeCell = window.document.getElementById(targetCell);
const gutter = codeCell.querySelector('.code-annotation-gutter');
gutter.appendChild(gutterDiv);
}
gutterDiv.style.top = top - 2 + "px";
gutterDiv.style.height = height + 4 + "px";
}
selectedAnnoteEl = annoteEl;
}
};
const unselectCodeLines = () => {
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
elementsIds.forEach((elId) => {
const div = window.document.getElementById(elId);
if (div) {
div.remove();
}
});
selectedAnnoteEl = undefined;
};
// Attach click handler to the DT
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
for (const annoteDlNode of annoteDls) {
annoteDlNode.addEventListener('click', (event) => {
const clickedEl = event.target;
if (clickedEl !== selectedAnnoteEl) {
unselectCodeLines();
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
if (activeEl) {
activeEl.classList.remove('code-annotation-active');
}
selectCodeLines(clickedEl);
clickedEl.classList.add('code-annotation-active');
} else {
// Unselect the line
unselectCodeLines();
clickedEl.classList.remove('code-annotation-active');
}
});
}
const findCites = (el) => {
const parentEl = el.parentElement;
if (parentEl) {
const cites = parentEl.dataset.cites;
if (cites) {
return {
el,
cites: cites.split(' ')
};
} else {
return findCites(el.parentElement)
}
} else {
return undefined;
}
};
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
for (var i=0; i<bibliorefs.length; i++) {
const ref = bibliorefs[i];
const citeInfo = findCites(ref);
if (citeInfo) {
tippyHover(citeInfo.el, function() {
var popup = window.document.createElement('div');
citeInfo.cites.forEach(function(cite) {
var citeDiv = window.document.createElement('div');
citeDiv.classList.add('hanging-indent');
citeDiv.classList.add('csl-entry');
var biblioDiv = window.document.getElementById('ref-' + cite);
if (biblioDiv) {
citeDiv.innerHTML = biblioDiv.innerHTML;
}
popup.appendChild(citeDiv);
});
return popup.innerHTML;
});
}
}
});
</script>
</div> <!-- /content -->
</body></html>