Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Creating Bland Altman Plots for dataset that has mutliple observations per patient

    Hi, I am trying to create a Bland Altman plot for dataset. I am comparing continuous values from two devices and my data contains maximum of 2 observations per patient. How do I create a Bland Altman plot while accounting for correlation at patient level?
    I have written the following code and tried to use the bootstrap technique but not sure if it is correct. Can someone please help me through this? Thanks!

    * Calculate the average and difference (bias)
    gen avg = (ctrl_thickness_cor + ctrl_thickness_pent) / 2
    gen bias = ctrl_thickness_cor - ctrl_thickness_pent

    * Summarize the bias and calculate LoA
    summarize bias, detail
    scalar mean_bias = r(mean)
    scalar sd_bias = r(sd)
    scalar ul_bias = r(mean) + 1.96 * r(sd)
    scalar ll_bias = r(mean) - 1.96 * r(sd)

    * Define a program for bootstrapping
    capture program drop blandaltman
    program blandaltman, rclass
    summarize bias, detail
    return scalar mean_bias = r(mean)
    return scalar ul_bias = r(mean) + 1.96 * r(sd)
    return scalar ll_bias = r(mean) - 1.96 * r(sd)
    end

    * Run the bootstrap with clustering by record_id, using BCa CIs
    bootstrap mean_bias=r(mean_bias) ul_bias=r(ul_bias) ll_bias=r(ll_bias), ///
    cluster(record_id) reps(1000) saving(C:\CCT, replace) seed(1234): blandaltman

    * Store bootstrap results
    estat bootstrap, all
    ereturn list
    matrix list = e(b)
    local actual_mean_bias: di %5.2f e(b)[1,1]
    local actual_ll: di %5.2f e(b)[1,2]
    local actual_ul: di %5.2f e(b)[1,3]

    matrix list = e(ci_percentile)
    local bs_meanll: di %5.2f e(ci_percentile)[1,1]
    local bs_meanul: di %5.2f e(ci_percentile)[2,1]
    local bs_lower_ll: di %5.2f e(ci_percentile)[1,2]
    local bs_lower_ul: di %5.2f e(ci_percentile)[2,2]
    local bs_upper_ll: di %5.2f e(ci_percentile)[1,3]
    local bs_upper_ul: di %5.2f e(ci_percentile)[2,3]


    * Debug: Display the CI values to check their width
    di "Mean Bias: " `actual_mean_bias' " (" `bs_meanll' " to " `bs_meanul' ")"
    di "LoA Upper: " `actual_ll' " (" `bs_lower_ll' " to " `bs_lower_ul' ")"
    di "LoA Lower: " `actual_ul' " (" `bs_upper_ll' " to " `bs_upper_ul' ")"



    twoway (scatter bias avg, mcolor("10 90 255") msize(small)) ///
    (function y = `actual_mean_bias', range(400 700) lcolor(red) lwidth(medium) lpattern(shortdash)) /// * Mean line in bold red
    (function y = `bs_meanll', range(400 700) lcolor(red) lwidth(medium) lpattern(dot)) /// * Mean ll line in bold red
    (function y = `bs_meanul', range(400 700) lcolor(red) lwidth(medium) lpattern(dot)) /// * Mean ul line in bold red
    (function y = `actual_ll', range(400 700) lcolor(blue) lwidth(medium) lpattern(shortdash)) /// * actual lowelimiy
    (function y = `bs_lower_ll', range(400 700) lcolor(blue) lwidth(medium) lpattern(dot)) /// * Upper limit in bold blue
    (function y = `bs_lower_ul', range(400 700) lcolor(blue) lwidth(medium) lpattern(dot)) /// * Lower limit in bold blue
    (function y = `actual_ul', range(400 700) lcolor(blue) lwidth(medium) lpattern(shortdash)) /// * actual upper limit
    (function y = `bs_upper_ll', range(400 700) lcolor(blue) lwidth(medium) lpattern(dot)) /// * Upper limit in bold blue
    (function y = `bs_upper_ul', range(400 700) lcolor(blue) lwidth(medium) lpattern(dot)) ///
    (function y = 0, range(400 700) lpattern(solid) lcolor(darkgray)) /// * Dotted line at y = 0
    , yscale(range(-80 80)) /// * Set the y-axis range
    ylabel(-80(20)80) /// * Adjust y-axis labels
    xlabel(400(50)700)


Working...
X