Per-pixel agreement heatmap for a producer signal matrix
Source:R/agreement_map.R
plot_agreement_map.RdVisualises where producers in a single condition agree on the
direction of signal. For each pixel, computes a one-sample
t-statistic against zero across producers
(mean / (sd / sqrt(N))), then displays the resulting map with
a diverging color palette (positive = agreement on positive
signal, negative = agreement on negative signal, zero = no
agreement). Saturation of the color is the magnitude of the
agreement, not the value of the group-mean CI.
Use this to answer "where do producers consistently agree the target trait lives in the face?". Pair with the group-mean CI image (raw mask or rendered) to see direction and agreement side by side.
Usage
plot_agreement_map(
signal_matrix,
img_dims = NULL,
mask = NULL,
threshold = NULL,
zlim = NULL,
palette = c("diverging", "fire"),
base_image = NULL,
alpha_max = 0.7,
main = "Per-pixel producer agreement (t-map)",
show_n = TRUE,
bar_label = NULL,
...
)Arguments
- signal_matrix
Pixels x participants raw mask (as returned by
ci_from_responses_*()orread_cis()+extract_signal()).- img_dims
Integer
c(nrow, ncol). IfNULL, inferred fromattr(signal_matrix, "img_dims")or fromsqrt(n_pixels)if the latter is a whole number.- mask
Optional logical vector of length
nrow(signal_matrix)(column-major) restricting display to a region (e.g.,make_face_mask(img_dims, region = "eyes")). Also accepts the output ofread_face_mask()for PNG/JPEG masks. Pixels outside the mask render asNA(transparent).- threshold
Optional positive numeric. When supplied, pixels with
|t| < thresholdare rendered in the neutral (white) color, making clusters of agreement stand out. DefaultNULL(full continuous map).- zlim
Numeric
c(low, high)for the color scale. Forpalette = "diverging"(default), defaults toc(-max(|t|), max(|t|))so the neutral color aligns witht = 0. Forpalette = "fire", defaults toc(0, max(|t|))so pale yellow aligns with|t| = 0.- palette
Character.
"diverging"(default; positive = blue, negative = red, neutral = white) encodes sign in hue and magnitude in saturation."fire"encodes|t|only on a single-hue ramp (pale yellow at zero -> deep red at large|t|); use this when the question is "where do producers have a consistent opinion" and direction is not needed. The"fire"view discards sign; pair withpalette = "diverging"or withplot_ci_overlay()to recover direction at a region of interest.- base_image
Optional. Either a numeric matrix (
nrow x ncol, grayscale, values in 0-1) or a path to a PNG/JPEG file. When supplied, the t-map is composited on top of the grayscale base; out-of-mask and subthreshold pixels render fully transparent. WhenNULL(default), the map is drawn on a flat panel viagraphics::image()(the historical behavior).- alpha_max
Numeric in
[0, 1]. Maximum opacity of the heatmap at the color-scale top (zlim_max) whenbase_imageis supplied. Ignored otherwise. Default 0.7.- main
Title.
- show_n
Logical. When
TRUE(default), draw the "N = ... producers, W x H pixels" subtitle line below the title. SetFALSEfor multi-panel layouts where this information is already in the caption.- bar_label
Optional character scalar overriding the colorbar axis label. When
NULL(default), uses"t"forpalette = "diverging"and"|t|"forpalette = "fire". Override e.g. with"Degree of agreement (|t|)"for a fire palette figure aimed at non-technical readers.- ...
Passed to
graphics::image().
Value
Invisibly, a list with t_map (numeric vector of t values
per pixel; always signed regardless of palette), n (producer
count), img_dims, mask (if supplied), zlim (the color
scale used), and palette (the palette name).
Details
This is structurally a one-sample t-map (vs zero); pixels where
producers' contributions are large and consistent in sign get
high |t|, pixels where contributions are random get t near zero.
Cluster-permutation inference would normally accompany this for
formal pixel-level FWER control between conditions
(rel_cluster_test()); the agreement map is the descriptive
counterpart for a single condition.
Reading the plot
Two palettes are available; pick by what question you are asking the data.
palette = "diverging" (default). Encodes sign and
magnitude together. Both deep red and deep blue indicate
strong agreement among producers; only the direction
differs. "No agreement" is the neutral color (white), not red.
Hue encodes the sign of the per-pixel one-sample
t. Blue = producers consistently add to the base at that pixel (positive agreement, producers chose noise that lightens the region); red = consistently subtract (negative agreement, producers chose noise that darkens the region).Saturation encodes
|t|. Deep color at either end means strong, consistent agreement; pale color means weak or inconsistent. The colorbar on the right reads intunits.zlimis symmetric around zero by default so the neutral color aligns witht = 0. Passzlim = c(-z, z)to fix the scale across panels for direct comparison.
palette = "fire". Encodes |t| only on a single-hue ramp
(pale yellow at zero -> deep red at large |t|). Use when the
question is where producers have a consistent opinion and the
direction is not needed. The "fire" view discards sign by
design; it cannot distinguish "producers consistently added"
from "producers consistently subtracted". To recover direction at
any region of interest, view the same data with
palette = "diverging" or pair with plot_ci_overlay() of the
group-mean CI.
Hue intensity encodes
|t|. Pale yellow / near-white at low|t|(so the underlying base face shows through low- agreement regions); orange at moderate|t|; deep red at large|t|. The colorbar reads in|t|units.zlimdefaults toc(0, max(|t|))and is asymmetric.
Common to both palettes.
thresholdclips color to the neutral end below|t| < threshold, making strong-agreement clusters stand out. This is descriptive only; it does not provide FWER control. For inferential pixel significance, useagreement_map_test()and render its result directly viaplot(agreement_map_test(...)), or overlay the contours viaplot_ci_overlay().base_imagecomposites the heatmap on top of a grayscale base face so anatomical context shows through. Out-of-mask and subthreshold pixels render fully transparent; the per-pixel opacity scales|t| / zlim_maxup toalpha_max. Works for both palettes. The color bar still shows the full scale so magnitudes are readable off the rendered overlay.The diverging color convention (blue = positive, red = negative) matches
plot_ci_overlay()and the cluster-test plots so the same group CI reads consistently across the package. The"fire"option is unique to this function; the CI-overlay and cluster-test plots need to show direction, so they do not provide a magnitude-only view.
See also
plot_ci_overlay() for the producer-mean counterpart
(signed CI, optionally with FWE contours); agreement_map_test()
for FWE-controlled significance, and its plot() method for a
one-call agreement map with contours; rel_cluster_test() for
inferential between-condition tests; make_face_mask() /
read_face_mask() for the optional mask.
Examples
if (FALSE) { # \dontrun{
# Minimal call-signature demo with a synthetic input. The agreement
# map will look flat because the input is pure noise.
n_side <- 32L
n_pix <- n_side * n_side
set.seed(1)
signal_matrix <- matrix(rnorm(n_pix * 20L), n_pix, 20L)
plot_agreement_map(signal_matrix, img_dims = c(n_side, n_side))
} # }
if (FALSE) { # \dontrun{
# Same function, richer input: simulate Brief-RC responses with a
# signal planted in the eye region, then look at the agreement map.
# Producers should consistently agree on the planted region.
sim <- simulate_briefrc_data(
n_per_condition = 20, n_trials = 60, conditions = "target",
signal_region = "eyes", signal_strength = "strong", seed = 1
)
cis <- ci_from_responses_briefrc(sim$data, noise_matrix = sim$noise_matrix)
plot_agreement_map(cis$signal_matrix)
} # }
if (FALSE) { # \dontrun{
# Composite the agreement map on the base face for a single
# publication-grade figure. Works for both palettes; the
# "diverging" branch matches plot_ci_overlay()'s color mapping.
sim <- simulate_briefrc_data(
n_per_condition = 20, n_trials = 60, conditions = "target",
signal_region = "eyes", signal_strength = "strong", seed = 1
)
cis <- ci_from_responses_briefrc(sim$data, noise_matrix = sim$noise_matrix)
plot_agreement_map(cis$signal_matrix,
base_image = sim$base_face,
threshold = 2.0,
main = "Agreement t-map over base face")
} # }