Makie PairPlot

Hi all

I am trying to make a pairplot similar to what you get with the Seaborn library but with Makie. I am using MakieLayouts and StatsMakie. I am using the classic Iris data to test it before using it elsewhere. The problem is the data looks all stretched. I have tried using the options mentioned in the MakieLayout docs here but with no success. Would someone maybe take a look and see.

col_names = [:sepalLength, :sepalWidth, :petalLength, :petalWidth, :class]
df = readdlm("iris.csv", ',')|> DataFrame
rename!(df, col_names)
df[!, 1:4] = Float32.(df[!,1:4])
df[!, 5] = String.(df[!, 5])




function  pairplot(df)
    dim = size(df, 2)-1

    scene, layout = layoutscene(30, resolution = (900, 900))
    axs = layout[1:dim, 1:dim] = [LAxis(scene) for i in 1:dim^2]
    x = 0
    for i in 1:dim, j in 1:dim  
              
        if i == j
            x+=1
            plt = plot!(axs[x],Position.stack, histogram, Data(df), Group(:class), df[:, i])
        else
            x+=1
            plt = Makie.scatter!(axs[x], Data(df), Group(:class), df[:,j], df[:,i])    
        end
    end
    scene
end

testPlot = pairplot(df)

Output is below

1 Like

Hi! Glad to see some Makie use in the wild, and as a quick preface, it’s often faster to get answers in the Makie Slack or Zulip channels, because Discourse posts are not so visible for us. (I just saw this by chance)

Your actual question: Right now you have to do

using AbstractPlotting: px
scatter!(ax, data, markersize = 10px)

This workaround is still necessary because Makie started out with the assumption that scatter markers had a meaningful size in data coordinates. The px thing tells the backend to use screen space coordinates instead. We are working on clearing all of that up but in the meantime, that’s the fix :slight_smile:

1 Like

@jules Awesome! This works perfectly. Now that I have the data points scaling correctly I can clean up the axis, put in legend etc… I think now I can produce a professional quality graphic. I will post what my output is below and when I clean it up I will post the code so if anyone else wants to make a pair plot there will exist some reference. Also I didn’t look at the PR’s but it would be nice if corrplot would have some options so that it would produce graphs more like the Seaborne library that wold be great. I don’t think it would be too hard to do.

As a side note I have been using Plots for a while but Makie has always been something I come back to, to see the state of it. I like the fact that its well documented and it has more unified way doing things than Plots. Plots is nice I just find that there are too many back ends and you almost get what want when doing something complex, but never what you want. Anyway recently I have switched to Makie full time as the plots and animations are beautiful. Keep up the great work. Also don’t get me wrong about Plots it’s great, I just like the direction Makie is going better. Also I will join the slack channel.

7 Likes

For future reference, in case anyone wants the full working code, here it is. I am on Julia v1.5:

using Makie
using StatsMakie
using DataFrames
using DelimitedFiles
using GLFW
using AbstractPlotting
using MakieLayout

col_names = [:sepalLength, :sepalWidth, :petalLength, :petalWidth, :class]
df = readdlm("iris.csv", ',')|> DataFrame
rename!(df, col_names)
df[!, 1:4] = Float32.(df[!,1:4])
df[!, 5] = String.(df[!, 5])

function  pairplot(df)
    dim = size(df, 2)-1

    scene, layout = layoutscene(30, resolution = (900, 900))
    axs = layout[1:dim, 1:dim] = [LAxis(scene) for i in 1:dim^2]
    x = 0
    for i in 1:dim, j in 1:dim  
	      
	if i == j
	    x+=1
	    plt = plot!(axs[x],Position.stack, histogram, Data(df), Group(:class), df[:, i])
	else
	    x+=1
	    plt = Makie.scatter!(axs[x], Data(df), Group(:class), df[:,j], df[:,i])    
	end
    end
    scene
end

testPlot = pairplot(df)

Also, you can download the data here: https://gist.githubusercontent.com/curran/a08a1080b88344b0c8a7/raw/0e7a9b0a5d22642a06d3d5b9bcbad9890c8ee534/iris.csv - Just make sure to delete the first row of the CSV or it will fail.

Here are the package versions I had:

  [537997a7] AbstractPlotting v0.10.11
  [a93c6f00] DataFrames v0.20.2
  [f7f18e0c] GLFW v3.4.0
  [ee78f7c6] Makie v0.10.0
  [5a521ce4] MakieLayout v0.9.10
  [65254759] StatsMakie v0.2.3

Hopefully this helps future generations of Julians trying to make their own pairplot!

P.S. Thanks to @Dustin_Hess for providing the initial impetus for this!

3 Likes

In case someone ends up here, I’m fairly sure the code posted so far does not work anymore with current Makie versions.

I wrote a function that gives a result very similar to the default seaborn pairplot with hue:

using DataFrames, CairoMakie

function pairplot(df; stride=1, colormap=:thermal, resolution=(1200,1200))

    dim = size(df,2) # how many colums there are in the dataframe
    idxs = 1:stride:size(df,1)
    colorant = range(0, 1, length=length(idxs))

    pp_theme = Attributes(
        Axis = (
            aspect = 1,
            topspinevisible = false,
            rightspinevisible = false,
        ),
        Scatter = (
            colormap = colormap, # try :thermal, :darkrainbow
            markersize = 6
        )
    )

    f = with_theme(pp_theme) do
        f = Figure(resolution=resolution)

        for i in 1:dim, j in 1:dim

            ax = Axis(f[i, j])
            scatter!(df[idxs,j], df[idxs,i], color = colorant)

            if i==dim
                ax.xticklabelsvisible = true
                ax.xlabel = names(df)[j]
            end
            if j==1
                ax.yticklabelsvisible = true
                ax.ylabel = names(df)[i]
            end
        end
        f
    end
end

I have CairoMakie 0.6.4 and GLMakie 0.4.5 installed.
Example of the output:

6 Likes

It’s also worth to mention the AlgebraOfGraphics here, since it has Makie as backend.

There is some little discussion also here cornerplot and corrplot · Issue #210 · JuliaPlots/AlgebraOfGraphics.jl · GitHub.

I managed to get what I want (correlation + density plots) with the following code:

using CairoMakie, AlgebraOfGraphics
AoG = AlgebraOfGraphics
set_aog_theme!()

using RDatasets: dataset

iris = dataset("datasets", "iris")

let
	props = filter(!=(:Species),propertynames(iris))[:,:]
	fig = Figure()
	
	plt = data(iris) * visual(Scatter, markersize=6) * mapping(props, permutedims(props), col=dims(1), row=dims(2), color = :Species)
	ag = draw!(fig[1, 2:3], plt)
	
	plts = [data(iris) * (mapping(prop, color = :Species)) * AoG.density() for prop in props]
	[draw!(fig[1,1][i,1], plts[i]) for i in 1:length(props)]
	legend!(fig[end+1, 2], ag, orientation=:horizontal, tellheight=true)
	fig
end

3 Likes

Greate! Do you think about make it a package?