I have a list of data (see below), which I represent graphically using this script:
# Define plotting parameters
pch_values <- c(16, 17) # Different symbols for beta_0 and beta_1
colors <- c("red", "blue", "gray60") # Colors for different noise types
lty_values <- c(1, 2, 3) # Line types for different noise types
quartile_titles <- c("Absolute Bias of First Quartile", "Absolute Bias of Second Quartile (Median)", "Absolute Bias of Third Quartile")
# Directory for saving plots
output_dir <- "Abs_Quartile_Bias_Plots"
if (!dir.exists(output_dir)) dir.create(output_dir)
# Compute unified y-axis limits for all quartile plots in test_data
y_values_all <- unlist(sapply(test_data, function(noise_data) {
sapply(noise_data, function(T_data) T_data)
}), use.names = FALSE)
ylim_min <- min(y_values_all, na.rm = TRUE)
ylim_max <- max(y_values_all, na.rm = TRUE)
margin <- 0.05 * (ylim_max - ylim_min) # Add 5% margin above and below
unified_ylim <- c(ylim_min - margin, ylim_max + margin)
# Set output file
png(file.path(output_dir, "Abs_Quartile_Bias_Case1.png"),
width = 1200, height = 400, res = 120)
par(mfrow = c(1, 3), mar = c(4, 4, 2, 1)) # 3 side-by-side subplots
# Plot each absolute quartile bias
for (quartile_idx in 1:3) {
# Start a blank plot with unified y-axis limits
plot(NULL, log = "x", xlim = range(sample_sizes), ylim = unified_ylim,
xlab = "Sample Size (T)",
ylab = quartile_titles[quartile_idx],
main = quartile_titles[quartile_idx])
# Add lines and points for beta_0 and beta_1 for each noise type
for (noise_idx in seq_along(noise_types)) {
noise <- noise_types[noise_idx]
for (coef_name_idx in seq_along(pch_values)) {
coef_name <- c("beta_0", "beta_1")[coef_name_idx] # Explicitly specify coefficient names
y_values <- sapply(test_data[[noise]][[coef_name]], function(T_data) T_data[[quartile_idx]])
# Plot lines
lines(sample_sizes, y_values, col = colors[noise_idx], lty = lty_values[noise_idx], lwd = 1)
# Plot points
points(sample_sizes, y_values, col = colors[noise_idx], pch = pch_values[coef_name_idx])
}
}
# Add legends
if (quartile_idx == 1) { # Only add legends to the first plot
legend("topright",
legend = c(expression(beta[0]), expression(beta[1])),
pch = pch_values,
col = "black", bty = "n")
legend("topright",
legend = str_to_title(noise_types),
col = colors,
lty = lty_values,
lwd = 1, bty = "n", inset = c(.18, 0))
}
}
dev.off()
Which yields the following figure:
The problem as you can see, is that ylim
is not adjusted to each subplot, which creates plots where the upper end of ylim
is far from the highest value of the lines inside the subplot.
Question:
Can someone help me modify the code such that ylim
is dynamically adjusted to the range of the data at hand?
I apologize of my data is not optimally arranged.
Here is the dput()
output of the data in question:
> dput(test_data)
list(gaussian = list(beta_0 = list(`50` = c(`25%` = 0.243594614710333,
`50%` = 0.00277753736411457, `75%` = 0.245669686373254), `100` = c(`25%` = 0.171918499273751,
`50%` = 9.39373213166839e-05, `75%` = 0.183152746837558), `200` = c(`25%` = 0.116881126444175,
`50%` = 0.00117104968639603, `75%` = 0.123610284184898), `500` = c(`25%` = 0.0804521896728776,
`50%` = 0.00103027837221392, `75%` = 0.0784101295289328), `1000` = c(`25%` = 0.0541010700519603,
`50%` = 0.00294703982537503, `75%` = 0.0531978110356446), `2000` = c(`25%` = 0.0377543581178926,
`50%` = 0.00333965713516848, `75%` = 0.0413079011502395), `5000` = c(`25%` = 0.0217425538489762,
`50%` = 0.000460109571013723, `75%` = 0.0257457441062152)), beta_1 = list(
`50` = c(`25%` = 0.00882506794511806, `50%` = 0.000371504996548033,
`75%` = 0.00765082797750871), `100` = c(`25%` = 0.00290263844961158,
`50%` = 6.82498075157412e-05, `75%` = 0.00286586470881645
), `200` = c(`25%` = 0.00109095625190614, `50%` = 5.22460831402505e-05,
`75%` = 0.00109448558611547), `500` = c(`25%` = 0.00026571655332952,
`50%` = 8.85613155698906e-07, `75%` = 0.000259202833770455
), `1000` = c(`25%` = 9.21700578033757e-05, `50%` = 7.24859772205377e-07,
`75%` = 9.59841859602406e-05), `2000` = c(`25%` = 3.41775667214161e-05,
`50%` = 3.30163678108342e-06, `75%` = 2.86060854759462e-05
), `5000` = c(`25%` = 8.28928386886751e-06, `50%` = 4.18267251500737e-07,
`75%` = 8.43229566438453e-06))), laplace = list(beta_0 = list(
`50` = c(`25%` = 0.198717632408904, `50%` = 0.0081310174987681,
`75%` = 0.210213471331161), `100` = c(`25%` = 0.130486991150159,
`50%` = 0.00513011870745728, `75%` = 0.151674765218005),
`200` = c(`25%` = 0.111212423845099, `50%` = 0.00734704246964579,
`75%` = 0.0981520122896047), `500` = c(`25%` = 0.0630465314163474,
`50%` = 0.00897075972839323, `75%` = 0.0683817884348215),
`1000` = c(`25%` = 0.042034483419907, `50%` = 0.00132855758101336,
`75%` = 0.0425837417269435), `2000` = c(`25%` = 0.0339129308142302,
`50%` = 0.00345531227818663, `75%` = 0.0280143719137393),
`5000` = c(`25%` = 0.0198791807771237, `50%` = 0.000479565883414246,
`75%` = 0.0194025102135911)), beta_1 = list(`50` = c(`25%` = 0.00740494352386101,
`50%` = 0.00058286479518399, `75%` = 0.00741009508728219), `100` = c(`25%` = 0.00244184197921071,
`50%` = 0.000134746791191187, `75%` = 0.00244511866997321), `200` = c(`25%` = 0.000866632964359182,
`50%` = 8.7678493771115e-05, `75%` = 0.0010573916668597), `500` = c(`25%` = 0.000235006834866658,
`50%` = 9.75544170911391e-06, `75%` = 0.000212441344117131),
`1000` = c(`25%` = 8.00301522252411e-05, `50%` = 1.07320472242378e-06,
`75%` = 7.29608951477445e-05), `2000` = c(`25%` = 2.54472054908028e-05,
`50%` = 1.46816056423305e-06, `75%` = 2.84447257516973e-05
), `5000` = c(`25%` = 6.16220803828504e-06, `50%` = 1.48241995123755e-07,
`75%` = 6.65929311072233e-06))), cauchy = list(beta_0 = list(
`50` = c(`25%` = 0.274524411682779, `50%` = 0.0361625726093231,
`75%` = 0.336776027564404), `100` = c(`25%` = 0.198215929997078,
`50%` = 0.00328917426856501, `75%` = 0.207109168934052),
`200` = c(`25%` = 0.155318692086412, `50%` = 0.00672679937945397,
`75%` = 0.154703229084234), `500` = c(`25%` = 0.0880029220252172,
`50%` = 0.00278228951379011, `75%` = 0.0884479446139164),
`1000` = c(`25%` = 0.0688536372229773, `50%` = 0.00305819621170977,
`75%` = 0.0644673760777885), `2000` = c(`25%` = 0.0507696330400698,
`50%` = 0.000188404592404767, `75%` = 0.0500372607497894),
`5000` = c(`25%` = 0.0310586078673812, `50%` = 0.0017270922827648,
`75%` = 0.0322962294132709)), beta_1 = list(`50` = c(`25%` = 0.0120626033466085,
`50%` = 0.0017021299049178, `75%` = 0.00978118814587825), `100` = c(`25%` = 0.00338466332476295,
`50%` = 7.46446842248005e-06, `75%` = 0.0037767462745677), `200` = c(`25%` = 0.00125677406659053,
`50%` = 4.41521154233016e-05, `75%` = 0.00133801259948108), `500` = c(`25%` = 0.000315465752873667,
`50%` = 1.30850267132665e-05, `75%` = 0.0003114951811094), `1000` = c(`25%` = 0.000119877019459924,
`50%` = 5.46893714759022e-07, `75%` = 0.000117584995672271),
`2000` = c(`25%` = 4.14058369635484e-05, `50%` = 9.97860400531181e-07,
`75%` = 4.36402038799244e-05), `5000` = c(`25%` = 9.47781604621056e-06,
`50%` = 9.22661139490799e-07, `75%` = 1.12907100797699e-05
))))
Apparently you have simulation data in matrix or matrix-convertible format. In this case, check out matplot
which is designed for matrices. Use type='o'
to get both lines and points.
png('foo.png', 800, 240)
op <- par(mfrow=c(1, 3), mar=c(4, 4, 2, 2)+.1)
for (i in 1:3) {
sim [[i]] |>
matplot(type='o', pch=rep(16:17, each=3), col=rep(colors, 2),
lty=rep(lty_values, 2), xlab='Sample Size (T)',
ylab=quartile_titles[i], xaxt='n', ylim=range(sim[[i]])*1.05)
axis(1, 1:7, sample_sizes)
if (identical(i, 1L)) {
legend("topright",
legend=c(as.list(noise_types), sapply(0:1, \(x) bquote(beta[.(x)]))),
pch=c(rep(NA, length(noise_types)), 16:17),
lty=c(lty_values, rep(NA, 2)),
col=c(colors, 1, 1), ncol=2, inset=c(-.1, 0),
bty="n")
}
}
par(op)
dev.off()
If you really want the redundant titles, use main
as usual.
Data:
set.seed(42)
sim <- outer((1:6)^2, c(.8, .5, 1),
Vectorize(\(z, f) {
(0.35*exp(-0.5*(1:7 - 1)) + rnorm(7, mean=0, sd=0.01))/z*f
},
SIMPLIFY=FALSE)) |>
apply(2, \(x) do.call('rbind', x), simplify=FALSE)
noise_types <- c('Gaussian', 'Laplace', 'Cauchy')
pch_values <- 16:17
colors <- c("gray60", "red", "blue")
lty_values <- c(3, 1, 2)
quartile_titles <- c("Absolute Bias of First Quartile",
"Absolute Bias of Second Quartile (Median)",
"Absolute Bias of Third Quartile")
sample_sizes <- c(50, 100, 200, 500, 1000, 2000, 5000)