5.3.1 3.1 Primary Objective
[Clear statement of primary objective]
SOCR ≫ | DSPA ≫ | DSPA2 Topics ≫ |
This DSPA Appendix shows examples of tapping into external artificial intelligence (AI) application programming interfaces (APIs) to generate AI predictions, responses, reviews, and recommendations based on the user’s prompts. We demonstrate mainly OpenAI API interfaces but similar protocols work for all other AI service providers.
This document demonstrates how to interact with OpenAI’s API using R.
It provides a comprehensive set of functions for sending requests to
various OpenAI endpoints, handling responses, and managing errors. The
same R/Rmd
interfqace to OpenAI API can be reproduced in a
Python
-based OpenAI API client.
Here is the overall protocol:
Set up and configure the AI API environment, including
azure_openai_endpoint
, deployment_name
,
api_version
, api_key
, and (optional)
organization_id
Define the exact API URL
Create the prompt:
Explain the math foundation of complex-time (kime) representation of repeated measurement spaciotemporal processes, where kappa = t * e^{i theta}, t is time, and theta is random distributed according to Phi(t), a kime-phase distribution. Use LaTeX typesetting.
Specify appropriate AI/LLM parameters, e.g.,
max_tokens
, temperature
Submit the request, check the response validity, and parse its content.
# Load required packages
if (!require("httr", quietly = TRUE)) install.packages("httr")
if (!require("jsonlite", quietly = TRUE)) install.packages("jsonlite")
library(httr)
library(jsonlite)
library(httr)
library(jsonlite)
# Enhanced function to read .env file and set environmental variables with debugging
read_env_file <- function(file_path = ".env") {
# Check if file exists
if (!file.exists(file_path)) {
stop("Error: .env file not found at ", file_path)
}
# Print file contents for debugging
# cat("Contents of .env file:\n")
file_contents <- readLines(file_path, warn = FALSE)
# print(file_contents)
# Process each line
for (line in file_contents) {
# Skip comments and empty lines
if (grepl("^\\s*#", line) || trimws(line) == "") {
next
}
# Find position of first equals sign
pos <- regexpr("=", line, fixed = TRUE)[1]
if (pos > 0) {
# Extract key and value
key <- trimws(substr(line, 1, pos - 1))
value <- trimws(substr(line, pos + 1, nchar(line)))
# Remove quotes if present
if ((substr(value, 1, 1) == "\"" && substr(value, nchar(value), nchar(value)) == "\"") ||
(substr(value, 1, 1) == "'" && substr(value, nchar(value), nchar(value)) == "'")) {
value <- substr(value, 2, nchar(value) - 1)
}
# Set the environment variable using direct assignment
# cat("Setting", key, "=", value, "\n")
assign_cmd <- paste0("Sys.setenv(", key, "='", value, "')")
eval(parse(text = assign_cmd))
}
}
return(TRUE)
}
# Check if .env file exists, if not, create it
if (!file.exists(".env")) {
cat('azure_openai_endpoint="https://api.umgpt.umich.edu/azure-openai-api"
deployment_name="gpt-4"
api_version="2024-10-21"
api_key="private_key"
organization_id="004036"', file = ".env")
cat("Created new .env file\n")
}
# Read the .env file
read_env_file()
## [1] TRUE
# Mask the private API key
mask_key <- function(key) {
if (nchar(key) <= 4) {
return(paste0(rep("*", nchar(key)), collapse=""))
} else {
# Show first 1 and last 1 characters, mask everything else
first_chars <- substr(key, 1, 1) # substr(key, 1, 2)
last_chars <- substr(key, nchar(key), nchar(key))
middle_mask <- paste0(rep("*", nchar(key) - 2), collapse="")
return(paste0(first_chars, middle_mask, last_chars))
}
}
# Print the environmental variables
cat("\nEnvironmental Variables after setting:\n")
##
## Environmental Variables after setting:
## Azure OpenAI Endpoint: https://api.umgpt.umich.edu/azure-openai-api
## Deployment Name: gpt-4
## API Version: 2024-10-21
## API Key: 4******************************3
# cat("API Key:", Sys.getenv("api_key"), "\n")
cat("Organization ID:", mask_key(Sys.getenv("organization_id")), "\n")
## Organization ID: 0****6
# # Set your Azure OpenAI info
azure_openai_endpoint <- Sys.getenv("azure_openai_endpoint")
deployment_name <- Sys.getenv("deployment_name") # "gpt-4" # e.g., "gpt-35-turbo"
api_version <- Sys.getenv("api_version") # "2024-10-21"
api_key <- Sys.getenv("api_key") # "private_key"
organization_id <- Sys.getenv("organization_id") # Optional in Azure, used in OpenAI.com
# Define the API URL
url <- paste0(
azure_openai_endpoint,
"/openai/deployments/", deployment_name,
"/chat/completions?api-version=", api_version
)
# Create the request body
myPrompt <- "Explain the math foundation of complex-time (kime) representation of repeated measurement spaciotemporal processes, where kappa = t * e^{i theta}, t is time, and theta is random distributed according to Phi(t), a kime-phase distribution. Use LaTeX typesetting."
body <- list(
messages = list(
list(role = "system", content = "You are a helpful assistant."),
list(role = "user", content = myPrompt)
),
max_tokens = 200,
temperature = 0.7
)
model_type <- "gpt-4"
temperature <- 0.7
max_tokens <- 200
data_path <- "data/"
custom_prompt <- "Explain complex time (kime), \\kappa = t e^{i\\theta}, where t is time and \\theta is a random variable distributed accoridng to a kime-phase distribution \\Phi (t)"
params <- data.frame(model_type, temperature, max_tokens, data_path, custom_prompt)
# Send POST request
response <- POST(
url,
add_headers(
`api-key` = api_key,
`Content-Type` = "application/json",
`OpenAI-Organization` = organization_id # Optional for Azure
),
body = toJSON(body, auto_unbox = TRUE)
)
# Check and parse response
if (status_code(response) == 200) {
content_data <- content(response, "parsed")
# Remove the extra backslashes to fix LaTeX rendering
clean_response <- gsub("\\\\", "\\",
content_data$choices[[1]]$message$content, fixed = TRUE)
cat("Response:\n", clean_response, "\n")
} else {
cat("Error:\n", content(response, "text"), "\n")
}
## Response:
## The concept of complex-time or "kime" representation in the context of repeated measurement spaciotemporal processes is an advanced theoretical framework that aims to capture the dynamics of processes where both the magnitude and the phase of time could be influential. The variable \(\kappa\) is defined as \(\kappa = t e^{i \theta}\), where \(t\) is the real time, and \(\theta\) is a phase component that is randomly distributed according to a specific distribution \(\Phi(t)\). This section will delve into the mathematical foundation of this representation.
##
## ### 1. Definition of Kime
##
## The kime, \(\kappa\), is defined by:
## \[
## \kappa = t e^{i \theta}
## \]
## where \( t \) is the real time, and \( e^{i \theta} \) adds a complex exponential component. The exponential term \( e^{i \theta} \) introduces the concept of a phase into the
# # Parse and print response
# response_content <- content(response, "parsed")
# cat(response_content$choices[[1]]$message$content, "\n")
In the pure textual prompt
below, notice that no LaTeX
is used. If can be used, but even without input with proper LaTeX
syntax, AI will figure out the math and still generate proper LaTeX
formatted response.
Explain the math foundation of complex-time (kime) representation of repeated measurement spaciotemporal processes, where kappa = t * e^{i theta}, t is time, and theta is random distributed according to Phi(t), a kime-phase distribution. Use LaTeX typesetting.
The gen-AI response
to the above prompt is included
below.
The concept of complex-time or “kime” representation in the context of repeated measurement spaciotemporal processes is an advanced theoretical framework that aims to capture the dynamics of processes where both the magnitude and the phase of time could be influential. The variable \(\kappa\) is defined as \(\kappa = t e^{i \theta}\), where \(t\) is the real time, and \(\theta\) is a phase component that is randomly distributed according to a specific distribution \(\Phi(t)\). This section will delve into the mathematical foundation of this representation.
The kime, \(\kappa\), is defined by: \[ \kappa = t e^{i \theta} \] where \(t\) is the real time, and \(e^{i \theta}\) adds a complex exponential component. The exponential term \(e^{i \theta}\) introduces the concept of a phase into the …
Below are some more advanced examples of integrating AI-powered
medical applications into R
Markdown including
Medical Text Generation - Using AI to generate comprehensive medical information
Medical Code Generation - Creating and executing R code for medical data analysis
Medical Image Generation & Analysis - Visualizing medical concepts and analyzing medical images
Again, we utilize the OpenAI API interface for medical AI applications. We’ll explore various output formats, interactive elements, custom styling, parameterization, and advanced visualization techniques.
The configuration below builds upon the original example, adding more robust error handling, environment variable management, and logging capabilities.
# Load required packages
library(httr)
library(jsonlite)
library(knitr)
# Enhanced function to read .env file and set environmental variables
read_env_file <- function(file_path = ".env") {
# Check if file exists
if (!file.exists(file_path)) {
warning("Warning: .env file not found at ", file_path, ". Using default values.")
return(FALSE)
}
# Process each line
file_contents <- readLines(file_path, warn = FALSE)
for (line in file_contents) {
# Skip comments and empty lines
if (grepl("^\\s*#", line) || trimws(line) == "") {
next
}
# Find position of first equals sign
pos <- regexpr("=", line, fixed = TRUE)[1]
if (pos > 0) {
# Extract key and value
key <- trimws(substr(line, 1, pos - 1))
value <- trimws(substr(line, pos + 1, nchar(line)))
# Remove quotes if present
if ((substr(value, 1, 1) == "\"" && substr(value, nchar(value), nchar(value)) == "\"") ||
(substr(value, 1, 1) == "'" && substr(value, nchar(value), nchar(value)) == "'")) {
value <- substr(value, 2, nchar(value) - 1)
}
# Set the environment variable
assign_cmd <- paste0("Sys.setenv(", key, "='", value, "')")
eval(parse(text = assign_cmd))
}
}
return(TRUE)
}
# Create or use existing .env file
if (!file.exists(".env")) {
cat('azure_openai_endpoint="https://api.umgpt.umich.edu/azure-openai-api"
deployment_name="gpt-4"
api_version="2024-10-21"
api_key="YOUR_API_KEY"
organization_id="YOUR_ORG_ID"', file = ".env")
message("Created new .env file with placeholders. Please update with your actual credentials.")
}
# Read the .env file
env_loaded <- read_env_file()
# Mask sensitive data for display
mask_key <- function(key) {
if (is.null(key) || key == "" || key == "YOUR_API_KEY" || key == "YOUR_ORG_ID") {
return("[NOT SET]")
}
if (nchar(key) <= 4) {
return(paste0(rep("*", nchar(key)), collapse=""))
} else {
# Show first 1 and last 1 characters, mask everything else
first_chars <- substr(key, 1, 1)
last_chars <- substr(key, nchar(key), nchar(key))
middle_mask <- paste0(rep("*", nchar(key) - 2), collapse="")
return(paste0(first_chars, middle_mask, last_chars))
}
}
# Create a configuration table for better visualization
config_df <- data.frame(
Setting = c("Azure OpenAI Endpoint", "Deployment Name", "API Version", "API Key", "Organization ID"),
Value = c(
Sys.getenv("azure_openai_endpoint", ""),
Sys.getenv("deployment_name", ""),
Sys.getenv("api_version", ""),
mask_key(Sys.getenv("api_key", "")),
mask_key(Sys.getenv("organization_id", ""))
),
stringsAsFactors = FALSE
)
# Display configuration table
format_table(config_df, "API Configuration")
Setting | Value |
---|---|
Azure OpenAI Endpoint | https://api.umgpt.umich.edu/azure-openai-api |
Deployment Name | gpt-4 |
API Version | 2024-10-21 |
API Key | 4******************************3 |
Organization ID | 0****6 |
# # Set variables from environment or params
# azure_openai_endpoint <- Sys.getenv("azure_openai_endpoint", "")
# deployment_name <- Sys.getenv("deployment_name", params$model_type)
# api_version <- Sys.getenv("api_version", "2024-10-21")
# api_key <- Sys.getenv("api_key", "")
# organization_id <- Sys.getenv("organization_id", "")
# Set variables from environment or default values
azure_openai_endpoint <- Sys.getenv("azure_openai_endpoint", "")
deployment_name <- Sys.getenv("deployment_name", "gpt-4") # Use a default value instead of params$model_type
api_version <- Sys.getenv("api_version", "2024-10-21")
api_key <- Sys.getenv("api_key", "")
organization_id <- Sys.getenv("organization_id", "")
# Validate configuration
if (azure_openai_endpoint == "" || api_key == "" ||
api_key == "YOUR_API_KEY" || organization_id == "YOUR_ORG_ID") {
warning("API configuration incomplete. Please update the .env file with valid credentials.")
}
# Define the API URL
url <- paste0(
azure_openai_endpoint,
"/openai/deployments/", deployment_name,
"/chat/completions?api-version=", api_version
)
These functions provide a more structured approach to interacting with the OpenAI API, with improved error handling and response processing.
# Function to send a request to the API
send_ai_request <- function(prompt,
system_prompt = "You are a helpful assistant with expertise in medicine. Provide accurate, evidence-based information.",
temperature = params$temperature,
max_tokens = params$max_tokens,
api_url = url,
key = api_key,
org_id = organization_id) {
# Create the request body
body <- list(
messages = list(
list(role = "system", content = system_prompt),
list(role = "user", content = prompt)
),
max_tokens = max_tokens,
temperature = temperature
)
# Set up error handling
tryCatch({
# Send POST request
response <- POST(
api_url,
add_headers(
`api-key` = key,
`Content-Type` = "application/json",
`OpenAI-Organization` = org_id
),
body = toJSON(body, auto_unbox = TRUE),
timeout(60) # Set timeout to 60 seconds
)
# Check response status
if (status_code(response) == 200) {
content_data <- content(response, "parsed")
# Clean response if it contains LaTeX
clean_response <- gsub("\\\\", "\\",
content_data$choices[[1]]$message$content,
fixed = TRUE)
return(list(
success = TRUE,
content = clean_response,
raw_response = content_data,
status_code = status_code(response)
))
} else {
# Handle error response
error_content <- content(response, "parsed")
return(list(
success = FALSE,
error = paste("Error:", status_code(response)),
message = if (!is.null(error_content$error$message)) error_content$error$message else "Unknown error",
status_code = status_code(response),
raw_response = error_content
))
}
}, error = function(e) {
# Handle exceptions
return(list(
success = FALSE,
error = "Request failed",
message = e$message,
status_code = NA
))
})
}
# Function to render AI response with proper formatting
render_ai_response <- function(response, show_status = TRUE) {
if (response$success) {
if (show_status) {
cat('<div class="ai-response-status success">✓ Response generated successfully</div>')
}
# Determine if the response has LaTeX content
has_latex <- grepl("\\$|\\\\begin\\{|\\\\end\\{", response$content)
cat('<div class="ai-response">')
if (has_latex) {
# For LaTeX content, use special rendering
cat(response$content)
} else {
# For normal content
cat(response$content)
}
cat('</div>')
} else {
cat('<div class="ai-response-status error">✗ Error:', response$error, '</div>')
cat('<div class="ai-response-error">', response$message, '</div>')
}
}
# Add custom CSS for better formatting
cat('
<style>
.ai-response {
background-color: #f8f9fa;
border-left: 4px solid #4582ec;
padding: 15px;
margin-bottom: 20px;
border-radius: 5px;
}
.ai-response-status {
font-weight: bold;
margin-bottom: 5px;
}
.ai-response-status.success {
color: #28a745;
}
.ai-response-status.error {
color: #dc3545;
}
.ai-response-error {
background-color: #fff3f3;
border-left: 4px solid #dc3545;
padding: 10px;
margin-bottom: 20px;
border-radius: 5px;
}
</style>
')
First, we show how to use the OpenAI API to generate medical text content with different styles and formats.
Let’s start with a simple example asking for medical information about Amyotrophic lateral sclerosis (ALS).
# Define prompt
ALS_prompt <- "Provide a concise overview of ALS including definition,
risk factors, symptoms, diagnosis, and general management approaches."
# Send request to AI
ALS_response <- send_ai_request(ALS_prompt)
# Render the response
render_ai_response(ALS_response)
Amyotrophic Lateral Sclerosis (ALS), also known as Lou Gehrig’s disease, is a progressive neurodegenerative disease that affects nerve cells in the brain and the spinal cord. It leads to the degeneration and death of motor neurons, which control voluntary muscles. This results in increasing disability as the muscles of the body gradually weaken, leading to paralysis.
The exact cause of ALS is unknown, but several risk factors have been identified: - Age: Most commonly affects people between the ages of 40 and 70. - Gender: Slightly more common in men, though the gender difference decreases with age. - Genetics: 5-10% of cases are familial, meaning they are directly inherited. - Environmental Factors: Some studies suggest that exposure to certain toxins or a history of military service may increase risk.
We can use the document parameters to customize the prompt. This makes the document more flexible and reusable.
# Use the prompt from parameters
custom_prompt_response <- send_ai_request(params$custom_prompt)
# Render the response
render_ai_response(custom_prompt_response)
The concept of “complex time” (kime), represented as \(\kappa = t e^{i\theta}\), where \(t\) is time and \(\theta\) is a random variable, is somewhat unconventional in traditional physics and mathematics. It appears to be a theoretical construct rather than a standard topic covered in typical scientific curricula. The expression itself suggests a combination of real time with a complex exponential component where the angle \(\theta\) introduces a phase factor. Here’s a breakdown of the components and the possible interpretation:
Real Time Component (t): This is straightforward, representing the conventional measure of time.
Complex Exponential ( \(e^{i\theta}\) ): This component introduces a phase factor into the time variable. In complex numbers, \(e^{i\theta}\) represents a point on the unit circle in the complex plane at an angle \(\theta\) from the positive real axis.
For medical content, evidence-based information with proper citations is crucial. Let’s request content with citations.
# Define prompt for evidence-based content
evidence_prompt <- "Summarize the current evidence-based treatment options for
heart failure with reduced ejection fraction (HFrEF). Include key medications,
their mechanisms of action, and reference recent clinical guidelines."
# Modified system prompt to request citations
evidence_system_prompt <- "You are a medical expert providing evidence-based information.
Include references to clinical guidelines and key studies using numbered citations [1], [2], etc."
# Send request
evidence_response <- send_ai_request(
prompt = evidence_prompt,
system_prompt = evidence_system_prompt,
max_tokens = 500
)
# Render the response
render_ai_response(evidence_response)
Heart failure with reduced ejection fraction (HFrEF) is characterized by a left ventricular ejection fraction of 40% or less and is associated with significant morbidity and mortality. The management of HFrEF primarily involves pharmacologic therapies aimed at improving symptoms, reducing hospitalizations, and decreasing mortality. According to the most recent clinical guidelines and evidence from key studies, the cornerstone treatments for HFrEF include:
Angiotensin-Converting Enzyme Inhibitors (ACEIs) or Angiotensin II Receptor Blockers (ARBs): These medications block the renin-angiotensin-aldosterone system (RAAS), which plays a critical role in the pathophysiology of heart failure. ACEIs and ARBs have been shown to reduce mortality and morbidity in patients with HFrEF [1]. Angiotensin receptor-neprilysin inhibitors (ARNIs), which combine the effects of ARBs and neprilysin inhibition, are also recommended as they have been shown to be more effective than ACEIs alone in reducing cardiovascular death and heart failure hospitalizations [2].
Beta-Blockers: These drugs reduce myocardial oxygen demand and counteract the detrimental effects of chronic sympathetic nervous system activation in heart failure. Beta-blockers have been demonstrated to decrease mortality and hospitalization rates in patients with HFrEF [3].
Mineralocorticoid Receptor Antagonists (MRAs): MRAs, such as spironolactone and eplerenone, block the effects of aldosterone, which can cause sodium retention, myocardial fibrosis, and vascular damage. These agents reduce both morbidity and mortality in patients with HFrEF [4].
Diuretics: While diuretics do not directly improve survival, they are effective in controlling symptoms related to fluid overload, such as dyspnea and peripheral edema. Loop diuretics are the most commonly used, particularly in patients with symptomatic heart failure [5].
SGLT2 Inhibitors: Originally developed for the treatment of diabetes, these medications have recently been shown to significantly reduce the risk of cardiovascular death and hospitalization for heart failure in patients with HFrEF, regardless of the presence of diabetes [6].
Ivabradine: This medication is indicated for patients who are symptomatic (NYHA class II-III) despite
R
Markdown allows creating interactive interfaces. Let’s
use a tabset to compare different medical conditions.
hypertension_prompt <- "Explain the current guidelines for hypertension diagnosis,
classification, and management. Include target blood pressure goals for different patient populations."
hypertension_response <- send_ai_request(hypertension_prompt, max_tokens = 300)
render_ai_response(hypertension_response, show_status = FALSE)
As of my last update, the guidelines for the diagnosis, classification, and management of hypertension primarily follow those set forth by the American College of Cardiology (ACC) and the American Heart Association (AHA) in their 2017 guidelines. It’s important to note that guidelines can vary slightly between different countries and organizations, but the ACC/AHA guidelines are widely recognized.
Hypertension is diagnosed based on blood pressure readings. According to the 2017 ACC/AHA guidelines:
Blood pressure should be measured using a validated device, and proper technique must be ensured. Diagnosis should ideally be based on the average of two or more careful readings at two or more visits.
Management strategies are generally categorized into lifestyle modifications and pharmacological treatment.
Lifestyle Modifications include: - Dietary changes (e.g., reduced salt intake, DASH diet) - Enhanced physicaldementia_prompt <- "Describe the step-wise approach to dementia management according to
current guidelines."
dementia_response <- send_ai_request(dementia_prompt, max_tokens = 300)
render_ai_response(dementia_response, show_status = FALSE)
The management of dementia is complex and requires a comprehensive, multidisciplinary approach. The following is a general step-wise approach based on current guidelines such as those from the Alzheimer’s Association, the American Academy of Neurology, and the National Institute on Aging. It is important to note that management should be individualized based on the patient’s needs, type of dementia, stage of the disease, and comorbid conditions.
Migraine is a complex neurological disorder characterized by recurrent episodes of headache along with symptoms such as nausea, vomiting, photophobia (sensitivity to light), and phonophobia (sensitivity to sound). The pathophysiology of migraine involves multiple neural pathways and neurotransmitters, which contribute to the migraine phases and symptoms.
1. Trigeminovascular System Activation: The initiation of a migraine is often linked to the activation of the trigeminovascular system. This system includes the trigeminal nerve and its connections to the blood vessels in the meninges (the protective coverings of the brain and spinal cord). Activation leads to the release of vasoactive peptides, including calcitonin gene-related peptide (CGRP) and substance P, which cause inflammation and dilation of cerebral blood vessels.
2. Cortical Spreading Depression (CSD): This refers to a wave of neuronal and glial depolarization that slowly spreads across the cortex. CSD is believed to be the physiological basis behind migraine aura—the visual, sensory, or motor symptoms that approximately 25-30% of migraineurs experience before the headache phase.
3. Central Sensitization: Prolonged migraine attacks can lead to central sensitization, where the central nervous system becomes more sensitive to stimuli. This can explain the allodynia (pain from stimuli which do not normally provoke pain) experienced during migraines.
**4. Neurotransmitter:::
AI can help generate structured content like comparison tables. Let’s create a comparison of antibiotics.
comparison_prompt <- "Create a comparison table of common antibiotics used to treat
respiratory infections. Include drug names, class, spectrum, common indications,
and important adverse effects. Format as a markdown table."
comparison_response <- send_ai_request(comparison_prompt, max_tokens = 600)
render_ai_response(comparison_response)
Below is a comparison table of common antibiotics used to treat respiratory infections. This table includes drug names, class, spectrum, common indications, and important adverse effects.
Drug Name | Class | Spectrum | Common Indications | Important Adverse Effects |
---|---|---|---|---|
Amoxicillin | Penicillin | Broad | Streptococcal pharyngitis, pneumonia | Diarrhea, rash, allergic reactions |
Azithromycin | Macrolide | Broad | Bronchitis, pneumonia, sinusitis | Diarrhea, QT prolongation, hearing loss |
Doxycycline | Tetracycline | Broad | Pneumonia, bronchitis, sinusitis | Photosensitivity, teeth discoloration |
Ceftriaxone | Cephalosporin | Broad | Pneumonia, acute bacterial exacerbations | Hypersensitivity reactions, diarrhea |
Levofloxacin | Fluoroquinolone | Broad | Pneumonia, bronchitis, sinusitis | Tendon rupture, QT prolongation, diarrhea |
Erythromycin | Macrolide | Broad | Bronchitis, pertussis, pneumonia | GI upset, QT prolongation, hepatotoxicity |
Amoxicillin/Clavulanate | Penicillin | Broad | Sinusitis, otitis media, pneumonia | Diarrhea, rash, allergic reactions |
Clarithromycin | Macrolide | Broad | Pneumonia, bronchitis, sinusitis | Diarrhea, taste disturbances, hepatotoxicity |
Piperacillin/Tazobactam | Penicillin | Broad | Hospital-acquired pneumonia | Hypersensitivity reactions, diarrhea |
Ciprofloxacin | Fluoroquinolone | Broad | Pneumonia, bronchitis, sinusitis | Tendon rupture, QT prolongation, diarrhea |
Let’s generate a medical decision-making algorithm for a common condition.
algorithm_prompt <- "Create a step-by-step diagnostic algorithm for evaluating acute chest pain in the emergency department. Include key decision points, diagnostic tests, and potential diagnoses."
algorithm_response <- send_ai_request(algorithm_prompt, max_tokens = 400)
render_ai_response(algorithm_response)
Step-by-Step Diagnostic Algorithm for Evaluating Acute Chest Pain in the Emergency Department
Now let’s visualize this algorithm using DiagrammeR
.
We’ll use a mermaid diagram:
# Generate a mermaid diagram from the algorithm
mermaid_prompt <- "Convert the diagnostic algorithm for chest pain evaluation into a mermaid
flowchart diagram. Use proper mermaid syntax. Keep it concise but comprehensive."
mermaid_response <- send_ai_request(mermaid_prompt, max_tokens = 600)
# Extract the mermaid code
if (mermaid_response$success) {
# Extract code between ```mermaid and ``` if present
mermaid_code <- gsub(".*```mermaid\\s*\\n(.+?)\\n\\s*```.*", "\\1",
mermaid_response$content, perl = TRUE)
# If extraction failed, use the whole response
if (mermaid_code == mermaid_response$content) {
mermaid_code <- mermaid_response$content
}
# Display the diagram
DiagrammeR::mermaid(mermaid_code)
} else {
cat("Failed to generate mermaid diagram")
}
AI can assist in generating R
code for medical data
analysis. This section demonstrates various code generation
scenarios.
Let’s generate and execute code for analyzing a sample medical dataset.
# Generate synthetic patient data
set.seed(123)
n <- 100
patient_data <- data.frame(
PatientID = paste0("P", 1:n),
Age = rnorm(n, mean = 55, sd = 15),
Gender = sample(c("Male", "Female"), n, replace = TRUE, prob = c(0.48, 0.52)),
BMI = rnorm(n, mean = 27, sd = 5),
SBP = rnorm(n, mean = 130, sd = 20),
DBP = rnorm(n, mean = 85, sd = 10),
A1C = rnorm(n, mean = 7, sd = 1.5),
LDL = rnorm(n, mean = 120, sd = 30),
HDL = rnorm(n, mean = 50, sd = 15),
Triglycerides = rnorm(n, mean = 150, sd = 70),
SmokingStatus = sample(c("Never", "Former", "Current"), n, replace = TRUE, prob = c(0.6, 0.3, 0.1)),
CVD = rbinom(n, 1, prob = 0.25),
stringsAsFactors = FALSE
)
# Clean up the data
patient_data$Age <- round(pmax(18, pmin(95, patient_data$Age)))
patient_data$BMI <- round(pmax(15, pmin(50, patient_data$BMI)), 1)
patient_data$SBP <- round(pmax(90, pmin(200, patient_data$SBP)))
patient_data$DBP <- round(pmax(50, pmin(120, patient_data$DBP)))
patient_data$A1C <- round(pmax(4, pmin(14, patient_data$A1C)), 1)
patient_data$LDL <- round(pmax(40, pmin(250, patient_data$LDL)))
patient_data$HDL <- round(pmax(20, pmin(100, patient_data$HDL)))
patient_data$Triglycerides <- round(pmax(50, pmin(500, patient_data$Triglycerides)))
# Show a sample of the data
head(patient_data) %>% format_table("Sample Patient Data")
PatientID | Age | Gender | BMI | SBP | DBP | A1C | LDL | HDL | Triglycerides | SmokingStatus | CVD |
---|---|---|---|---|---|---|---|---|---|---|---|
P1 | 47 | Female | 30.9 | 122 | 95 | 9.1 | 145 | 21 | 258 | Former | 0 |
P2 | 52 | Male | 30.8 | 119 | 65 | 8.6 | 97 | 52 | 142 | Never | 1 |
P3 | 78 | Male | 28.7 | 123 | 81 | 7.7 | 153 | 59 | 186 | Never | 0 |
P4 | 56 | Female | 22.0 | 132 | 86 | 8.1 | 127 | 28 | 165 | Current | 0 |
P5 | 57 | Female | 26.4 | 162 | 76 | 8.4 | 170 | 57 | 137 | Former | 0 |
P6 | 81 | Male | 25.6 | 128 | 88 | 4.0 | 76 | 38 | 142 | Former | 0 |
Now, let’s ask the AI to generate code to perform exploratory data analysis.
eda_prompt <- "Generate R code to perform exploratory data analysis on the patient_data
dataframe. Include summary statistics, visualizations of age and BMI distributions,
correlation analysis between numeric variables, and comparison of lab values by gender
and cardiovascular disease status. Use ggplot2 for visualizations."
eda_code_response <- send_ai_request(
prompt = eda_prompt,
system_prompt = "You are an R programming expert. Generate only executable R code without explanations.
The code should be well-commented and use modern tidyverse/ggplot2 approaches.",
max_tokens = 1000
)
# Display the generated code
if (eda_code_response$success) {
cat("```r\n")
cat(eda_code_response$content)
cat("\n```\n")
# Create a safer execution environment
tryCatch({
# We need to make sure the code references correct column names
# Let's do a preprocessing step to map AI variable names to our actual data
code_to_execute <- eda_code_response$content
# Replace likely mismatched variable names
code_to_execute <- gsub("cardio", "CVD", code_to_execute)
# Fix other potential variables
code_to_execute <- gsub("lab_value", "Value", code_to_execute)
# Execute the modified code
eval(parse(text = code_to_execute))
}, error = function(e) {
cat("Error executing code:", e$message, "\n\n")
cat("This is likely due to a mismatch between the variable names in the generated code and your dataset.\n")
cat("You may need to manually adapt the code to work with your specific data structure.\n")
})
} else {
cat("Failed to generate code:", eda_code_response$message)
}
```r
# Load the necessary libraries
library(tidyverse)
# Load example data (assuming it's already available in your environment)
# patient_data <- read.csv("path_to_your_data.csv")
# Basic summary statistics for each column
summary(patient_data)
# Histogram of Age Distribution
ggplot(patient_data, aes(x = age)) +
geom_histogram(bins = 30, fill = "blue", color = "white") +
ggtitle("Distribution of Age") +
xlab("Age") +
ylab("Frequency")
# Histogram of BMI Distribution
ggplot(patient_data, aes(x = bmi)) +
geom_histogram(bins = 30, fill = "green", color = "white") +
ggtitle("Distribution of BMI") +
xlab("BMI") +
ylab("Frequency")
# Correlation matrix of numeric variables
numeric_data <- select_if(patient_data, is.numeric)
correlation_matrix <- cor(numeric_data)
print(correlation_matrix)
# Visualizing correlations using ggplot2
library(corrplot)
corrplot(correlation_matrix, method = "circle")
# Comparing lab values by gender
lab_values_by_gender <- patient_data %>%
select(gender, chol, gluc, creat) %>%
pivot_longer(cols = c(chol, gluc, creat), names_to = "lab_test", values_to = "value")
ggplot(lab_values_by_gender, aes(x = gender, y = value, fill = gender)) +
geom_boxplot() +
facet_wrap(~lab_test, scales = "free_y") +
ggtitle("Lab Values by Gender") +
xlab("Gender") +
ylab("Value")
# Comparing lab values by cardiovascular disease status
lab_values_by_cvd <- patient_data %>%
select(cardio, chol, gluc, creat) %>%
pivot_longer(cols = c(chol, gluc, creat), names_to = "lab_test", values_to = "value")
ggplot(lab_values_by_cvd, aes(x = factor(cardio), y = value, fill = factor(cardio))) +
geom_boxplot() +
facet_wrap(~lab_test, scales = "free_y") +
ggtitle("Lab Values by Cardiovascular Disease Status") +
xlab("Cardiovascular Disease (0 = No, 1 = Yes)") +
ylab("Value")
Error executing code: attempt to use zero-length variable name
This is likely due to a mismatch between the variable names in the generated code and your dataset.
You may need to manually adapt the code to work with your specific data structure.
Note that AI-generated code often needs adaptation to work with specific datasets.
For production use, we might consider creating a more controlled workflow where
we have predefined code templates with placeholders, and the AI merely fills in
specific portions, rather than generating entire code blocks from scratch.
<pre><code>
# First, let's create a data dictionary to help the AI understand our data
data_dict <- paste(
"Patient data structure:",
"- PatientID: Patient identifier",
"- Age: Patient age in years",
"- Gender: 'Male' or 'Female'",
"- BMI: Body Mass Index",
"- SBP: Systolic Blood Pressure in mmHg",
"- DBP: Diastolic Blood Pressure in mmHg",
"- A1C: Hemoglobin A1C percentage",
"- LDL: Low-density lipoprotein cholesterol in mg/dL",
"- HDL: High-density lipoprotein cholesterol in mg/dL",
"- Triglycerides: Triglyceride levels in mg/dL",
"- SmokingStatus: 'Never', 'Former', or 'Current'",
"- CVD: Cardiovascular disease status (1 = present, 0 = absent)",
sep = "\n"
)
# Modify the prompt to include the data dictionary
eda_prompt <- paste(
data_dict,
"\n\nGenerate R code to perform exploratory data analysis on the patient_data dataframe. Include:",
"1. Summary statistics for all variables",
"2. Visualizations of age and BMI distributions",
"3. Correlation analysis between numeric variables",
"4. Comparison of lab values by gender and cardiovascular disease status (CVD)",
"Use ggplot2 for visualizations and ensure all variable names exactly match those in the data dictionary.",
sep = "\n"
)
</code></pre>
## Risk Score Calculator
Let's generate code for a *cardiovascular risk calculator*.
```` r
risk_calc_prompt <- "Generate R code for a function to calculate cardiovascular risk based
on patient age, gender, smoking status, SBP, HDL, and LDL. Use a simple model where risk increases
with age, SBP, LDL and smoking, and decreases with HDL. Include a plotting function to visualize
risk distribution across the dataset."
risk_calc_response <- send_ai_request(
prompt = risk_calc_prompt,
system_prompt = "You are an R programming expert. Generate only executable R code without explanations.
The code should be well-commented and use modern tidyverse/ggplot2 approaches.",
max_tokens = 400
)
# Display and execute the generated code
if (risk_calc_response$success) {
cat("```r\n")
cat(risk_calc_response$content)
cat("\n```\n")
# More robust execution with error handling
tryCatch({
# Check for common code issues before executing
if (grepl("\\`\\`\\`r|\\`\\`\\`", risk_calc_response$content)) {
# Remove markdown code block markers if present
code_to_execute <- gsub("\\`\\`\\`r|\\`\\`\\`", "", risk_calc_response$content)
} else {
code_to_execute <- risk_calc_response$content
}
# Execute the code
eval(parse(text = code_to_execute))
}, error = function(e) {
cat("Error executing code:", e$message, "\n")
cat("Consider implementing the function manually based on the AI suggestion.\n")
})
} else {
cat("Failed to generate code:", risk_calc_response$message)
}
```R
# Load necessary libraries
library(tidyverse)
# Define the function to calculate cardiovascular risk
calculate_risk <- function(age, gender, smoker, sbp, hdl, ldl) {
# Initialize base risk
risk <- 0
# Increase risk based on age, SBP, and LDL
risk <- risk + (age - 50) * 0.05 + (sbp - 120) * 0.02 + (ldl - 100) * 0.03
# Decrease risk based on HDL
risk <- risk - (hdl - 40) * 0.02
# Additional risk for smokers
if (smoker == "Yes") {
risk <- risk + 20
}
# Adjust risk based on gender
if (gender == "Female") {
risk <- risk * 0.8
}
# Ensure risk is not negative
max(risk, 0)
}
# Create function to add cardiovascular risk to a dataframe
add_cardiovascular_risk <- function(df) {
df %>%
mutate(cardio_risk = mapply(calculate_risk, age, gender, smoker, sbp, hdl, ldl))
}
# Function to plot risk distribution
plot_risk_distribution <- function(df) {
df %>%
ggplot(aes(x = cardio_risk, fill = gender)) +
geom_histogram(bins = 30, alpha = 0.6) +
labs(title = "Distribution of Cardiovascular Risk", x = "Cardiovascular Risk", y = "Frequency") +
theme_minimal()
}
# Example usage with a hypothetical dataset
# Assuming the dataset 'patient_data' has columns: age, gender, smoker, sbp, hdl, ldl
# patient_data <- data.frame(
# age = c
Error executing code: object ‘R’ not found Consider implementing the function manually based on the AI suggestion.
Let’s create a simple RShiny
component within the
R
Markdown document itself to explore the patient data
(this is note run during knitting!).
# Define a simple Shiny application
shinyApp(
ui = fluidPage(
titlePanel("Patient Data Explorer"),
sidebarLayout(
sidebarPanel(
selectInput("x_var", "X Variable:",
choices = c("Age", "BMI", "SBP", "DBP", "A1C", "LDL", "HDL", "Triglycerides")),
selectInput("y_var", "Y Variable:",
choices = c("BMI", "SBP", "DBP", "A1C", "LDL", "HDL", "Triglycerides", "Age"),
selected = "BMI"),
checkboxGroupInput("group_var", "Group By:",
choices = c("Gender", "SmokingStatus", "CVD"),
selected = "Gender"),
sliderInput("point_size", "Point Size:", min = 1, max = 5, value = 2, step = 0.5),
sliderInput("alpha", "Point Transparency:", min = 0.1, max = 1, value = 0.7, step = 0.1)
),
mainPanel(
plotlyOutput("scatter_plot"),
dataTableOutput("summary_table")
)
)
),
server = function(input, output) {
output$scatter_plot <- renderPlotly({
# Set the grouping variable
if (length(input$group_var) == 0) {
p <- ggplot(patient_data, aes_string(x = input$x_var, y = input$y_var))
} else {
# Create a new grouping variable that combines all selected factors
group_data <- patient_data
group_data$Group <- apply(group_data[, input$group_var, drop = FALSE], 1,
function(x) paste(input$group_var, x, sep = ": ", collapse = ", "))
p <- ggplot(group_data, aes_string(x = input$x_var, y = input$y_var, color = "Group"))
}
# Add the scatter plot
p <- p + geom_point(size = input$point_size, alpha = input$alpha) +
labs(title = paste(input$y_var, "vs", input$x_var),
subtitle = "Interactive Patient Data Explorer") +
theme_minimal()
# Convert to plotly for interaction
ggplotly(p)
})
output$summary_table <- renderDataTable({
# Create summary statistics for selected variables
if (length(input$group_var) == 0) {
summary_df <- data.frame(
Variable = c(input$x_var, input$y_var),
Mean = c(mean(patient_data[[input$x_var]]), mean(patient_data[[input$y_var]])),
SD = c(sd(patient_data[[input$x_var]]), sd(patient_data[[input$y_var]])),
Median = c(median(patient_data[[input$x_var]]), median(patient_data[[input$y_var]])),
Min = c(min(patient_data[[input$x_var]]), min(patient_data[[input$y_var]])),
Max = c(max(patient_data[[input$x_var]]), max(patient_data[[input$y_var]]))
)
} else {
# Create summary stats grouped by the first grouping variable
group_var <- input$group_var[1]
summary_data <- patient_data %>%
group_by(!!sym(group_var)) %>%
summarize(
Mean_X = mean(!!sym(input$x_var)),
SD_X = sd(!!sym(input$x_var)),
Mean_Y = mean(!!sym(input$y_var)),
SD_Y = sd(!!sym(input$y_var)),
Count = n()
)
summary_df <- summary_data
}
# Return the table
datatable(summary_df, options = list(pageLength = 5))
})
},
options = list(height = 600)
)
This section demonstrates how to work with medical images in
R
Markdown.
First, we’ll generate descriptions of medical diagrams, then visualize them using different methods.
diagram_prompt <- "Describe a detailed diagram of the cardiac conduction system,
including the sinoatrial node, atrioventricular node, bundle of His, bundle branches,
and Purkinje fibers. Explain the pathway of electrical conduction."
diagram_response <- send_ai_request(diagram_prompt, max_tokens = 400)
render_ai_response(diagram_response)
The cardiac conduction system is a network of nodes, cells, and signals that work together to control the heart rate. This system generates electrical impulses and conducts them throughout the heart, causing it to contract and pump blood. Below is a detailed description of the components of the cardiac conduction system and the pathway of electrical conduction:
Let’s create a simple visualization of human anatomy using basic
R
plotting.
# Heart chambers visualization
heart_data <- data.frame(
x = c(0, 1, 1, 0, 0, -1, -1, 0), # Simplified heart outline
y = c(0, 1, -1, -2, 0, -1, 1, 0),
chamber = rep(c("Right Atrium", "Right Ventricle", "Left Atrium", "Left Ventricle"), each = 2)
)
# Using ggplot2 to create a simplified heart diagram
ggplot() +
# Right Atrium
annotate("polygon", x = c(-0.5, -0.5, 0, 0), y = c(0, 1, 1, 0), fill = "skyblue", alpha = 0.7) +
annotate("text", x = -0.25, y = 0.5, label = "RA") +
# Right Ventricle
annotate("polygon", x = c(-0.5, -0.5, 0, 0), y = c(0, -1, -1, 0), fill = "royalblue", alpha = 0.7) +
annotate("text", x = -0.25, y = -0.5, label = "RV") +
# Left Atrium
annotate("polygon", x = c(0, 0, 0.5, 0.5), y = c(0, 1, 1, 0), fill = "pink", alpha = 0.7) +
annotate("text", x = 0.25, y = 0.5, label = "LA") +
# Left Ventricle
annotate("polygon", x = c(0, 0, 0.5, 0.5), y = c(0, -1, -1, 0), fill = "red", alpha = 0.7) +
annotate("text", x = 0.25, y = -0.5, label = "LV") +
# Add conduction system components
annotate("point", x = -0.3, y = 0.8, color = "yellow", size = 3) +
annotate("text", x = -0.3, y = 0.9, label = "SA Node", hjust = 0.5) +
annotate("point", x = 0, y = 0, color = "yellow", size = 3) +
annotate("text", x = 0, y = 0.1, label = "AV Node", hjust = 0.5) +
# Bundle of His and branches
annotate("segment", x = 0, y = 0, xend = 0, yend = -0.3, color = "orange", size = 1) +
annotate("segment", x = 0, y = -0.3, xend = -0.2, yend = -0.5, color = "orange", size = 1) +
annotate("segment", x = 0, y = -0.3, xend = 0.2, yend = -0.5, color = "orange", size = 1) +
# Purkinje fibers
annotate("segment", x = -0.2, y = -0.5, xend = -0.3, yend = -0.8, color = "orange", size = 0.5) +
annotate("segment", x = -0.2, y = -0.5, xend = -0.4, yend = -0.7, color = "orange", size = 0.5) +
annotate("segment", x = 0.2, y = -0.5, xend = 0.3, yend = -0.8, color = "orange", size = 0.5) +
annotate("segment", x = 0.2, y = -0.5, xend = 0.4, yend = -0.7, color = "orange", size = 0.5) +
# Formatting
labs(title = "Simplified Cardiac Conduction System",
subtitle = "Showing major components and pathways") +
theme_void() +
theme(
plot.title = element_text(hjust = 0.5, size = 16),
plot.subtitle = element_text(hjust = 0.5, size = 12),
legend.position = "none"
) +
coord_fixed(ratio = 1)
# Add legend/explanation
legend_data <- data.frame(
component = c("Sinoatrial (SA) Node", "Atrioventricular (AV) Node",
"Bundle of His & Branches", "Purkinje Fibers"),
color = c("yellow", "yellow", "orange", "orange"),
description = c("Primary pacemaker", "Delays signal to ventricles",
"Rapid conduction pathway", "Terminal conduction network")
)
kableExtra::kbl(legend_data, caption = "Cardiac Conduction System Components") %>%
kableExtra::kable_styling(full_width = FALSE) %>%
kableExtra::column_spec(2, color = legend_data$color, background = "white")
component | color | description |
---|---|---|
Sinoatrial (SA) Node | yellow | Primary pacemaker |
Atrioventricular (AV) Node | yellow | Delays signal to ventricles |
Bundle of His & Branches | orange | Rapid conduction pathway |
Purkinje Fibers | orange | Terminal conduction network |
This example demonstrates how to analyze medical images. We’ll use
the EBImage
package for a simplified example of image
processing that might be applied to medical images.
# Load required packages for image processing
library(EBImage)
# Create a sample "medical image" (simulating an X-ray)
width <- 300
height <- 300
chest_xray <- matrix(0.92, height, width)
# Create a more distinct simulated nodule
chest_xray[110:125, 80:95] <- 0.5 # Make nodule darker/more distinct
# Add "ribs" and "spine" with boundary checking
for (i in 1:10) {
offset <- 20 + i * 20
row_start <- min(height, max(1, 100 + offset))
row_end <- min(height, max(1, 110 + offset))
if (row_start > height || row_end < 1) next
# Left ribs
col_left_start <- 50
col_left_end <- min(width, 150)
left_cells <- (row_end - row_start + 1) * (col_left_end - col_left_start + 1)
if (left_cells > 0) {
chest_xray[row_start:row_end, col_left_start:col_left_end] <-
0.7 + rnorm(left_cells, 0, 0.02)
}
# Right ribs
col_right_start <- min(width, 150)
col_right_end <- min(width, 250)
right_cells <- (row_end - row_start + 1) * (col_right_end - col_right_start + 1)
if (right_cells > 0) {
chest_xray[row_start:row_end, col_right_start:col_right_end] <-
0.7 + rnorm(right_cells, 0, 0.02)
}
}
# Add spine
spine_start <- 100
spine_end <- min(height, 250)
spine_left <- 145
spine_right <- min(width, 155)
spine_cells <- (spine_end - spine_start + 1) * (spine_right - spine_left + 1)
if (spine_cells > 0) {
chest_xray[spine_start:spine_end, spine_left:spine_right] <- 0.5 + rnorm(spine_cells, 0, 0.02)
}
# Convert to EBImage object
xray_img <- EBImage::as.Image(chest_xray)
# Display the original simulated X-ray
display(xray_img, method = "raster", all = TRUE, title = "Simulated Chest X-ray")
# Simplified and more robust image analysis approach
# 1. Enhance contrast
xray_enhanced <- EBImage::normalize(xray_img)
# 2. Apply thresholding to segment potential abnormalities
threshold <- 0.6 # Adjusted threshold
xray_threshold <- xray_enhanced < threshold
# 3. Clean up the segmentation
xray_cleaned <- EBImage::opening(xray_threshold, EBImage::makeBrush(3, shape = "disc"))
# 4. Label connected components
xray_labeled <- EBImage::bwlabel(xray_cleaned)
# Display the processed images without trying to compute features
par(mfrow = c(2, 2), mar = c(1, 1, 2, 1))
display(xray_img, method = "raster", title = "Original", margin = 0)
display(xray_enhanced, method = "raster", title = "Enhanced", margin = 0)
display(xray_threshold, method = "raster", title = "Thresholded", margin = 0)
display(EBImage::colorLabels(xray_labeled), method = "raster",
title = "Detected Components", margin = 0)
# Restore display settings
par(mfrow = c(1, 1), mar = c(5, 4, 4, 2) + 0.1)
# Try to compute features with safer approach
tryCatch({
# Compute just shape features
xray_features <- EBImage::computeFeatures.shape(xray_labeled)
# Check if we got any components
if (nrow(xray_features) > 0) {
# Filter components by size - use a smaller threshold to detect the nodule
large_components <- xray_features[,"s.area"] > 20
if (sum(large_components) > 0) {
# Create a data frame with detected regions - only use features we know exist
findings <- data.frame(
Region_ID = which(large_components),
Area = xray_features[large_components, "s.area"],
Perimeter = xray_features[large_components, "s.perimeter"]
)
# Add circularity if it exists
if ("s.circularity" %in% colnames(xray_features)) {
findings$Circularity <- xray_features[large_components, "s.circularity"]
}
# Add position information if available
if (all(c("m.cx", "m.cy") %in% colnames(xray_features))) {
findings$X_Center <- xray_features[large_components, "m.cx"]
findings$Y_Center <- xray_features[large_components, "m.cy"]
}
# Display findings table
knitr::kable(findings, caption = "Detected Regions of Interest")
} else {
cat("No significant regions detected after size filtering.")
}
} else {
cat("No regions detected during segmentation.")
}
}, error = function(e) {
cat("Error in feature computation:", e$message, "\n")
cat("This is likely due to issues with the segmentation process.\n")
})
Region_ID | Area | Perimeter | |
---|---|---|---|
1 | 1 | 741 | 244 |
2 | 2 | 316 | 104 |
3 | 3 | 28 | 18 |
4 | 4 | 182 | 73 |
5 | 5 | 6996 | 1982 |
6 | 6 | 538 | 174 |
8 | 8 | 537 | 211 |
9 | 9 | 385 | 151 |
10 | 10 | 467 | 151 |
11 | 11 | 256 | 60 |
12 | 12 | 307 | 97 |
14 | 14 | 1429 | 477 |
16 | 16 | 131 | 63 |
19 | 19 | 33 | 19 |
20 | 20 | 828 | 315 |
21 | 21 | 724 | 239 |
22 | 22 | 627 | 212 |
23 | 23 | 274 | 92 |
25 | 25 | 333 | 119 |
28 | 28 | 196 | 80 |
29 | 29 | 213 | 82 |
We can also create interactive 3D visualizations of medical data
using plotly
.
# Create a simple 3D model of a heart (simplified)
# In a real scenario, you would use actual medical 3D data
# Generate points for a heart-like shape
t <- seq(0, 2*pi, length.out = 100)
x <- 16 * sin(t)^3
y <- 13 * cos(t) - 5 * cos(2*t) - 2 * cos(3*t) - cos(4*t)
z <- rep(0, length(t))
# Create multiple layers to give depth
heart_3d <- data.frame()
for (depth in seq(-5, 5, by = 0.5)) {
scale_factor <- 1 - abs(depth/7)
layer <- data.frame(
x = x * scale_factor,
y = y * scale_factor,
z = depth,
layer = as.factor(depth)
)
heart_3d <- rbind(heart_3d, layer)
}
# Create a 3D scatter plot with plotly
library(plotly)
plot_ly(heart_3d, x = ~x, y = ~y, z = ~z,
color = ~layer, colors = colorRampPalette(c("darkred", "red", "pink"))(length(unique(heart_3d$layer)))) %>%
add_markers(size = 3, opacity = 0.7) %>%
layout(
title = "Interactive 3D Heart Model",
scene = list(
xaxis = list(title = ""),
yaxis = list(title = ""),
zaxis = list(title = ""),
camera = list(eye = list(x = 1.5, y = -1.5, z = 1.5))
)
)
R
Markdown supports various document formats. Here we’ll
demonstrate how to create templates for different medical document
types.
An example of generating a simple medical case report.
case_report_template <- '
# Medical Case Report Template
## Patient Information
- *Age:* [Patient Age]
- *Gender:* [Patient Gender]
- *Main Complaint:* [Chief Complaint]
## Clinical Findings
[Detailed description of relevant findings from history and physical examination]
## Timeline
[Chronological timeline of patient symptoms, treatments, and outcomes]
## Diagnostic Assessment
[Summary of diagnostic methods, reasoning, and results]
## Therapeutic Interventions
[Description of treatments provided]
## Follow-up and Outcomes
[Outcome measures and follow-up results]
## Discussion
[Summary of case importance, relevant literature, and lessons learned]
## Patient Perspective
[Optional section with the patient\'s perspective on their care]
## Informed Consent
[Statement regarding informed consent obtained from the patient]
## References
[Numbered list of references]
'
cat(case_report_template)
[Detailed description of relevant findings from history and physical examination]
[Chronological timeline of patient symptoms, treatments, and outcomes]
[Summary of diagnostic methods, reasoning, and results]
[Description of treatments provided]
[Outcome measures and follow-up results]
[Summary of case importance, relevant literature, and lessons learned]
[Optional section with the patient’s perspective on their care]
[Statement regarding informed consent obtained from the patient]
[Numbered list of references]
Here is another example of a clinical trial protocol.
clinical_trial_template <- '
# Clinical Trial Protocol Template
## 1. General Information
- *Protocol Title:* [Full protocol title]
- *Protocol ID:* [Unique identifier]
- *Version:* [Version number and date]
- *Principal Investigator:* [Name and contact]
- *Sponsor:* [Name of sponsor]
## 2. Background and Rationale
[Scientific background and explanation of rationale]
## 3. Objectives
### 3.1 Primary Objective
[Clear statement of primary objective]
### 3.2 Secondary Objectives
[List of secondary objectives]
## 4. Study Design
[Description of trial design including type, allocation ratio, framework]
## 5. Methodology
### 5.1 Participants
[Eligibility criteria, sources, recruitment methods]
### 5.2 Interventions
[Detailed description of interventions for each group]
### 5.3 Outcomes
[Primary and secondary outcome measures]
### 5.4 Sample Size
[Estimated number of participants needed and basis for calculation]
### 5.5 Randomization
[Method used to generate allocation sequence]
## 6. Data Collection and Management
[Description of methods for data collection and management]
## 7. Statistical Analysis
[Statistical methods for analyzing primary and secondary outcomes]
## 8. Ethics and Dissemination
[Ethics approval, consent procedures, confidentiality, access to data]
## 9. References
[List of references]
'
cat(clinical_trial_template)
[Scientific background and explanation of rationale]
[Clear statement of primary objective]
[List of secondary objectives]
[Description of trial design including type, allocation ratio, framework]
[Eligibility criteria, sources, recruitment methods]
[Detailed description of interventions for each group]
[Primary and secondary outcome measures]
[Estimated number of participants needed and basis for calculation]
[Method used to generate allocation sequence]
[Description of methods for data collection and management]
[Statistical methods for analyzing primary and secondary outcomes]
[Ethics approval, consent procedures, confidentiality, access to data]
[List of references]
R
Markdown FeaturesWe can also showcase more advanced features ofR
Markdown
that can enhance medical documents.
You can use parameters to create dynamic reports that change based on input values.
# Generate a parameterized diagnostic report
generate_diagnostic_report <- function(condition, severity) {
# The function would normally fetch real data
# This is a simplified example
condition_data <- switch(condition,
"diabetes" = list(
title = "Diabetes Management Report",
metrics = c("HbA1c", "Fasting Glucose", "Post-prandial Glucose", "BMI"),
thresholds = c(7.0, 100, 140, 25),
units = c("%", "mg/dL", "mg/dL", "kg/m²")
),
"hypertension" = list(
title = "Hypertension Management Report",
metrics = c("Systolic BP", "Diastolic BP", "Heart Rate", "Sodium Intake"),
thresholds = c(130, 80, 80, 2300),
units = c("mmHg", "mmHg", "bpm", "mg/day")
),
"asthma" = list(
title = "Asthma Control Report",
metrics = c("FEV1", "PEF", "Symptom Score", "Rescue Inhaler Use"),
thresholds = c(80, 80, 3, 3),
units = c("% predicted", "% predicted", "score", "times/week")
)
)
# Generate random patient values based on severity
set.seed(123) # For reproducibility
if (severity == "mild") {
variation <- 0.1 # 10% variation from threshold
} else if (severity == "moderate") {
variation <- 0.3 # 30% variation from threshold
} else {
variation <- 0.5 # 50% variation from threshold
}
# Generate values relative to thresholds based on severity
patient_values <- sapply(1:length(condition_data$thresholds), function(i) {
# For simplicity, higher values are "worse" for all metrics here
# In a real application, this would be more nuanced
condition_data$thresholds[i] * (1 + variation * runif(1, 0.5, 1))
})
# Create report dataframe
report_data <- data.frame(
Metric = condition_data$metrics,
Patient_Value = round(patient_values, 1),
Threshold = condition_data$thresholds,
Units = condition_data$units,
Status = ifelse(patient_values > condition_data$thresholds, "Above Target", "At Target")
)
# Create recommendations based on severity
recommendations <- switch(severity,
"mild" = "Continue current management. Follow up in 3 months.",
"moderate" = "Adjust medication dosage. Follow up in 1 month.",
"severe" = "Urgent intervention required. Refer to specialist and follow up in 1 week."
)
# Return the report components
return(list(
title = condition_data$title,
condition = condition,
severity = severity,
data = report_data,
recommendations = recommendations
))
}
# Generate a sample report
sample_report <- generate_diagnostic_report(
condition = "diabetes",
severity = "moderate"
)
# Display the report
cat("<div class='report-header'>", sample_report$title, "</div>")
# Display the diagnostic data
kableExtra::kbl(sample_report$data, caption = paste("Patient Metrics -", toupper(substr(sample_report$severity, 1, 1)), substr(sample_report$severity, 2, nchar(sample_report$severity)), "Severity")) %>%
kableExtra::kable_styling(bootstrap_options = c("striped", "hover")) %>%
kableExtra::row_spec(which(sample_report$data$Status == "Above Target"), background = "#ffdddd") %>%
kableExtra::row_spec(which(sample_report$data$Status == "At Target"), background = "#ddffdd") %>%
kableExtra::column_spec(5, color = ifelse(sample_report$data$Status == "Above Target", "red", "green"))
Metric | Patient_Value | Threshold | Units | Status |
---|---|---|---|---|
HbA1c | 8.4 | 7 | % | Above Target |
Fasting Glucose | 126.8 | 100 | mg/dL | Above Target |
Post-prandial Glucose | 169.6 | 140 | mg/dL | Above Target |
BMI | 32.1 | 25 | kg/m² | Above Target |
# Visualize the metrics
ggplot(sample_report$data, aes(x = Metric, y = Patient_Value, fill = Status)) +
geom_bar(stat = "identity") +
geom_hline(aes(yintercept = Threshold), linetype = "dashed", color = "darkred") +
facet_wrap(~ Metric, scales = "free_y") +
labs(title = paste("Patient Metrics for", sample_report$condition),
subtitle = paste("Severity:", sample_report$severity),
y = "Value",
x = "") +
scale_fill_manual(values = c("Above Target" = "#ff6666", "At Target" = "#66aa66")) +
theme_minimal() +
theme(strip.background = element_rect(fill = "#f0f0f0"),
strip.text = element_text(face = "bold"),
axis.text.x = element_blank())
Adjust medication dosage. Follow up in 1 month.
# Add custom CSS for formatting
cat("
<style>
.report-header {
background-color: #2c3e50;
color: white;
padding: 15px;
margin-bottom: 20px;
font-size: 24px;
font-weight: bold;
border-radius: 5px;
text-align: center;
}
.recommendations {
background-color: #f8f9fa;
border-left: 4px solid #6c757d;
padding: 15px;
margin-top: 20px;
border-radius: 5px;
}
</style>
")
R
Markdown allows custom styling to create professional
documents. Here’s an example of using custom CSS.
# In an actual document, you would include this in a separate CSS file
# or in the YAML header, but for demonstration purposes:
custom_css <- "
/* Custom styles for medical reports */
body {
font-family: 'Roboto', 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1.6;
color: #333333;
}
h1, h2, h3, h4 {
color: #2c3e50;
font-weight: 700;
}
h1 {
border-bottom: 2px solid #3498db;
padding-bottom: 10px;
}
.section {
margin-bottom: 30px;
padding: 20px;
background-color: #f8f9fa;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.alert {
padding: 15px;
border-radius: 5px;
margin-bottom: 20px;
}
.alert-danger {
background-color: #f8d7da;
border: 1px solid #f5c6cb;
color: #721c24;
}
.alert-warning {
background-color: #fff3cd;
border: 1px solid #ffeeba;
color: #856404;
}
.alert-info {
background-color: #d1ecf1;
border: 1px solid #bee5eb;
color: #0c5460;
}
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
th {
background-color: #3498db;
color: white;
text-align: left;
padding: 12px;
}
td {
padding: 10px;
border: 1px solid #ddd;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
.footer {
margin-top: 50px;
padding-top: 20px;
border-top: 1px solid #ddd;
text-align: center;
font-size: 0.8em;
color: #777;
}
"
# You can write this to a file
# write(custom_css, file = "custom_styles.css")
# Then reference it in your YAML header:
# output:
# html_document:
# css: custom_styles.css
For PDF output, you can use LaTeX
customization.
# Example of LaTeX customization for PDF documents
# This would go in a header.tex file:
latex_header <- '
% Custom LaTeX preamble for medical documents
\\usepackage{booktabs} % Better table formatting
\\usepackage{multirow} % Multi-row cells in tables
\\usepackage{colortbl} % Table cell colors
\\usepackage{xcolor} % Custom colors
\\usepackage{fancyhdr} % Custom headers and footers
\\usepackage{graphicx} % Enhanced graphics
\\usepackage{titlesec} % Section title formatting
\\usepackage{enumitem} % Customized lists
\\usepackage{tcolorbox} % Colored boxes for important info
% Define custom colors
\\definecolor{medblue}{RGB}{52, 152, 219}
\\definecolor{meddarkblue}{RGB}{44, 62, 80}
\\definecolor{medred}{RGB}{231, 76, 60}
\\definecolor{medgreen}{RGB}{46, 204, 113}
\\definecolor{medyellow}{RGB}{241, 196, 15}
% Style section headings
\\titleformat{\\section}{\\normalfont\\Large\\bfseries\\color{meddarkblue}}{\\thesection}{1em}{}[{\\titlerule[0.8pt]}]
\\titleformat{\\subsection}{\\normalfont\\large\\bfseries\\color{medblue}}{\\thesubsection}{1em}{}
% Custom header/footer
\\pagestyle{fancy}
\\fancyhf{}
\\fancyhead[L]{Medical Document}
\\fancyhead[R]{\\today}
\\fancyfoot[C]{\\thepage}
\\renewcommand{\\headrulewidth}{0.4pt}
\\renewcommand{\\footrulewidth}{0.4pt}
% Define custom box environments
\\newtcolorbox{warningbox}{
colback=medyellow!10,
colframe=medyellow,
boxrule=0.5pt,
arc=2mm,
title=Warning
}
\\newtcolorbox{alertbox}{
colback=medred!10,
colframe=medred,
boxrule=0.5pt,
arc=2mm,
title=Alert
}
\\newtcolorbox{infobox}{
colback=medblue!10,
colframe=medblue,
boxrule=0.5pt,
arc=2mm,
title=Information
}
'
# You would write this to a file
# write(latex_header, file = "header.tex")
# Then reference it in your YAML header:
# output:
# pdf_document:
# includes:
# in_header: header.tex
For more complex reports, you can organize your code by sourcing
external R
scripts.
# In an actual document you would use:
# source("R/data_preparation.R")
# source("R/analysis_functions.R")
# source("R/visualization_helpers.R")
# Example content of data_preparation.R:
data_preparation_example <- '
# data_preparation.R
# Function to load and clean patient data
load_patient_data <- function(patient_id) {
# Connect to database or load from files
# Clean and preprocess data
# Return structured data frame
}
# Function to extract lab results
get_lab_results <- function(patient_id, date_range) {
# Query lab data for specified patient and date range
# Format and return results
}
# Function to load medication history
get_medication_history <- function(patient_id, date_range) {
# Query medication data
# Process and return structured history
}
'
# Example content of analysis_functions.R:
analysis_functions_example <- '
# analysis_functions.R
# Function to calculate risk scores
calculate_risk_scores <- function(patient_data) {
# Apply various risk scoring algorithms
# Return data frame with risk assessments
}
# Function to analyze trends
analyze_trends <- function(time_series_data, measure) {
# Apply time series analysis
# Identify significant changes or patterns
# Return trend analysis
}
# Function to generate treatment recommendations
generate_recommendations <- function(patient_data, risk_scores) {
# Apply clinical guidelines to patient data
# Generate personalized recommendations
# Return structured recommendations
}
'
# Display examples
cat("# Example data_preparation.R:\n")
cat("```r\n")
cat(data_preparation_example)
cat("```\n\n")
cat("# Example analysis_functions.R:\n")
cat("```r\n")
cat(analysis_functions_example)
cat("```\n")
cat('
1. Xie Y, Allaire JJ, Grolemund G (2018). *R Markdown: The Definitive Guide*. Chapman and Hall/CRC.
2. Xie Y, Dervieux C, Riederer E (2020). *R Markdown Cookbook*. Chapman and Hall/CRC.
3. Wickham H, Grolemund G (2017). *R for Data Science*. O\'Reilly Media.
4. American Diabetes Association (2023). *Standards of Medical Care in Diabetes*. Diabetes Care.
5. Whelton PK, et al. (2023). *Guideline for the Prevention, Detection, Evaluation, and Management of High Blood Pressure in Adults*. American College of Cardiology/American Heart Association.
6. Global Initiative for Asthma (2023). *Global Strategy for Asthma Management and Prevention*.
')
Xie Y, Allaire JJ, Grolemund G (2018). R Markdown: The Definitive Guide. Chapman and Hall/CRC.
Xie Y, Dervieux C, Riederer E (2020). R Markdown Cookbook. Chapman and Hall/CRC.
Wickham H, Grolemund G (2017). R for Data Science. O’Reilly Media.
American Diabetes Association (2023). Standards of Medical Care in Diabetes. Diabetes Care.
Whelton PK, et al. (2023). Guideline for the Prevention, Detection, Evaluation, and Management of High Blood Pressure in Adults. American College of Cardiology/American Heart Association.
Global Initiative for Asthma (2023). Global Strategy for Asthma Management and Prevention.
R version 4.3.3 (2024-02-29 ucrt) Platform: x86_64-w64-mingw32/x64 (64-bit) Running under: Windows 11 x64 (build 26100)
Matrix products: default
locale: [1] LC_COLLATE=English_United States.utf8 [2]
LC_CTYPE=English_United States.utf8
[3] LC_MONETARY=English_United States.utf8 [4] LC_NUMERIC=C
[5] LC_TIME=English_United States.utf8
time zone: America/New_York tzcode source: internal
attached base packages: [1] stats graphics grDevices utils datasets methods base
other attached packages: [1] reticulate_1.38.0 EBImage_4.44.0
kableExtra_1.4.0
[4] reactable_0.4.4 flextable_0.9.7 DiagrammeR_1.0.11
[7] flexdashboard_0.6.2 shiny_1.8.1.1 DT_0.33
[10] plotly_4.10.4 ggplot2_3.5.1 dplyr_1.1.4
[13] rmarkdown_2.29 knitr_1.49 jsonlite_1.8.9
[16] httr_1.4.7
loaded via a namespace (and not attached): [1] gtable_0.3.6 xfun_0.50
bslib_0.9.0
[4] htmlwidgets_1.6.4 visNetwork_2.1.2 lattice_0.22-6
[7] crosstalk_1.2.1 bitops_1.0-7 vctrs_0.6.5
[10] tools_4.3.3 generics_0.1.3 curl_6.2.0
[13] tibble_3.2.1 pkgconfig_2.0.3 Matrix_1.6-5
[16] data.table_1.16.4 RColorBrewer_1.1-3 uuid_1.2-0
[19] lifecycle_1.0.4 farver_2.1.2 compiler_4.3.3
[22] stringr_1.5.1 textshaping_0.4.0 munsell_0.5.1
[25] tiff_0.1-12 codetools_0.2-20 httpuv_1.6.15
[28] fontquiver_0.2.1 fontLiberation_0.1.0 htmltools_0.5.8.1
[31] sass_0.4.9 RCurl_1.98-1.14 yaml_2.3.10
[34] lazyeval_0.2.2 later_1.4.1 pillar_1.10.1
[37] jquerylib_0.1.4 tidyr_1.3.1 openssl_2.3.1
[40] cachem_1.1.0 abind_1.4-5 mime_0.12
[43] fontBitstreamVera_0.1.1 locfit_1.5-9.10 tidyselect_1.2.1
[46] zip_2.3.1 digest_0.6.37 stringi_1.8.4
[49] purrr_1.0.2 labeling_0.4.3 fastmap_1.2.0
[52] grid_4.3.3 colorspace_2.1-1 cli_3.6.3
[55] magrittr_2.0.3 withr_3.0.2 gdtools_0.4.2
[58] scales_1.3.0 promises_1.3.2 officer_0.6.8
[61] fftwtools_0.9-11 jpeg_0.1-10 png_0.1-8
[64] askpass_1.2.1 ragg_1.3.2 evaluate_1.0.3
[67] viridisLite_0.4.2 rlang_1.1.5 Rcpp_1.0.14
[70] xtable_1.8-4 glue_1.8.0 xml2_1.3.6
[73] BiocGenerics_0.48.1 svglite_2.1.3 rstudioapi_0.16.0
[76] R6_2.5.1 systemfonts_1.1.0