---
title: "DP Score Plots"
description: >
Estimate and plot private two-dimensional PCA score histograms,
configure synthetic sampling, compare groups, and reuse directions.
output:
rmarkdown::html_vignette:
toc: true
toc_depth: 2
vignette: >
%\VignetteIndexEntry{DP Score Plots}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r score-setup, include=FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.align = "center",
fig.width = 7,
fig.height = 5,
message = FALSE,
warning = TRUE,
error = FALSE,
cache = FALSE
)
```
This tutorial shows how to use `dp_score()` to estimate **private 2D score histograms**, inspect their stored probabilities, and display them as histograms or **synthetic score points**. It also covers the additive and sparse estimators, grouped plots, plot controls, and reuse of previously estimated private PC directions.
The focus is on **R arguments, examples, and visualization**.
For the mathematics of the private frame, histogram mechanisms, and privacy accounting, see [DP Score Methodology](method-dp-score.html).
For data requirements and general budget allocation, see [Getting Started](tutorials-getting-started.html).
## 1. Load the example data
We use `gau`, a synthetic dataset containing 1,000 observations and 20 numeric variables.
For dataset details, see the [`gau`](../reference/gau.html).
```{r score-data}
library(dppca)
data("gau", package = "dppca")
X <- gau
dim(X)
```
## 2. Set the privacy budget and estimate a score histogram
A `dp_score()` fit needs two privacy components: **`loading`**, to estimate private PC directions, and **`score`**, to estimate the private plotting frame and the histogram. If `split` is omitted, `dp_score()` allocates the total privacy budget equally between them.
```{r score-privacy}
score_privacy <- privacy_control(
eps = 6,
delta = 1e-4
)
```
In this example, loading and score each receive $(\varepsilon,\delta)=(3,5\times10^{-5})$ when used by `dp_score()`.
Within the score allocation, the package automatically assigns **35% of score epsilon to frame estimation**, **65% to the histogram**, and **all score delta to the histogram**.
First, we use both the additive and sparse histogram methods, without retaining non-private reference data:
```{r score-fit}
set.seed(123)
score_fit <- dp_score(
X,
privacy = score_privacy,
bins = c(10, 10),
method = c("add", "sparse"),
axes = c(1, 2),
non_private = FALSE
)
score_fit
```
The main arguments of `dp_score()` are:
::: {.score-argument-table}
| Argument | Description |
|:--|:--|
| `X` | Input observations; numeric features in columns. The selected group column, if any, is excluded from PCA. |
| `privacy` | Loading/score allocations from `privacy_control()`; an omitted `split` gives an equal two-way allocation for `dp_score()`. |
| `bins` | Positive integer vector `c(m_x, m_y)` specifying the numbers of horizontal and vertical histogram bins (required). |
| `method` | One or both of `"add"` (Gaussian) and `"sparse"` (stability-based); default: `c("add", "sparse")`. |
| `axes` | Two distinct PC indices, in horizontal/vertical order (default: `c(1, 2)`). |
| `cpp.option` | Use the compiled direction estimator (`TRUE`, the default), or the R implementation (`FALSE`). |
| `V_dp` | Reuse a previously estimated full private direction matrix; the loading allocation must record its actual prior privacy cost. |
| `non_private` | Retain ordinary PCA reference scores and histograms when `TRUE` (default: `FALSE`). |
| `group` | A group-column name or a label vector; `NULL` (default) fits a pooled histogram. Groups must be publicly fixed for the stated parallel-composition argument. |
:::
The `V_dp` argument allows previously estimated private PC directions to be reused in `dp_score()`.
For a detailed example, see [Reusing Private PC Directions](tutorials-scree-plots.html#reusing-private-pc-directions) in the DP Scree Plot tutorial.
### 2.1. Additive and sparse methods
The two estimators differ in how they perturb bin frequencies.
The full mathematical definitions are in [Additive histogram](method-dp-score.html#additive-histogram) and [Sparse histogram](method-dp-score.html#sparse-histogram).
::: {.score-method-table}
| Method | What to expect |
|:--|:--|
| `"add"` | Adds Gaussian noise to **every** count; normalizes truncated positive counts. |
| `"sparse"` | Adds Laplace noise **only to nonempty** bin proportions; keeps cells passing a threshold and may produce an all-zero histogram. |
:::
## 3. Inspect and plot the result
### 3.1. Read the fit and stored estimates
Printing the fitted object gives a summary of the stored results. `summary()` reports the frame, grid, grouping information when applicable, and positive bin counts and probability sums:
```{r score-summary}
score_summary <- summary(score_fit)
score_summary
```
You can inspect the same results directly:
```{r score-values}
score_fit$frame
head(score_fit$add)
sum(score_fit$add$prob)
score_fit$metadata$method
score_fit$metadata$privacy
```
::: {.score-argument-table}
| Stored component | Meaning |
|:--|:--|
| `score_fit$frame$xlim`, `$ylim` | Private horizontal and vertical plotting limits. |
| `score_fit$add` | Data frame with `xmin`, `xmax`, `ymin`, `ymax`, and `prob` for every cell. |
| `score_fit$add$prob` | Estimated probability mass in each cell, **not** density height or an observed cell count. |
| `score_fit$nonprivate` | `NULL` here (`non_private = FALSE`); when requested, stores ordinary PCA reference results. |
| `score_fit$nonprivate$scores` | Centered ordinary PCA score coordinates, available only when `non_private = TRUE`. |
| `score_fit$nonprivate$frame`, `$histogram` | Ordinary reference frame and histogram when requested. |
| `score_fit$metadata` | Data dimensions, axes, bin counts, method(s), privacy allocation, and grouping settings. |
:::
### 3.2. Show a private histogram
```{r score-histogram, fig.alt="Private two-dimensional PCA score histogram with shaded rectangular bins."}
histogram_plot <- plot(
score_fit,
type = "histogram"
)
```
The shade of a cell represents its estimated probability mass.
The `center` argument controls **display centering**, not the estimation of
private directions, the score frame, or histogram probabilities. By default,
`center = TRUE` shifts the midpoint of the privately estimated score frame
to $(0,0)$ in both histogram and synthetic-sample plots, See [Display centering](method-dp-score.html#score-display-centering).
To retain the original private frame coordinates in the plots, set
`center = FALSE` explicitly:
```{r score-center, eval=FALSE, fig.alt="Private PCA score histogram and synthetic samples displayed without shifting the private frame center to the origin."}
set.seed(321)
plot(score_fit, type = c("histogram", "sample"), center = FALSE)
```
### 3.3. Draw synthetic score points
The same fitted histogram can be displayed as synthetic points.
```{r score-sample, fig.alt="Synthetic PCA score points sampled from the private histogram."}
set.seed(321)
sample_plot <- plot(
score_fit,
type = "sample",
sampling_control = sampling_control(
method = "uniform",
sample_size = 500,
bandwidth_scale = 0.1
)
)
```
These are **500 newly generated coordinates**. A bin is first selected using the stored private probabilities;
the point is then generated within that bin or at its center, optionally with Gaussian jitter. See [Synthetic score sampling](method-dp-score.html#synthetic-sampling).
The main arguments of `sampling_control()` are:
::: {.score-sampling-table}
| Setting | Description |
|:--|:--|
| `method = "uniform"` | Draw uniformly inside a sampled bin, followed by optional jitter (default). |
| `method = "center"` | Start at a sampled bin's center, followed by optional jitter. |
| `sample_size = NULL` | By default, generate the same number of synthetic points as the original observations (1,000 in this example). |
| `bandwidth_scale = NULL` | Use method-specific default jitter multipliers: `center = 0.5` and `uniform = 0.25`. |
| `bandwidth_scale = 0` | Disable jitter; `"center"` then produces points exactly at bin centers. |
:::
When `dp_score()` is fitted with `non_private = TRUE`, `plot()` automatically includes non-private comparison panels. For sample plots, the non-private panel displays the original centered PCA scores by default, while the private panel displays synthetic points generated from the DP histogram. If `sample_size` is explicitly specified, both panels display the specified number of synthetic points sampled from their respective histograms. A fit with `non_private = FALSE` displays only private panels; `plot()` has no separate `non_private` option.
## 4. Customize the plot
Use `score_plot_control()` to adjust colors, labels, point sizes, and the group legend.
```{r score-customize, fig.alt="Private additive score histogram with customized labels and shading."}
plot(
score_fit,
type = "histogram",
plot_control = score_plot_control(
color = "#1F4E79",
add_title = "Estimated distribution on PC1 and PC2",
xlab = "Private PC1 score",
ylab = "Private PC2 score",
hist_alpha_range = c(0, 0.85),
base_size = 13,
title_size = 14
)
)
```
::: {.score-sampling-table}
| Plot setting | What it changes |
|:--|:--|
| `color`, `hist_alpha_range` | Default histogram/scatter color and shading intensity. |
| `scatter_size`, `scatter_alpha` | Synthetic/observed point size and transparency. |
| `add_title`, `sparse_title` | Titles for the private histogram methods. |
| `scatter_title`, `nonprivate_title` | Titles used when ordinary reference panels are shown. |
| `xlab`, `ylab`, `base_size`, `title_size` | Axis labels and typography. |
| `group_colors`, `show_group_legend` | Group palette and legend visibility. |
:::
## 5. Group-wise private score histograms {#group-score-tutorial}
The `group` argument estimates histograms for labelled groups using **one shared private direction estimate, one frame, and one grid**.
Group labels and their fixed membership must be public for the stated group-level privacy accounting. The `group` column is excluded from PCA features. The theory and assumptions are detailed in [Group-wise private score histograms](method-dp-score.html#grouped-score).
### 5.1. Fit a private histogram for each group
The `gau_g` dataset adds a `group` column to the 20 numeric variables.
```{r score-group-data}
data("gau_g", package = "dppca")
X_group <- gau_g
dim(X_group)
table(X_group$group)
```
We first fit private-only group histograms:
```{r score-group-fit}
set.seed(456)
group_fit <- dp_score(
X_group,
privacy = score_privacy,
bins = c(10, 10),
group = "group",
non_private = FALSE
)
summary(group_fit)
names(group_fit$groups)
```
The result stores one histogram per group, for example `group_fit$groups[["group1"]]$add`.
Optional ordinary reference group histograms would be available through `group_fit$nonprivate$groups[["group1"]]$histogram` only when fitted with `non_private = TRUE`.
### 5.2. Plot a group histogram overlay
The group-wise histograms can be visualized using `plot(group_fit)` without specifying any additional options.
```{r score-group-default, fig.alt="Group-wise differentially private score histogram"}
plot(group_fit)
```
Group colors are assigned automatically according to the following rules:
- If all group labels are valid color names recognized by R (e.g., `"red"`, `"blue"`, and `"green"`), those colors are used directly.
- Otherwise, colors are automatically generated using the `"Dark 3"` palette from `grDevices::hcl.colors()`.
- Users can override the automatic colors by specifying `group_colors` through `score_plot_control()`.
For example, we can assign custom colors to the five groups and adjust the histogram transparency:
```{r score-group-histogram, fig.alt="Group-wise differentially private score histogram overlays with five custom group colors"}
group_colors <- c(
group1 = "#0072B2", group2 = "#D55E00", group3 = "#009E73",
group4 = "#CC79A7", group5 = "#E69F00"
)
group_hist_plot <- plot(
group_fit,
sampling_control = sampling_control(
method = "uniform", sample_size = 500
),
plot_control = score_plot_control(
group_colors = group_colors,
hist_alpha_range = c(0, 0.75)
)
)
```
The `hist_alpha_range` argument controls the transparency range, with `c(0, 0.75)` setting the maximum opacity to 0.75. Each group's bin probabilities are normalized within that group. Also, `sample_size = 500` requests **500 points across all groups**, not 500
per group.
For complete argument descriptions, see `?dp_score`, `?plot.dp_score`,
`?score_plot_control`, and `?sampling_control`. For a combined scree,
score, and loading analysis, continue to
[DP PCA Visualization](tutorials-pca-visualization.html).
---
**Previous:** [DP Scree Plot](tutorials-scree-plots.html)
**Next:** [DP PCA Visualization](tutorials-dp-visualization.html)
**Tutorial overview:** [Choose a starting point](tutorials-getting-started.html#choose-a-starting-point)