bpca is an S3-based package for principal component biplot analysis. It supports:
hj, sqrt, jk, gh);This vignette presents a practical end-to-end workflow.
library(bpca)
data(gabriel1971)
data(ontario)gabriel1971 is a classic biplot matrix and works well for reproducible examples.
bp2 <- bpca(gabriel1971,
d=1:2)
class(bp2)
#> [1] "bpca.2d" "bpca" "list"
bp2$number
#> [1] 1 2
round(bp2$importance, 3)
#> explained
#> general 0.973
#> partial 0.973Key returned components include:
eigenvalues, eigenvectors;number (selected principal components);importance (retained variance);coord$objects and coord$variables.names(bp2)
#> [1] "call" "eigenvalues" "eigenvectors" "number" "importance"
#> [6] "coord" "var.rb" "var.rd"
str(bp2$coord)
#> List of 2
#> $ objects : num [1:8, 1:8] 3.976 2.593 -2.193 1.746 -0.929 ...
#> ..- attr(*, "dimnames")=List of 2
#> .. ..$ : chr [1:8] "toilet" "kitchen" "bath" "eletricity" ...
#> .. ..$ : chr [1:8] "PC1" "PC2" "PC3" "PC4" ...
#> $ variables: num [1:9, 1:8] 2.58 2.6 2.58 2.6 2.43 ...
#> ..- attr(*, "dimnames")=List of 2
#> .. ..$ : chr [1:9] "CRISTIAN" "ARMENIAN" "JEWISH" "MOSLEM" ...
#> .. ..$ : chr [1:8] "PC1" "PC2" "PC3" "PC4" ...summary(bp2)
#> Eigenvalue(s) :
#> [1] 7.627198e+00 1.771676e+00 1.096260e+00 5.064330e-01 3.456395e-01
#> [6] 3.150429e-01 1.001889e-01 5.766751e-16
#>
#> Considered on reduction :
#> [1] 7.627198 1.771676
#>
#> Variance retained by each :
#> [1] 0.92339915 0.04982279
#>
#> Cumulative variance retained :
#> [1] 0.9233991 0.9732219
#>
#> Prop. of total variance retained :
#> [1] 0.973
summary(bp2,
presentation=TRUE)
#> Eigenvalue(s): 7.627198 1.771676 1.09626 0.506433 0.3456395 0.3150429 0.1001889 5.766751e-16
#> - Considered on reduction: 7.627198 1.771676
#> - Variance retained by each: 0.9233991 0.04982279
#> - Cumulative variance retained: 0.9233991 0.9732219
#> - Prop. of total variance retained: 0.973methods <- c("hj", "sqrt", "jk", "gh")
retained <- sapply(
methods,
function(m) {
bp <- bpca(gabriel1971,
method=m,
d=1:2)
as.numeric(bp$importance["general", "explained"])
}
)
retained
#> hj sqrt jk gh
#> 0.973 0.973 0.973 0.973The retained variance can be similar across methods, but geometric interpretation differs.
var.rb stores projected correlations among variables under the selected biplot reduction.
bp2_q <- bpca(gabriel1971,
d=1:2,
var.rb=TRUE)
round(bp2_q$var.rb, 2)
#> CRISTIAN ARMENIAN JEWISH MOSLEM MODERN.1 MODERN.2 OTHER.1 OTHER.2 RUR
#> CRISTIAN 1.00 1.00 1.00 1.00 0.88 0.87 0.98 1.00 0.99
#> ARMENIAN 1.00 1.00 1.00 1.00 0.87 0.86 0.98 1.00 0.99
#> JEWISH 1.00 1.00 1.00 1.00 0.83 0.82 0.97 0.99 1.00
#> MOSLEM 1.00 1.00 1.00 1.00 0.86 0.85 0.98 1.00 1.00
#> MODERN.1 0.88 0.87 0.83 0.86 1.00 1.00 0.95 0.90 0.80
#> MODERN.2 0.87 0.86 0.82 0.85 1.00 1.00 0.94 0.89 0.79
#> OTHER.1 0.98 0.98 0.97 0.98 0.95 0.94 1.00 0.99 0.95
#> OTHER.2 1.00 1.00 0.99 1.00 0.90 0.89 0.99 1.00 0.98
#> RUR 0.99 0.99 1.00 1.00 0.80 0.79 0.95 0.98 1.00qbpca() compares observed vs projected correlations in vectorized form.
q2 <- qbpca(gabriel1971,
bp2_q)
head(q2)
#> obs var.rb
#> CRISTIAN vs. ARMENIAN 0.9973894 0.9999397
#> CRISTIAN vs. JEWISH 0.9561588 0.9961640
#> CRISTIAN vs. MOSLEM 0.9857920 0.9991587
#> CRISTIAN vs. MODERN.1 0.8665372 0.8773237
#> CRISTIAN vs. MODERN.2 0.8216573 0.8674140
#> CRISTIAN vs. OTHER.1 0.9520075 0.9849207var.rd highlights poorly represented variable correlations for a chosen threshold (limit).
bp2_rd <- bpca(gabriel1971,
d=1:2,
var.rb=TRUE,
var.rd=TRUE,
limit=3)
bp2_rd$var.rd
#> CRISTIAN ARMENIAN JEWISH MOSLEM MODERN.1 MODERN.2 OTHER.1 OTHER.2 RUR
#> CRISTIAN - * * * * *
#> ARMENIAN - * * *
#> JEWISH * * - *
#> MOSLEM - *
#> MODERN.1 - *
#> MODERN.2 * * -
#> OTHER.1 * - *
#> OTHER.2 * - *
#> RUR * * * * * * * -bp3 <- bpca(gabriel1971,
d=1:3,
var.rb=TRUE)
bp3$number
#> [1] 1 2 3
round(bp3$importance, 3)
#> explained
#> general 0.992
#> partial 0.992The plot.bpca.2d method supports several analysis-oriented views via type:
"bp": basic biplot;"eo": evaluate one object;"ev": evaluate one variable;"co" / "cv": compare objects / variables;"ww", "dv", "ms", "ro", "rv" for GGE-style diagnostics.Examples (kept as non-evaluated chunks to keep vignette deterministic):
# Basic 2D
plot(bp2)
# Evaluate one object
plot(bpca(ontario),
type="eo",
obj.id=7)
# Evaluate one variable
plot(bpca(ontario),
type="ev",
var.id="E7")
# Compare two objects
plot(bpca(ontario),
type="co",
obj.id=c("g7", "g13"))3D rendering can be static (scatterplot3d) or interactive (rgl):
# Static 3D
plot(bp3)
# Interactive 3D
plot(bp3,
rgl.use=TRUE)The package provides an xtable method for bpca objects.
if (requireNamespace("xtable", quietly=TRUE)) {
tbl <- xtable::xtable(bp2)
tbl[1:6, , drop=FALSE]
}
#> % latex table generated in R 4.7.0 by xtable 1.8-8 package
#> % Mon May 11 12:17:21 2026
#> \begin{table}[ht]
#> \centering
#> \begin{tabular}{lrrr}
#> \hline
#> &&\multicolumn{2}{c}{Eigenvectors\_MOSLEM} \\ \cline{3-4}
#> && PC1 $(\lambda_1=0.34)$& PC2 $(\lambda_2=0.21)$ \\
#> \hline
#> \multirow{3}{*}{Eigenvectors}&CRISTIAN&0.34&0.15 \\
#> &ARMENIAN & 0.34 & 0.17 \\
#> &JEWISH & 0.34 & 0.28 \\
#> \hline
#> &Eigenvectors\_MODERN.1 & 0.32 & -0.58 \\
#> &Eigenvectors\_MODERN.2 & 0.31 & -0.60 \\
#> \hline
#> \end{tabular}
#> \end{table}Use print() (S3) so the xtable.bpca formatter runs; xtable::print.xtable() does not dispatch to it.
For HTML output (including this html_vignette), pass type="html". The chunk must use results='asis' so the table is inserted as raw HTML.
if (requireNamespace("xtable",
quietly=TRUE)) {
tbl <- xtable::xtable(bp2)
print(tbl,
type="html")
}| PC1 (λ1=7.63) | PC2 (λ2=1.77) | |
|---|---|---|
| CRISTIAN | 0.34 | 0.15 |
| ARMENIAN | 0.34 | 0.17 |
| JEWISH | 0.34 | 0.28 |
| MOSLEM | 0.34 | 0.21 |
| MODERN.1 | 0.32 | -0.58 |
| MODERN.2 | 0.31 | -0.60 |
| OTHER.1 | 0.35 | -0.11 |
| OTHER.2 | 0.34 | 0.07 |
| RUR | 0.32 | 0.34 |
| Variance retained | 0.92 | 0.05 |
| Variance accumulated | 0.92 | 0.97 |
To generate the biplot-style LaTeX table (e.g. pdf_document or Sweave), use the default type and call print():
tbl <- xtable::xtable(bp2,
caption="Biplot summary",
label="tab:bp2")
rn <- rownames(tbl)
idx_retained <- which(rn == "Variance retained")
hlines <- c(-1, 0, nrow(tbl) - 1L)
if (length(idx_retained) == 1L && idx_retained > 1L) {
hlines <- c(hlines, idx_retained - 1L)
}
hlines <- sort(unique(hlines))
print(tbl,
hline.after=hlines)d=1:2 for 2D and d=1:3 for 3D.var.rb=TRUE and var.rd=TRUE when diagnosis quality is part of your analysis workflow.xtable::, rgl::).