Skip to content

Instantly share code, notes, and snippets.

@jkrumbiegel
Last active July 31, 2023 21:07
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jkrumbiegel/9ffcae3f6d1e2794939a8241a889499f to your computer and use it in GitHub Desktop.
Save jkrumbiegel/9ffcae3f6d1e2794939a8241a889499f to your computer and use it in GitHub Desktop.
upset
using CairoMakie
##
function count_set(df, cols, setcols)
count(eachrow(df)) do row
any(ismissing, row[cols[setcols]]) && return false # all setcols must be non-missing
!all(row[cols[setcols]]) && return false # all set colls must be true
any(skipmissing(row[cols[Not(setcols)]])) && return false # no non-set cols can be true
return true
end
end
function upset_dots!(ax, colsets, nsets=maximum(Iterators.flatten(colsets)))
xlims!(ax, (0, length(colsets) + 1))
hidedecorations!(ax)
hidespines!(ax)
for (x, p) in enumerate(colsets)
scatter!(ax, fill(x, nsets - length(p)), collect(1:nsets)[Not(p)], markersize=16, color=:lightgray)
scatter!(ax, fill(x, length(p)), p, markersize=16, color=:black)
length(p) > 1 && lines!(ax, [x,x], [extrema(p)...], color=:black, linewidth=3)
end
end
ycols = [:noir,:war,:children,:adventure]
df = DataFrame(rand(Bool, 1000, 4), ycols)
fig = Figure(fontsize = 14)
intersection_ax = Axis(fig[1,1], ylabel="intersection size", yautolimitmargin = (0, 0.15))
dot_ax = Axis(fig[2,1])
set_ax = Axis(fig[2,2], xlabel="set size", yticks = (1:4, string.(ycols)),
xautolimitmargin = (0, 0.15), yticklabelpad = 10, xgridvisible = false)
intersects = [
[1], # 1. a only
[2], # 2. b only
[3], # 3. c only
[4], # 4. d only
[1,2], # 5. a and b only
[1,3], # 6. a and c only
[1,2,3], # 7. a, b, and c only
[1,2,3,4], # 8. a, b, c, and d
]
barplot!(intersection_ax, 1:length(intersects),
[count_set(df, ycols, i) for i in intersects],
bar_labels=:y, color = :gray20,
label_size = 14, label_formatter = x -> string(Int(x)))
barplot!(set_ax, 1:4, [count(df[!, col]) for col in ycols],
direction=:x, bar_labels=:y, label_size = 14, color = :gray20,
label_formatter = x -> string(Int(x)))
for i in 1:2:length(ycols)
poly!(dot_ax,
BBox(0, length(intersects) + 1, i-0.5, i+0.5),
color = :gray95
)
end
upset_dots!(dot_ax, intersects)
hidexdecorations!(intersection_ax)
hideydecorations!(set_ax, ticklabels = false)
rowgap!(fig.layout, 0)
linkyaxes!(dot_ax, set_ax)
linkxaxes!(dot_ax, intersection_ax)
hidespines!(intersection_ax, :t, :r, :b)
hidespines!(set_ax, :t, :r, :l)
fig
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment