Staged bilateral hip scopes
Explore data
Code
# Explore vars
df %>%
group_by(staged_over_1year) %>%
skimr::skim(revision_scope_sum,
tha_sum,
any_reop_sum) | Name | Piped data |
| Number of rows | 152 |
| Number of columns | 54 |
| _______________________ | |
| Column type frequency: | |
| logical | 3 |
| ________________________ | |
| Group variables | staged_over_1year |
Variable type: logical
| skim_variable | staged_over_1year | n_missing | complete_rate | mean | count |
|---|---|---|---|---|---|
| revision_scope_sum | FALSE | 0 | 1 | 0.07 | FAL: 80, TRU: 6 |
| revision_scope_sum | TRUE | 0 | 1 | 0.12 | FAL: 58, TRU: 8 |
| tha_sum | FALSE | 0 | 1 | 0.05 | FAL: 82, TRU: 4 |
| tha_sum | TRUE | 0 | 1 | 0.03 | FAL: 64, TRU: 2 |
| any_reop_sum | FALSE | 0 | 1 | 0.12 | FAL: 76, TRU: 10 |
| any_reop_sum | TRUE | 0 | 1 | 0.15 | FAL: 56, TRU: 10 |
Code
# Explore vars
df %>%
skimr::skim(age_surgery_1,
age_surgery_2,
sex,
bmi,
alpha_AP,
alpha_frog,
alpha_90,
lcea,
posterior_wall,
crossover,
ischial)| Name | Piped data |
| Number of rows | 152 |
| Number of columns | 54 |
| _______________________ | |
| Column type frequency: | |
| factor | 4 |
| numeric | 7 |
| ________________________ | |
| Group variables | None |
Variable type: factor
| skim_variable | n_missing | complete_rate | ordered | n_unique | top_counts |
|---|---|---|---|---|---|
| sex | 0 | 1.00 | FALSE | 2 | fem: 90, mal: 62 |
| posterior_wall | 35 | 0.77 | FALSE | 2 | 0: 93, 1: 24 |
| crossover | 36 | 0.76 | FALSE | 2 | 0: 67, 1: 49 |
| ischial | 36 | 0.76 | FALSE | 2 | 0: 60, 1: 56 |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| age_surgery_1 | 0 | 1.00 | 36.06 | 13.02 | 15.49 | 26.74 | 34.34 | 45.07 | 70.02 | ▅▇▃▂▁ |
| age_surgery_2 | 0 | 1.00 | 37.65 | 13.25 | 15.62 | 28.36 | 36.29 | 45.57 | 71.23 | ▅▇▆▃▂ |
| bmi | 0 | 1.00 | 25.66 | 4.63 | 18.00 | 22.58 | 24.50 | 28.22 | 39.15 | ▃▇▃▁▁ |
| alpha_AP | 35 | 0.77 | 65.24 | 15.62 | 37.80 | 52.20 | 68.20 | 76.60 | 116.90 | ▆▅▇▁▁ |
| alpha_frog | 36 | 0.76 | 56.59 | 10.21 | 37.10 | 48.98 | 55.36 | 64.28 | 81.80 | ▅▇▆▅▂ |
| alpha_90 | 40 | 0.74 | 47.79 | 12.77 | 30.50 | 39.65 | 43.95 | 54.32 | 118.90 | ▇▃▁▁▁ |
| lcea | 35 | 0.77 | 34.73 | 6.33 | 19.80 | 30.30 | 34.06 | 38.30 | 53.80 | ▂▇▇▃▁ |
Code
# Visualize data
df %>% ggplot(aes(x = time_between_cases,
y = MHHS_2yr,
group = case_id,
col = case_id)) +
geom_point(size = 3) +
geom_smooth(method = lm,
se = TRUE,
linewidth = 1.2) +
scale_color_viridis_d(option = 'plasma',
end = .7)Results
Demographics
Code
n_patients <- df %>% distinct(id) %>% nrow() %>% as.numeric()
n_hip <- df %>% nrow() %>% as.numeric()
# Demographics
demos <- df %>%
filter(case_id == '1') %>%
summarise(
across(
c(age_surgery_1,
age_surgery_2,
bmi,
time_between_cases),
list(mean = mean,
sd = sd,
min = min,
max = max),
.names = '{.col}.{.fn}'
)
) %>%
pivot_longer(everything()) %>%
mutate(
value = round(value, digits = 1)
) %>%
separate_wider_delim(
cols = name,
delim = '.',
names = c('var', 'stat')
) %>%
pivot_wider(
names_from = stat,
values_from = value
) %>%
as.data.frame() %>%
column_to_rownames(var = 'var')
# Followup
demos <- df %>%
mutate(fu_fix = case_when(
followup < 1.7 & !is.na(MHHS_2yr) ~ 2,
TRUE ~ followup
)) %>%
filter(case_id == '1') %>%
filter(followup >= 1.7) %>%
summarise(
across(c(fu_fix),
list(mean = mean,
sd = sd),
.names = '{.col}.{.fn}')
) %>%
pivot_longer(everything()) %>%
mutate(
value = round(value, digits = 1)
) %>%
separate_wider_delim(
cols = name,
delim = '.',
names = c('var', 'stat')
) %>%
pivot_wider(
names_from = stat,
values_from = value
) %>%
as.data.frame() %>%
column_to_rownames(var = 'var') %>%
bind_rows(demos)A total of 76 patients (152 hips) underwent staged bilateral primary hip arthroscopies with a minimum of two years postoperative followup and were included in this study. The mean age at the time of the first surgery was 36.1 +/- 13.1 years and the mean age at the time of the second surgery was 37.7 +/- 13.3 years. There was a mean duration of 1.6 +/- 1.8 years between the staged procedures (range 0.1 to 7.9 years). The mean followup for the cohort was 4.4 +/- 2.3 years.
Code
t1 <- df %>%
filter(case_id == '1') %>%
select(
age_surgery_1,
age_surgery_2,
sex,
bmi,
time_between_cases,
staged_over_1year
) %>%
mutate(
sex = recode_factor(sex,
'male' = 'Male',
'female' = 'Female')
) %>%
mutate(
staged_over_1year = recode_factor(as.factor(staged_over_1year),
'FALSE' = '< 1 year',
'TRUE' = '> 1 year')
) %>%
tbl_summary(
by = staged_over_1year,
missing = 'no',
statistic = list(
all_continuous() ~ '{mean} +/- {sd}'
),
digits = list(
all_categorical() ~ c(0,1),
all_continuous() ~ c(1,1)),
label = list(
age_surgery_1 ~ 'Age at first stage (years)',
age_surgery_2 ~ 'Age at second stage (years)',
sex ~ 'Sex',
bmi ~ 'BMI',
time_between_cases ~ 'Duration between stages (years)'
)
) %>%
add_p(test = list(
all_continuous() ~ 't.test'
),
pvalue_fun = function(x) style_pvalue(x, digits = 3),
test.args = all_tests('fisher.test') ~ list(simulate.p.value = TRUE)) %>%
bold_p(t = 0.05) %>%
add_overall() %>%
modify_spanning_header(all_stat_cols(stat_0 = F) ~ "**Duration between stages**") %>%
modify_caption("<div style='text-align: left; font-weight: bold'>
Patient Demographics") %>%
bold_labels() %>%
as_gt() %>%
gt::tab_options(
table.font.size = '12px',
data_row.padding = gt::px(3)
)
t1| Characteristic | Overall, N = 761 | Duration between stages | p-value2 | |
|---|---|---|---|---|
| < 1 year, N = 431 | > 1 year, N = 331 | |||
| Age at first stage (years) | 36.1 +/- 13.1 | 33.8 +/- 12.8 | 39.0 +/- 13.0 | 0.092 |
| Age at second stage (years) | 37.7 +/- 13.3 | 34.3 +/- 12.9 | 42.1 +/- 12.7 | 0.011 |
| Sex | 0.828 | |||
| Male | 31 (40.8%) | 18 (41.9%) | 13 (39.4%) | |
| Female | 45 (59.2%) | 25 (58.1%) | 20 (60.6%) | |
| BMI | 25.5 +/- 4.6 | 25.6 +/- 4.8 | 25.4 +/- 4.5 | 0.867 |
| Duration between stages (years) | 1.6 +/- 1.8 | 0.4 +/- 0.3 | 3.1 +/- 1.9 | <0.001 |
| 1 Mean +/- SD; n (%) | ||||
| 2 Welch Two Sample t-test; Pearson’s Chi-squared test | ||||
Radiographic parameters
Code
t2 <- df %>%
select(
alpha_AP,
alpha_frog,
alpha_90,
lcea,
posterior_wall,
crossover,
ischial
) %>%
mutate(
posterior_wall = recode_factor(posterior_wall,
'0' = 'FALSE',
'1' = 'TRUE'),
crossover = recode_factor(crossover,
'0' = 'FALSE',
'1' = 'TRUE'),
ischial = recode_factor(ischial,
'0' = 'FALSE',
'1' = 'TRUE')
) %>%
mutate(
across(
where(is.factor),
as.logical
)
) %>%
tbl_summary(
missing = 'no',
statistic = list(
all_continuous() ~ '{mean} +/- {sd}'
),
digits = list(
all_categorical() ~ c(0,1),
all_continuous() ~ c(1,1)),
label = list(
alpha_AP ~ 'Alpha angle (AP view)',
alpha_frog ~ 'Alpha angle (frog lateral view)',
alpha_90 ~ 'Alpha angle (Dunn view)',
lcea ~ 'Lateral center edge angle',
posterior_wall ~ 'Posterior wall sign',
crossover ~ 'Crossover sign',
ischial ~ 'Ischial spine sign'
)
) %>%
modify_caption("<div style='text-align: left; font-weight: bold'>
Radiographic parameters") %>%
bold_labels() %>%
as_gt() %>%
gt::tab_options(
table.font.size = '12px',
data_row.padding = gt::px(3)
)
t2| Characteristic | N = 1521 |
|---|---|
| Alpha angle (AP view) | 65.2 +/- 15.6 |
| Alpha angle (frog lateral view) | 56.6 +/- 10.2 |
| Alpha angle (Dunn view) | 47.8 +/- 12.8 |
| Lateral center edge angle | 34.7 +/- 6.3 |
| Posterior wall sign | 24 (20.5%) |
| Crossover sign | 49 (42.2%) |
| Ischial spine sign | 56 (48.3%) |
| 1 Mean +/- SD; n (%) | |
Outcomes
There was no difference in the rate of revision arthroscopy, conversion to THA, or overall failure of primary arthroscopy between patients who underwent staged bilateral hip arthroscopies less than 1 year apart and those who underwent staged surgeries greater than 1 year apart.
Code
var_names <- df %>%
select(all_of(starts_with('mhhs_', ignore.case = FALSE)),
all_of(starts_with('nahs_', ignore.case = FALSE))) %>%
colnames()
t3 <- df %>%
filter(case_id == '1') %>%
select(
revision_scope_sum,
tha_sum,
any_reop_sum,
mhhs_baseline_side1,
mhhs_2yr_side1,
nahs_baseline_side1,
nahs_2yr_side1,
mhhs_baseline_side2,
mhhs_2yr_side2,
nahs_baseline_side2,
nahs_2yr_side2,
staged_over_1year
) %>%
mutate(
staged_over_1year = recode_factor(as.factor(staged_over_1year),
'FALSE' = '< 1 year',
'TRUE' = '> 1 year')
) %>%
tbl_summary(
by = staged_over_1year,
missing = 'no',
statistic = list(
all_continuous() ~ '{mean} +/- {sd}'
),
digits = list(
all_categorical() ~ c(0,1),
all_continuous() ~ c(1,1)),
label = list(
revision_scope_sum ~ 'Revision arthroscopy',
tha_sum ~ 'Conversion to THA',
any_reop_sum ~ 'Failure (any reoperation)',
mhhs_baseline_side1 ~ 'mHHS - Baseline',
mhhs_2yr_side1 ~ 'mHHS - 2 years',
nahs_baseline_side1 ~ 'NAHS - Baseline',
nahs_2yr_side1 ~ 'NAHS - 2 years',
mhhs_baseline_side2 ~ 'mHHS - Baseline',
mhhs_2yr_side2 ~ 'mHHS - 2 years',
nahs_baseline_side2 ~ 'NAHS - Baseline',
nahs_2yr_side2 ~ 'NAHS - 2 years'
)
) %>%
add_p(test = list(
all_continuous() ~ 't.test'
),
pvalue_fun = function(x) style_pvalue(x, digits = 3),
test.args = all_tests('fisher.test') ~ list(simulate.p.value = TRUE)) %>%
bold_p(t = 0.05) %>%
add_overall() %>%
modify_spanning_header(all_stat_cols(stat_0 = F) ~ "**Duration between stages**") %>%
modify_caption("<div style='text-align: left; font-weight: bold'>
Outcomes") %>%
bold_labels() %>%
as_gt() %>%
tab_options(
table.font.size = '12px',
data_row.padding = gt::px(3)
) %>%
tab_row_group(label = 'Second hip',
rows = 8:11) %>%
tab_style(
style = cell_text(weight = 'normal'),
locations = cells_body(
columns = label,
rows = 8:11
)
) %>%
tab_style(
style = cell_text(indent = px(10)),
locations = cells_body(
columns = label,
rows = 8:11
)
) %>%
tab_row_group(label = 'First hip',
rows = 4:7) %>%
tab_style(
style = cell_text(weight = 'normal'),
locations = cells_body(
columns = label,
rows = 4:7
)
) %>%
tab_style(
style = cell_text(indent = px(10)),
locations = cells_body(
columns = label,
rows = 4:7
)
) %>%
tab_row_group(label = 'Failure of primary arthroscopy',
rows = 1:3) %>%
tab_style(
style = cell_text(weight = 'normal'),
locations = cells_body(
columns = label,
rows = 1:3
)
) %>%
tab_style(
style = cell_text(indent = px(10)),
locations = cells_body(
columns = label,
rows = 1:3
)
)
t3| Characteristic | Overall, N = 761 | Duration between stages | p-value2 | |
|---|---|---|---|---|
| < 1 year, N = 431 | > 1 year, N = 331 | |||
| Failure of primary arthroscopy | ||||
| Revision arthroscopy | 7 (9.2%) | 3 (7.0%) | 4 (12.1%) | 0.460 |
| Conversion to THA | 3 (3.9%) | 2 (4.7%) | 1 (3.0%) | >0.999 |
| Failure (any reoperation) | 10 (13.2%) | 5 (11.6%) | 5 (15.2%) | 0.739 |
| First hip | ||||
| mHHS - Baseline | 53.6 +/- 16.0 | 56.5 +/- 14.7 | 50.1 +/- 17.1 | 0.107 |
| mHHS - 2 years | 83.8 +/- 15.6 | 85.2 +/- 17.9 | 82.5 +/- 13.3 | 0.588 |
| NAHS - Baseline | 52.3 +/- 15.7 | 55.8 +/- 14.3 | 48.2 +/- 16.4 | 0.048 |
| NAHS - 2 years | 84.3 +/- 16.0 | 85.3 +/- 19.1 | 83.2 +/- 12.4 | 0.660 |
| Second hip | ||||
| mHHS - Baseline | 53.7 +/- 14.8 | 57.7 +/- 13.5 | 48.5 +/- 15.1 | 0.010 |
| mHHS - 2 years | 82.9 +/- 18.1 | 84.7 +/- 19.3 | 79.3 +/- 16.0 | 0.514 |
| NAHS - Baseline | 52.8 +/- 16.7 | 56.1 +/- 15.9 | 48.7 +/- 17.1 | 0.064 |
| NAHS - 2 years | 85.9 +/- 19.0 | 86.5 +/- 22.8 | 84.9 +/- 12.2 | 0.823 |
| 1 n (%); Mean +/- SD | ||||
| 2 Fisher’s exact test; Welch Two Sample t-test | ||||
Based on logistic regression, the duration between hip arthroscopy stages does not have an effect on the risk of failure when controlling for age, sex, BMI, preoperative alpha angle (measured on Dunn view), and LCEA.
Code
library(lme4)
m <- glm(as.factor(any_reop) ~ time_between_cases + age + sex + bmi + alpha_90 + lcea,
data = df,
family = binomial)
# summary(m)
# exp(coef(m))
rt1 <- m %>%
tbl_regression(exponentiate = TRUE,
label = list(
time_between_cases ~ 'Time between stages (years)',
age ~ 'Age',
sex ~ 'Sex',
bmi ~ 'BMI',
alpha_90 ~ 'Alpha angle (Dunn view)',
lcea ~ 'LCEA'
),
pvalue_fun = function(x) style_pvalue(x, digits = 3)) %>%
bold_p(t = 0.05) %>%
modify_caption("<div style='text-align: left; font-weight: bold'>
Odds of failure of primary hip arthroscopy") %>%
modify_table_body(
~.x %>%
mutate(label = case_when(
label == 'male' ~ 'Male',
label == 'female' ~ 'Female',
TRUE ~ label
))
) %>%
as_gt() %>%
gt::tab_options(
table.font.size = 'small',
data_row.padding = gt::px(3)
)
rt1| Characteristic | OR1 | 95% CI1 | p-value |
|---|---|---|---|
| Time between stages (years) | 1.29 | 0.83, 1.94 | 0.227 |
| Age | 1.10 | 1.03, 1.20 | 0.010 |
| Sex | |||
| Female | — | — | |
| Male | 1.04 | 0.17, 5.72 | 0.964 |
| BMI | 1.02 | 0.82, 1.26 | 0.838 |
| Alpha angle (Dunn view) | 1.06 | 0.99, 1.14 | 0.072 |
| LCEA | 1.06 | 0.91, 1.22 | 0.458 |
| 1 OR = Odds Ratio, CI = Confidence Interval | |||