# \[ANN\] A Package for Generating Corner Plots (PairPlots.jl)

**URL:** <https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542>\
**Category:** Package Announcements\
**Tags:** plotting\
**Created:** [April 4, 2021, 3:36am UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542 "2021-04-04T03:36:53Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [December 27, 2022, 8:35pm UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/21 "2022-12-27T20:35:32Z")

</div>

Awesome to see the new release! Looking forward to trying it out 💯

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [December 28, 2022, 6:55am UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/22 "2022-12-28T06:55:49Z")

</div>

Looks really nice! By the way, I almost added super-above-subscripts to `rich` but then removed it again before merging because the possible line break semantics weren’t clear to me. But seeing this real world use case, maybe I should think about how to get it back in again. Because it would be nicer not having to mix latex and normal font styles just for that.

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [December 28, 2022, 9:08am UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/23 "2022-12-28T09:08:02Z")

</div>

And another comment, with weak dependencies coming in Julia 1.9, you could factor the Makie support out into a submodule that only loads the code when Makie is loaded as well. Then users of Plots wouldn’t need to pay the latency increase.

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [December 28, 2022, 10:54am UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/24 "2022-12-28T10:54:42Z")

</div>

@sefffal if you feel that the package will target Makie moving forward, you can consider moving it to MakieOrg for greater visibility:

> **[MakieOrg](https://github.com/MakieOrg)**
>
> Organization for the Makie plotting ecosystem. MakieOrg has 11 repositories available. Follow their code on GitHub.

---

<div class="post-metadata">

**Author:** ![sefffal](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sefffal/32/23640_2.png) [@sefffal](https://discourse.julialang.org/u/sefffal)\
**Post date:** [December 28, 2022, 2:40pm UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/25 "2022-12-28T14:40:58Z")

</div>

> [@jules](#):
>
> I almost added super-above-subscripts to `rich`…

That would be great! It would equally be really nice if there was a way to use the LaTeX functionality with the default font (unless, say, a glyph was not available). That way the LaTeXified axes labels could match too.

> [@jules](#):
>
> And another comment, with weak dependencies coming in Julia 1.9, you could factor the Makie support out into a submodule that only loads the code when Makie is loaded as well. Then users of Plots wouldn’t need to pay the latency increase.

Great point. I am still debating whether to keep the Plots.jl functionality or not. All the bookkeeping to layout the subplots makes the code very messy.  
To make the Plots.jl version work, I actually make all the plots “inset subplots” with absolute positioning, all inside a single large plot with hidden axes. Then I have to carefully manage the axis limits manually between all plots. Not so nice!

---

<div class="post-metadata">

**Author:** ![sefffal](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sefffal/32/23640_2.png) [@sefffal](https://discourse.julialang.org/u/sefffal)\
**Post date:** [December 28, 2022, 9:41pm UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/26 "2022-12-28T21:41:19Z")

</div>

Release is merged, tagged, and pile of new docs are live [here](https://sefffal.github.io/PairPlots.jl/dev/)!

I also added a basic Legend feature that can help with multiple series.

 ![image](https://global.discourse-cdn.com/julialang/original/3X/d/1/d1557c8e1d36ca2fdc289b79c92dd35627fc2780.png)

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [December 29, 2022, 10:20am UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/27 "2022-12-29T10:20:06Z")

</div>

Latex is a bit more complicated because glyphs like integral signs need to be adjusted so they look good with super and subscripts, and these relationships differ per font. Text layouting in Makie is much simpler and only concatenates letters left to right without kerning.

---

<div class="post-metadata">

**Author:** ![sefffal](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sefffal/32/23640_2.png) [@sefffal](https://discourse.julialang.org/u/sefffal)\
**Post date:** [February 27, 2023, 4:33pm UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/28 "2023-02-27T16:33:35Z")

</div>

# Announcing PairPlots.jl version 1.0.0!

In my opinion all the basic functionality of PairPlots is now present, so to avoid falling into the [0ver](https://0ver.org/) trap, I’m tagging this as the 1.0.0 release. Expect new major versions to arrive whenever we need to adjust the API.

New since the previous release:

- “Truth” lines and other vertical/horizontal line series.
- Automatic figure sizing (unless you are plotting into an existing layout e.g.`pairplot(fig[1,1])`
- Separate options for step-histograms and filled-histograms
- Improved automatic legend creation
- Integration with MCMCChains via a new julia 1.9+ package extension. Just run `pairplot(chains)`.

Extensive guide and docs: [PairPlots.jl](https://sefffal.github.io/PairPlots.jl/dev/)

**Two series overplotted with truth lines:**

 ![image](https://global.discourse-cdn.com/julialang/original/3X/f/d/fda446e62d11d498ea4fc582c96eca48831c445e.jpeg)

**MCMCChains support & figure auto-sizing**

 ![image](https://global.discourse-cdn.com/julialang/original/3X/a/f/afe4f79d8eb192cae87931c86a10533ff985b2ea.jpeg)

Thanks as always to the Makie maintainers who make this possible!

---

<div class="post-metadata">

**Author:** ![sefffal](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sefffal/32/23640_2.png) [@sefffal](https://discourse.julialang.org/u/sefffal)\
**Post date:** [November 28, 2023, 8:05pm UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/29 "2023-11-28T20:05:55Z")

</div>

# New release of PairPlots

PairPlots is now updated to 2.1.0, with the following new features:

## Support for Unitful and DynamicQuantities

If you plot a table with columns containing either Unitful units or DynamicQuantity units, the units will automatically be pulled out into series labels.

If you would like more customization, you can as always pass the `labels` keyword argument with your desired label formatting.

```julia
using Unitful # or DynamicQuantities
df = DataFrame((;a=randn(10000)*u"m",b=randn(10000)*u"m/s"))
pairplot(df)

```

 ![image](https://global.discourse-cdn.com/julialang/original/3X/1/7/176f0098c42c703e182a6dc2c37effa519d075fd.png)

## Support for missing data

You can now plot tables that contain missing data in some rows.  
To be conservative, any row with a missing value is removed from the figure (instead of only skipping some sub-plots).  
Feedback welcome on this behaviour.

Whenever missing data is skipped, an annotation is added to the bottom of the plot.  
If you don’t want the annotation, just drop the missing rows yourself eg. with `DataFrames.dropmissing` before you pass the table in.

```julia
# Generate some random, sometimes missing, data.
df = DataFrame(randn(1000,3) .* rand.(Ref((missing, 1, 1, 1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1))), :auto)
pairplot(df)

```

 ![image](https://global.discourse-cdn.com/julialang/original/3X/9/b/9b852b0be753a3100c0d98c95396648a7118faed.jpeg)

This works for multiple series as well:

```julia
pairplot(
    PairPlots.Series(df1,label="one",color=(:darkblue,0.5)),
    PairPlots.Series(df2,label="two",color=(:darkgreen,0.5))
)

```

 ![image](https://global.discourse-cdn.com/julialang/original/3X/7/3/7373677a935d27b260477e34b7955be644f0e9b1.jpeg)

## Support for Makie 0.20

Self-explanatory 🙂

Thanks everyone, and keep those feature-requests and bug-reports coming!

-WT

---

<div class="post-metadata">

**Author:** ![sefffal](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sefffal/32/23640_2.png) [@sefffal](https://discourse.julialang.org/u/sefffal)\
**Post date:** [December 18, 2023, 4:09pm UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/30 "2023-12-18T16:09:28Z")

</div>

## New Feature: full grid of plots above and below the diagonal

Thanks @aplavin for the feature request! PairPlots.jl now supports displaying a full grid of plots if you pass the `fullgrid=true` option:

```julia
N = 100000
α = [2randn(N÷2) .+ 6; randn(N÷2)]
β = [3randn(N÷2); 2randn(N÷2)]
γ = randn(N)
δ = β .+ 0.6randn(N)
df = (;α, β, γ, δ);

pairplot(df, fullgrid=true)

```

 ![image](https://global.discourse-cdn.com/julialang/original/3X/b/5/b5b0cae309274ba8c0bc8917034117218438bcbb.jpeg)

Adding a legend is currently not supported when combined with a full grid plot but will be added back in a future version.

While we’re at it, here’s a demo of just some of the ways you can customize the look of a pair plot:

```julia

using PairPlots, CairoMakie

N = 100000
θ = 8rand(N) .+ 0.1 .* randn.()
r = atan.(θ) .+ 0.1 .* randn.()
x = r.*cos.(θ) 
y = r.*sin.(θ) 
tbl = (;x,y,θ,r=r.^2)

fig = Figure(
    size=(1000,500)
)
pairplot(
    fig[1,1],
    tbl => (
        PairPlots.Hist(sigmas=[3],color=:black, linewidth=2),
        PairPlots.Contour(sigmas=[1],color=:blue, linewidth=2),
        PairPlots.Scatter(markersize=1 ,color=(:blue,1), filtersigma=3),
        PairPlots.MarginDensity(color=:white),
        PairPlots.MarginConfidenceLimits(color=:orange, linestyle=:dot, linewidth=5)
    ),
    PairPlots.Truth(
        (;x = 0, y=0),
        color=:darkred    
    ),
    fullgrid=true,
    labels = Dict(
        :θ => "angle θ",
        :r => Makie.rich("radius r", font=:bold, color=:red),
        :x => L"\sum_i^N{x_i}",
        :y => Makie.rich("position y", font=:italic)
    ),
    bodyaxis=(;
        aspect=1,
        backgroundcolor=:lightgray
    ),
    diagaxis=(;
        backgroundcolor=:black
    )
)

ax = Axis3(fig[1,2])
scatter!(ax,x,y,r,markersize=1)
hidedecorations!(ax)
Makie.Label(fig[0,:], "Super Title", fontsize=20)
fig

```

 ![image](https://global.discourse-cdn.com/julialang/original/3X/d/a/da54aa7998c97f3c9c876a3c8355e30338a79868.jpeg)

## Future Roadmap

The next major feature I would like to land is support for the new Makie declarative API. It’s my understanding that adopting this API will make it so that PairPlots can be animated, or updated live while eg an MCMC run is sampling. I’ll aim to do this as soon as the new API is stabilized by the Makie team.

Another feature request is for categorical axes. A contribution in the form of a PR adding this feature would be well-received.

Thanks all, and keep the feature requests coming!

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [December 18, 2023, 4:23pm UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/31 "2023-12-18T16:23:50Z")

</div>

This package gets better and better! Super useful for multivariate data analysis!

---

<div class="post-metadata">

**Author:** ![sefffal](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sefffal/32/23640_2.png) [@sefffal](https://discourse.julialang.org/u/sefffal)\
**Post date:** [December 28, 2023, 10:22pm UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/32 "2023-12-28T22:22:22Z")

</div>

Announcing a new minor release (that should be in the registry soon).

## New Feature: Trend Lines

This release added support for displaying simple linear trend lines fit to each pair of variables, skipping any missing values.

See [Failing to plot correlograms in Julia: Makie vs. AoG vs StatsPlots - #23 by sefffal](https://discourse.julialang.org/t/failing-to-plot-correlograms-in-julia-makie-vs-aog-vs-statsplots/107971/23) for the discussion that prompted this addition.

```julia
pairplot(
    table => (
        # choose what kind of series you want in body and along diagonal
        PairPlots.Scatter(),
        PairPlots.MarginHist(),
        # Add trend line
        PairPlots.TrendLine(color=:red),
    ),
    fullgrid=true
)

```

 ![image](https://global.discourse-cdn.com/julialang/original/3X/8/7/870fc9b2bddc8fe12faf784ea2cba0aa5640dc08.jpeg)

If the data is ill conditioned (such that calculating the line results in a singular exception, then no line is displayed.

I’m interested to expand on this in future. I can imagine wanting to see the formula, correlation coefficient, etc, as well as display arbitrarily complex models.

Perhaps this could be added via extension packages, eg for GLM.jl.

I’d be interested to hear what the community thinks would be a good approach.

---

<div class="post-metadata">

**Author:** ![sefffal](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sefffal/32/23640_2.png) [@sefffal](https://discourse.julialang.org/u/sefffal)\
**Post date:** [January 29, 2024, 6:13pm UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/33 "2024-01-29T18:13:22Z")

</div>

Announcing a new minor release of PairPlots.

## Improvement: Automatic choice of significant figures in titles

Starting with version 2.4.0, the number of decimal points in titles specifying the credible interval is now calculated automatically.

Previously if you plotted a variable with a very small range, eg. 0.0004 ± 0.001 the titles were always rounded to 0.00 ± 0.00. Not ideal! Thanks @astrozot on GitHub for the bug report.

If the variable range becomes smaller than ± 0.0001, we switch to using scientific notation automatically: e.g. (1 ± 0.1) X 10^-6 .

## Improvement: Use ± (\pm) when possible

Credible ranges like `10^{+2.5}_{-2.5}` are now displayed as `10±2.5`.

See example below.

I consider this release non-breaking (not requiring a major version bump) because the change in plot formatting is quite minor. This is furthermore a feature release instead of a patch release because this formatter can now be specified as a function instead of just a format string.

Happy plotting!

 ![image](https://global.discourse-cdn.com/julialang/original/3X/f/2/f24eef2b81f60e75ee2f64c3443dafb6b3ed21e5.jpeg)

---

<div class="post-metadata">

**Author:** ![sefffal](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sefffal/32/23640_2.png) [@sefffal](https://discourse.julialang.org/u/sefffal)\
**Post date:** [February 5, 2024, 4:09pm UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/34 "2024-02-05T16:09:17Z")

</div>

## Feedback Requested on Default Styles

## Question 1

Up until now, the number of bins used for the default style was always 32. If I recall correctly, this is the default in `corner.py`. I think it would be better to choose this number dynamically using something like Sturges’s formula.

Here is the before and after for 100,000 points, 10,000 points, 1000 points, and 100 points:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/7/2/727e2332d0cdbdd8a639ae2b937bb787ed1aabc9.jpeg)  
 ![image](https://global.discourse-cdn.com/julialang/original/3X/3/1/3119327e0c7402ce85a6424aefab5aae40c93293.jpeg)  
 ![image](https://global.discourse-cdn.com/julialang/original/3X/f/8/f8dfa1e321a1b24c4e1f90c31a36fe830679ad2d.jpeg)  
 ![image](https://global.discourse-cdn.com/julialang/original/3X/c/2/c297c6b8d677750a44ca291e65fe0c55c53ea716.jpeg)

The net result is that most existing plots will look a little more blocky. Note that as always you can override the number of bins when constructing the plot, this is just the default (that I think most people use anyways).

Are users okay with this change? Please let me know if not, otherwise I will release this as a new minor version in the coming days.

## Question 2

I am also wondering if we should not add a traditional histogram next to the smoothed kernel density estimates along the diagonals (for the default styles). The KDE looks really nice but can sometimes smooth over interesting structure in the data. Maybe it’s safer to do something like this:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/c/f/cf7fbfe4fe03b0d28bddeee72b0e500f161f7723.jpeg)

I would be interested to hear your thoughts. I won’t merge this change for the time being.

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [February 5, 2024, 10:04pm UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/35 "2024-02-05T22:04:04Z")

</div>

I like the proposal of adding the histogram on top of the kde by default.

---

<div class="post-metadata">

**Author:** ![sefffal](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sefffal/32/23640_2.png) [@sefffal](https://discourse.julialang.org/u/sefffal)\
**Post date:** [February 5, 2024, 10:23pm UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/36 "2024-02-05T22:23:12Z")

</div>

Thanks for the feedback. Do you think making this kind of style change is acceptable in a minor release, or would this be better as a major release?

I don’t really know whether default plot outputs should be considered part of SemVer or not.

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [February 5, 2024, 11:22pm UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/37 "2024-02-05T23:22:42Z")

</div>

I would personally consider it as a small improvement of defaults. People can always add a keyword option to be more explicit in their downstream scripts if they dislike defaults.

---

<div class="post-metadata">

**Author:** ![sefffal](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sefffal/32/23640_2.png) [@sefffal](https://discourse.julialang.org/u/sefffal)\
**Post date:** [February 6, 2024, 12:55am UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/38 "2024-02-06T00:55:17Z")

</div>

The changes described above are now released. Thanks for your inputs!

---

<div class="post-metadata">

**Author:** ![sefffal](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sefffal/32/23640_2.png) [@sefffal](https://discourse.julialang.org/u/sefffal)\
**Post date:** [February 9, 2024, 5:55pm UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/39 "2024-02-09T17:55:15Z")

</div>

Announcing a new minor release of PairPlots

## Improvement: address crowding of tick labels

In previous versions, tick labels could overlap with each other becoming unreadable. This happened whenever the formatted tick labels exceeded about 4 digits.

I experimented with trying to detect this situation, but in the end I found the code was quite brittle. We would need to guess where Makie would put the automatic ticks, format the value, and measure its length (or a similar heuristic).

Instead, I have simply rotated the x and y tick marks by 45 degrees. This gives them a lot more room without crowding.

### Before:

 ![](https://global.discourse-cdn.com/julialang/original/3X/5/6/5678d0336658dc67401b78d00b1e69e2b4d59d0f.png)

### After:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/1/6/16e41e615b98e8d2939bd2598f41b34f3631edd6.jpeg)

Another approach would be to rotate only the bottom ticks by 90 degrees. This looks a bit cleaner but I think it is harder to read.

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [February 9, 2024, 6:17pm UTC](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542/40 "2024-02-09T18:17:53Z")

</div>

This is really useful! Thanks for the update and hard work on this @sefffal !

[Previous page](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542.md?page=1)

[Next page](https://discourse.julialang.org/t/ann-a-package-for-generating-corner-plots-pairplots-jl/58542.md?page=3)
