Statwise.Visualization builds statistical plot descriptions from tidy rows,
one-dimensional Nx.Tensors, map columns, and dataframe-like column data. The
direct constructors return %Statwise.Visualization.Plot{} structs. The
composition API returns %Statwise.Visualization.Figure{} structs.
Use Statwise.Visualization.to_vega_lite/2 to export a plot as a plain
Vega-Lite-compatible map.
For a runnable Livebook with all chart types and styling options, see
docs/visualization_gallery.livemd.
For the longer seaborn-inspired improvement plan, see
docs/visualization_roadmap.md.
In Livebook, install the optional display packages and call
Statwise.Visualization.show/2:
Mix.install([
{:statwise, path: "/Users/catethos/workspace/statistic"},
{:jason, "~> 1.4"},
{:vega_lite, "~> 0.1"},
{:kino_vega_lite, "~> 0.1"}
])Statwise.Visualization.box_plot(%{
control: [1.2, 1.8, 2.1],
treatment: [2.4, 2.8, 3.0]
})
|> Statwise.Visualization.show()Style can be applied after the plot content is built:
Statwise.Visualization.box_plot(%{
control: [1.2, 1.8, 2.1],
treatment: [2.4, 2.8, 3.0]
})
|> Statwise.Visualization.with_style(
width: 480,
height: 280,
color: "#2563eb",
opacity: 0.8,
background: "#ffffff",
config: [
axis: [
labelColor: "#374151",
titleColor: "#111827"
],
view: [
stroke: nil
]
]
)
|> Statwise.Visualization.show()Histogram
plot = Statwise.Visualization.histogram([1, 2, 2, 3, 4], bins: 10)
Statwise.Visualization.to_vega_lite(plot)With dataframe-style column data:
data = %{height: [62, 64, 66, nil, 70]}
Statwise.Visualization.histogram(data, x: :height)Missing values are dropped by default. Pass missing: :error to reject them.
Box Plot
Statwise.Visualization.box_plot([1, 2, 3, 4])Grouped data can be supplied as a map:
Statwise.Visualization.box_plot(%{
control: [1.2, 1.8, 2.1],
treatment: [2.4, 2.8, 3.0]
})Or selected from column data:
Statwise.Visualization.box_plot(data, columns: [:control, :treatment])Faceted box plots use tidy row data. Prefer semantic mappings:
rows = [
%{site: :north, treatment: :control, score: 1.2},
%{site: :north, treatment: :control, score: 1.8},
%{site: :north, treatment: :treated, score: 2.4},
%{site: :north, treatment: :treated, score: 2.8},
%{site: :south, treatment: :control, score: 1.0},
%{site: :south, treatment: :control, score: 1.4},
%{site: :south, treatment: :treated, score: 3.0},
%{site: :south, treatment: :treated, score: 3.4}
]
Statwise.Visualization.box_plot(rows,
x: :treatment,
y: :score,
color: :treatment,
facet: :site,
columns: 2,
title: "Scores by Treatment and Site"
)
|> Statwise.Visualization.with_style(width: 180, height: 220, color: "#2563eb")
|> Statwise.Visualization.show()Relational Plots
rows = [
%{time: 1, treatment: :control, score: 1.2},
%{time: 2, treatment: :control, score: 1.8},
%{time: 1, treatment: :treated, score: 2.4},
%{time: 2, treatment: :treated, score: 2.9}
]
Statwise.Visualization.scatter(rows, x: :time, y: :score, color: :treatment)
Statwise.Visualization.line(rows, x: :time, y: :score, color: :treatment)Categorical And Summary Plots
Statwise.Visualization.strip_plot(rows, x: :treatment, y: :score)
Statwise.Visualization.count_plot(rows, x: :treatment)
Statwise.Visualization.bar_plot(rows, x: :treatment, y: :score, stat: :mean)
Statwise.Visualization.point_plot(rows, x: :treatment, y: :score, interval: :confidence)Supported summary statistics are :count, :mean, :median, and :sum.
Supported intervals are nil, :standard_error, :confidence, and
:percentile. Standard-error and confidence intervals apply to stat: :mean;
percentile intervals can be used with any summary statistic.
Heatmaps
cells = [
%{metric: :a, group: :control, value: 0.42},
%{metric: :a, group: :treated, value: 0.61}
]
Statwise.Visualization.heatmap(cells, x: :group, y: :metric, color: :value)Faceting
Wrapped facets use facet: :field. Row and column facets use a facet spec:
Statwise.Visualization.scatter(rows,
x: :time,
y: :score,
facet: [row: :site, column: :treatment],
share_y: false
)share_x: false or share_y: false exports Vega-Lite independent scale
resolution for the corresponding axis.
ECDF
Statwise.Visualization.ecdf([3, 1, 2, 2])The ECDF builder sorts the sample and computes cumulative probabilities before export, making the resulting plot independent of Vega-Lite transforms.
QQ Plot
Statwise.Visualization.qq_plot([10.0, 11.5, 12.2, 13.1])QQ plots currently support distribution: :normal. The builder uses standard
normal quantiles on the x-axis and includes a sample-scaled reference line by
default. This keeps the plot useful for testing normality even when the sample
is not already standard normal.
Statwise.Visualization.qq_plot(values, reference_line: false)Use reference_scale: :standard to draw the unscaled standard-normal y = x
line instead:
Statwise.Visualization.qq_plot(values, reference_scale: :standard)QQ plots use separate point and reference-line layers. Style point size and the reference line separately:
Statwise.Visualization.qq_plot([10.0, 11.5, 12.2, 13.1, 13.8, 15.0])
|> Statwise.Visualization.with_style(
point: [
color: "#dc2626",
size: 80
],
reference: [
color: "#6b7280",
stroke_width: 1
]
)
|> Statwise.Visualization.show()Rank Plot
Rank plots show the average ranks assigned across two samples, which can be useful when inspecting nonparametric comparisons.
Statwise.Visualization.rank_plot([10, 30], [20], x_label: :control, y_label: :treatment)Statistical Test Annotations
The highest-level workflow is to build a categorical plot from tidy rows, then ask Statwise to compute the statistical comparison from the same plotted data. This keeps the visualized samples and the tested samples aligned:
control = [1.2, 1.9, 2.4]
treatment = [2.2, 3.0, 3.4]
rows =
Enum.map(control, &%{group: :control, score: &1}) ++
Enum.map(treatment, &%{group: :treated, score: &1})
rows
|> Statwise.Visualization.box_plot(x: :group, y: :score)
|> Statwise.Visualization.with_test(:t_test, groups: {:control, :treated})
|> Statwise.Visualization.show()For categorical plots, Statwise exports comparison brackets and labels as additional Vega-Lite layers. The default label includes the p-value and a preferred effect size when the test result has one. Annotation layers also carry tooltip fields for the test name, p-value, statistic, and rendered label.
You can use a nonparametric test the same way:
rows
|> Statwise.Visualization.box_plot(x: :group, y: :score)
|> Statwise.Visualization.with_test(:mann_whitney, groups: {:control, :treated})
|> Statwise.Visualization.show()For faceted plots, computed tests are run independently inside each facet:
rows
|> Statwise.Visualization.box_plot(x: :group, y: :score, facet: :site)
|> Statwise.Visualization.with_test(:t_test, groups: {:control, :treated})
|> Statwise.Visualization.show()When each panel has exactly two x-groups, groups: can be omitted. If a
requested group is missing or empty in a computed test annotation, Statwise
raises an explicit error instead of silently dropping the comparison. Multiple
test annotations on the same plot are stacked above the plotted values.
Precomputed results can also be attached when the test was run elsewhere:
result = Statwise.TTest.independent(control, treatment, effect_size: true)
rows
|> Statwise.Visualization.box_plot(x: :group, y: :score)
|> Statwise.Visualization.with_test(result, groups: {:control, :treated})
|> Statwise.Visualization.show()Use show: to control label content:
Statwise.Visualization.with_test(plot, result, show: [:p_value, :statistic])The existing result-specific plots are still available for direct inspection.
T-test results can be visualized as confidence-interval plots:
result = Statwise.TTest.independent([1.2, 1.9, 2.4], [2.2, 3.0, 3.4])
Statwise.Visualization.t_test(result)Any result with a confidence interval can use the generic helper:
Statwise.Visualization.confidence_interval(result)Mann-Whitney U results can be visualized as U1 and U2 statistic bars:
result = Statwise.MannWhitney.test([1, 2, 3], [2, 4, 6])
Statwise.Visualization.mann_whitney(result)Vega-Lite Output
The Vega-Lite exporter returns ordinary maps with string keys:
plot = Statwise.Visualization.histogram([1, 2, 2, 3], title: "Values")
spec = Statwise.Visualization.to_vega_lite(plot, width: 400, height: 240)For applications that want a specific format directly:
Statwise.Visualization.to_json(plot)
Statwise.Visualization.to_vega_lite_plot(plot)
Statwise.Visualization.to_kino(plot)to_vega_lite/2 remains dependency-free and returns a map. The other helpers
require Jason, VegaLite, or Kino.VegaLite to be available at runtime.
Style can also be passed as a one-off export option:
Statwise.Visualization.to_vega_lite(plot,
style: [
width: 420,
height: 240,
color: "#16a34a",
stroke_width: 3
]
)Themes, Palettes, And Escape Hatches
Themes are applied before attached style, and export-time style wins last:
plot
|> Statwise.Visualization.with_theme(:minimal)
|> Statwise.Visualization.with_palette(:statwise)
|> Statwise.Visualization.with_style(
encoding: [
x: [
axis: [
grid: true
]
]
]
)Available named themes are :default, :minimal, :paper, :dark, and
:livebook. Palettes accept :category10, :statwise, :muted, or a list of
hex colors.
Composition API
For layered charts, start with shared data and mappings, add layers, then label, facet, theme, or style the figure:
rows
|> Statwise.Visualization.plot(x: :time, y: :score, color: :treatment)
|> Statwise.Visualization.add(:point)
|> Statwise.Visualization.add(:line)
|> Statwise.Visualization.facet(column: :site)
|> Statwise.Visualization.label(title: "Scores by Site")
|> Statwise.Visualization.to_vega_lite()