Skip to content

Commit

Permalink
Add real content
Browse files Browse the repository at this point in the history
  • Loading branch information
asinghvi17 committed Mar 4, 2024
1 parent 20521b4 commit 5ee7025
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 18 deletions.
18 changes: 18 additions & 0 deletions docs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"devDependencies": {
"markdown-it": "^14.0.0",
"markdown-it-mathjax3": "^4.3.2",
"vitepress": "^1.0.0-rc.43",
"vitepress-plugin-tabs": "^0.5.0",
"vitest": "^1.3.0"
},
"scripts": {
"docs:dev": "vitepress dev build/.documenter",
"docs:build": "vitepress build build/.documenter",
"docs:preview": "vitepress preview build/.documenter"
},
"dependencies": {
"@shikijs/transformers": "^1.1.7",
"markdown-it-footnote": "^4.0.0"
}
}
7 changes: 6 additions & 1 deletion src/SwarmMakie.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# # SwarmMakie.jl

module SwarmMakie

# Write your package code here.
using Makie, Random

include("recipe.jl")
include("algorithms/simple.jl")

end
23 changes: 6 additions & 17 deletions src/beeswarm.jl → src/algorithms/mkborregaard.jl
Original file line number Diff line number Diff line change
@@ -1,16 +1,3 @@
using Random: shuffle
using Makie
@recipe(Beeswarm, positions) do scene
return default_theme(scene, Scatter)
end

Makie.conversion_trait(::Type{<: Beeswarm}) = Makie.PointBased()

function Makie.plot!(plot::Beeswarm)
positions = beeswarm.converted[1] # being PointBased, it should always receive a vector of Point2
markersize = beeswarm.markersize

end

function beeswarm_coords(olda, side = :both)

Expand Down Expand Up @@ -40,10 +27,10 @@ function beeswarm_coords(olda, side = :both)
end

function potential_interactions(freeind)
outside_range(x) = abs(a[freeind]-a[x])>cellsize
lo_ind = findprev(outside_range, LinearIndices(a), freeind)
outside_range(x) = abs(a[freeind] - x) > cellsize
lo_ind = findprev(outside_range, a, freeind)
lo = isnothing(lo_ind) ? 1 : lo_ind + 1
hi_ind = findnext(outside_range, LinearIndices(a), freeind)
hi_ind = findnext(outside_range, a, freeind)
hi = isnothing(hi_ind) ? lastindex(a)-1 : hi_ind - 1
if lo != 0 && hi != 0 && hi >= lo
included[freeind] ? (lo:hi)[.!(included[lo:hi])] : (lo:hi)[included[lo:hi]]
Expand All @@ -64,9 +51,11 @@ function beeswarm_coords(olda, side = :both)
nearest_ypos = fill(NaN, length(a))
while !isnothing(ind)
included[ind] = true
ind = findfirst(v->v>a[ind] + cellsize, a)
ind = findfirst(v -> v > (a[ind] + cellsize), a)
end

@show sum(included)

# now fill the rest in turn
update_ypos!(nearest_ypos, findall(.!(included)))
innow = sum(included)
Expand Down
13 changes: 13 additions & 0 deletions src/algorithms/simple.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""
SimpleBeeswarm()
A simple implementation like Matplotlib's algorithm.
"""
struct SimpleBeeswarm <: BeeswarmAlgorithm
end

function calculate!(buffer::AbstractVector{<: Point2}, alg::SimpleBeeswarm, positions::AbstractVector{<: Point2}, markersize)

buffer .= positions
return
end
96 changes: 96 additions & 0 deletions src/recipe.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# # Beeswarm recipe

# In this file, we define the `Beeswarm` recipe.

@recipe(Beeswarm, positions) do scene
return merge(
Attributes(
algorithm = NoBeeswarm(),
),
default_theme(scene, Scatter),
)
end

Makie.conversion_trait(::Type{<: Beeswarm}) = Makie.PointBased()

# this is subtyped by e.g. `SimpleBeeswarm` and `VerticallyChallengedBeeswarm`
abstract type BeeswarmAlgorithm end

struct NoBeeswarm <: BeeswarmAlgorithm
end

function calculate!(buffer::AbstractVector{<: Point2}, alg::NoBeeswarm, positions::AbstractVector{<: Point2}, markersize)
@info "Calculating..."
buffer .= positions
return
end


function Makie.plot!(plot::Beeswarm)
positions = plot.converted[1] # being PointBased, it should always receive a vector of Point2
@assert positions[] isa AbstractVector{<: Point2} "`positions` should be an `AbstractVector` of `Point2` after conversion, got type $(typeof(positions)). If you have passed in `x, y, z` input, be aware that `beeswarm` only accepts 2-D input (`x, y`)."

# this is a bit risky but #YOLO
# we extract the plot's parent Scene, from which we can extract
# the viewport, i.e., pixelspace!
scene = Makie.parent_scene(plot)
# Now, we can extract the Scene's limits from the camera's projectionview.
# Note that this only works for 2-D Scenes, and gets us the transformed space limits,
# so if you're trying to run this in a scene with a `transform_func`, that's something to
# be aware of.
finalwidths = lift(scene.camera.projection) do pv
xmin, xmax = minmax((((-1, 1) .- pv[1, 4]) ./ pv[1, 1])...)
ymin, ymax = minmax((((-1, 1) .- pv[2, 4]) ./ pv[2, 2])...)
return Makie.Vec2(xmax - xmin, ymax - ymin)
end
# and its viewport (in case the scene changes size)
pixel_widths = @lift widths($(scene.viewport))
old_pixel_widths = Ref(pixel_widths[])
old_finalwidths = Ref(finalwidths[])

should_update_based_on_zoom = Observable(nothing)
lift(plot, finalwidths, pixel_widths) do fw, pw # if we change more than 5%, recalculate.
if !all(isapprox.(fw, old_finalwidths[]; rtol = 0.05)) || !all(isapprox.(pw, old_pixel_widths[]; rtol = 0.05))
old_pixel_widths[] = pw
old_finalwidths[] = fw
notify(should_update_based_on_zoom)
end
end


# set up buffers
point_buffer = Observable{Vector{Point2f}}(zeros(Point2f, length(positions[])))
pixelspace_point_buffer = Observable{Vector{Point2f}}(zeros(Point2f, length(positions[])))
color_buffer = Observable{Vector{RGBA{Float32}}}()
# when the positions change, we must update the buffer arrays
onany(plot, plot.converted[1], plot.algorithm, plot.color, plot.markersize, should_update_based_on_zoom) do positions, algorithm, colors, markersize, _
if length(positions) != length(point_buffer[])
# recreate point buffer if lengths have changed
point_buffer.val = zeros(Point2f, length(positions))
pixelspace_point_buffer.val = zeros(Point2f, length(positions))
# color_buffer.val = zeros(RGBA{Float32}, length(positions))
end
pixelspace_point_buffer.val .= Makie.project.((scene.camera, ), :data, :pixel, positions)
calculate!(point_buffer.val, algorithm, pixelspace_point_buffer.val, markersize)
point_buffer.val .= Makie.project.((scene.camera,), :pixel, :data, pixelspace_point_buffer.val)
# color_buffer.val .= colors # TODO: figure out some way to make this better.

# update the scatter plot
notify(point_buffer)
end
# create a set of Attributes that we can pass down
attrs = copy(plot.attributes)
pop!(attrs, :algorithm)
pop!(attrs, :space)
# attrs[:color] = color_buffer
attrs[:space] = :data
attrs[:markerspace] = :pixel
# create the scatter plot
scatter_plot = scatter!(
plot,
attrs,
point_buffer
)
return
end

0 comments on commit 5ee7025

Please sign in to comment.