A Hinton diagram is a compact visualization of a numerical matrix. Each cell is represented by a square whose area is proportional to the magnitude of the value, so larger values are immediately distinguishable from smaller ones, something that colour shading alone (as in a heatmap) does not achieve as directly.
For signed data, the convention established by Geoffrey Hinton for visualizing neural network weights is:
For non-negative data, the grey background is omitted and all squares are drawn in black.
A Hinton diagram excels when:
Typical use cases include neural network weight matrices, correlation matrices, factor loadings from PCA or factor analysis, and transition matrices from Markov models.
# A 10x10 signed matrix
set.seed(99)
m <- matrix(rnorm(100), nrow = 10)
rownames(m) <- paste0("r", 1:10)
colnames(m) <- paste0("c", 1:10)
df <- matrix_to_hinton(m)
ggplot(df, aes(x = col, y = row, weight = weight)) +
geom_hinton() +
scale_fill_hinton() +
coord_fixed() +
theme_hinton() +
labs(title = "A signed Hinton diagram")The five-function recipe is the standard gghinton
workflow:
matrix_to_hinton(): reshape the matrix to a tidy data
framegeom_hinton(): draw the squaresscale_fill_hinton(): apply the conventional white/black
colour schemecoord_fixed(): ensure squares appear as squares (not
rectangles)theme_hinton(): remove grid lines that would compete
visually with the squaresWhen all values are non-negative, geom_hinton() detects
this automatically and omits the grey background.
m_pos <- abs(m)
df_pos <- matrix_to_hinton(m_pos)
ggplot(df_pos, aes(x = col, y = row, weight = weight)) +
geom_hinton() +
scale_fill_hinton() +
coord_fixed() +
theme_hinton() +
labs(title = "An unsigned Hinton diagram")as_hinton_df() provides a generic interface that
dispatches on the class of its input.
# matrix
as_hinton_df(matrix(c(1, -2, 3, -4), 2, 2))
#> row col weight
#> 1 2 1 1
#> 2 1 1 -2
#> 3 2 2 3
#> 4 1 2 -4
# base R table
t2 <- table(
group = c("A", "A", "B", "B"),
outcome = c("yes", "no", "yes", "no")
)
as_hinton_df(t2)
#> row col weight row_label col_label
#> 1 2 1 1 A no
#> 2 1 1 1 B no
#> 3 2 2 1 A yes
#> 4 1 2 1 B yesIf you already have a tidy data frame with the right column names, pass it directly:
scale_by parameterBy default, normalization is per-panel: the largest
value in each facet fills its cell. When you want to compare magnitudes
across facets, use scale_by = "global" so that all
panels share the same scale.
set.seed(1)
df_a <- cbind(matrix_to_hinton(matrix(runif(9, -1, 1), 3, 3)),
panel = "A (range +/-1)")
df_b <- cbind(matrix_to_hinton(matrix(runif(9, -5, 5), 3, 3)),
panel = "B (range +/-5)")
df_ab <- rbind(df_a, df_b)
# Per-panel scaling: each panel's largest value fills its cell
ggplot(df_ab, aes(x = col, y = row, weight = weight)) +
geom_hinton(scale_by = "panel") +
scale_fill_hinton() +
coord_fixed() +
theme_hinton() +
facet_wrap(~panel) +
labs(title = 'scale_by = "panel" (default)')
# Global scaling: panel A appears much smaller
ggplot(df_ab, aes(x = col, y = row, weight = weight)) +
geom_hinton(scale_by = "global") +
scale_fill_hinton() +
coord_fixed() +
theme_hinton() +
facet_wrap(~panel) +
labs(title = 'scale_by = "global"')Pass a named values vector to
scale_fill_hinton() to override individual colours while
keeping the defaults for the rest:
df <- matrix_to_hinton(m)
ggplot(df, aes(x = col, y = row, weight = weight)) +
geom_hinton(background = FALSE) +
scale_fill_hinton(values = c(positive = "darkblue", negative = "darkred")) +
coord_fixed() +
theme_hinton() +
labs(title = "Custom colours")When matrix_to_hinton() detects row or column names it
adds row_label and col_label columns that you
can use with scale_* breaks and labels.
# m has rownames/colnames set above
df_named <- matrix_to_hinton(m)
ggplot(df_named, aes(x = col, y = row, weight = weight)) +
geom_hinton() +
scale_fill_hinton() +
scale_x_continuous(
breaks = seq_len(ncol(m)),
labels = colnames(m)
) +
scale_y_continuous(
breaks = seq_len(nrow(m)),
labels = rev(rownames(m)) # reversed because row 1 is at the top
) +
coord_fixed() +
theme_hinton() +
labs(title = "Named axes")Set background = FALSE to suppress the grey background
even for signed data:
ggplot(df, aes(x = col, y = row, weight = weight)) +
geom_hinton(background = FALSE) +
scale_fill_hinton(values = c(positive = "grey70")) +
coord_fixed() +
theme_hinton() +
labs(title = "Signed data without background")df_cor <- as_hinton_df(cor(mtcars))
vars <- colnames(mtcars)
ggplot(df_cor, aes(x = col, y = row, weight = weight)) +
geom_hinton() +
scale_fill_hinton() +
scale_x_continuous(breaks = seq_along(vars), labels = vars) +
scale_y_continuous(breaks = seq_along(vars), labels = rev(vars)) +
coord_fixed() +
theme_hinton() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(title = "cor(mtcars)",
subtitle = "White = positive, black = negative correlation")