-
-
Notifications
You must be signed in to change notification settings - Fork 317
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* implement waterfall recipe * add plotting_functions examples for waterfall to the docs * mention waterfall in NEWS.md * add more `lift`s in waterfall recipe Co-authored-by: Simon <[email protected]>
- Loading branch information
1 parent
39cc40f
commit 1c8d098
Showing
4 changed files
with
241 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
# waterfall | ||
|
||
{{doc waterfall}} | ||
|
||
### Examples | ||
|
||
\begin{examplefigure}{} | ||
```julia | ||
using CairoMakie | ||
CairoMakie.activate!() # hide | ||
|
||
y = [6, 4, 2, -8, 3, 5, 1, -2, -3, 7] | ||
|
||
waterfall(y) | ||
``` | ||
\end{examplefigure} | ||
|
||
The direction of the bars might be easier to parse with some visual support. | ||
|
||
\begin{examplefigure}{} | ||
```julia | ||
using CairoMakie | ||
CairoMakie.activate!() # hide | ||
|
||
y = [6, 4, 2, -8, 3, 5, 1, -2, -3, 7] | ||
|
||
waterfall(y, show_direction=true) | ||
``` | ||
\end{examplefigure} | ||
|
||
You can customize the markers that indicate the bar directions. | ||
|
||
\begin{examplefigure}{} | ||
```julia | ||
using CairoMakie | ||
CairoMakie.activate!() # hide | ||
|
||
y = [6, 4, 2, -8, 3, 5, 1, -2, -3, 7] | ||
|
||
waterfall(y, show_direction=true, marker_pos=:cross, marker_neg=:hline, direction_color=:gold) | ||
``` | ||
\end{examplefigure} | ||
|
||
If the `dodge` attribute is provided, bars are stacked by `dodge`. | ||
|
||
\begin{examplefigure}{} | ||
```julia | ||
using CairoMakie | ||
CairoMakie.activate!() # hide | ||
colors = Makie.wong_colors() | ||
|
||
x = repeat(1:2, inner=5) | ||
y = [6, 4, 2, -8, 3, 5, 1, -2, -3, 7] | ||
group = repeat(1:5, outer=2) | ||
|
||
waterfall(x, y, dodge=group, color=colors[group]) | ||
``` | ||
\end{examplefigure} | ||
|
||
It can be easier to compare final results of different groups if they are shown in the background. | ||
|
||
\begin{examplefigure}{} | ||
```julia | ||
using CairoMakie | ||
CairoMakie.activate!() # hide | ||
colors = Makie.wong_colors() | ||
|
||
x = repeat(1:2, inner=5) | ||
y = [6, 4, 2, -8, 3, 5, 1, -2, -3, 7] | ||
group = repeat(1:5, outer=2) | ||
|
||
waterfall(x, y, dodge=group, color=colors[group], show_direction=true, show_final=true) | ||
``` | ||
\end{examplefigure} | ||
|
||
The color of the final bars in the background can be modified. | ||
|
||
\begin{examplefigure}{} | ||
```julia | ||
using CairoMakie | ||
CairoMakie.activate!() # hide | ||
colors = Makie.wong_colors() | ||
|
||
x = repeat(1:2, inner=5) | ||
y = [6, 4, 2, -8, 3, 5, 1, -2, -3, 7] | ||
group = repeat(1:5, outer=2) | ||
|
||
waterfall(x, y, dodge=group, color=colors[group], show_final=true, final_color=(colors[6], 1//3)) | ||
``` | ||
\end{examplefigure} | ||
|
||
You can also specify to stack grouped waterfall plots by `x`. | ||
|
||
\begin{examplefigure}{} | ||
```julia | ||
using CairoMakie | ||
CairoMakie.activate!() # hide | ||
colors = Makie.wong_colors() | ||
|
||
x = repeat(1:5, outer=2) | ||
y = [6, 4, 2, -8, 3, 5, 1, -2, -3, 7] | ||
group = repeat(1:2, inner=5) | ||
|
||
waterfall(x, y, dodge=group, color=colors[group], show_direction=true, stack=:x) | ||
``` | ||
\end{examplefigure} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
""" | ||
waterfall(x, y; kwargs...) | ||
Plots a [waterfall chart](https://en.wikipedia.org/wiki/Waterfall_chart) to visualize individual | ||
positive and negative components that add up to a net result as a barplot with stacked bars next | ||
to each other. | ||
## Attributes | ||
$(ATTRIBUTES) | ||
Furthermore the same attributes as for `barplot` are supported. | ||
""" | ||
@recipe(Waterfall, x, y) do scene | ||
return Attributes(; | ||
dodge=automatic, | ||
n_dodge=automatic, | ||
gap=0.2, | ||
dodge_gap=0.03, | ||
width=automatic, | ||
cycle=[:color => :patchcolor], | ||
stack=automatic, | ||
show_direction=false, | ||
marker_pos=:utriangle, | ||
marker_neg=:dtriangle, | ||
direction_color=theme(scene, :backgroundcolor), | ||
show_final=false, | ||
final_color=plot_color(:grey90, 0.5), | ||
final_gap=automatic, | ||
final_dodge_gap=0, | ||
) | ||
end | ||
|
||
conversion_trait(::Type{<:Waterfall}) = PointBased() | ||
|
||
function Makie.plot!(p::Waterfall) | ||
function stack_bars(xy, dodge, stack) | ||
x, y = first.(xy), last.(xy) | ||
if stack === automatic | ||
stack = dodge === automatic ? :x : :dodge | ||
end | ||
i_dodge = dodge === automatic ? ones(Int, length(x)) : dodge | ||
i_stack, i_group = stack === :dodge ? (i_dodge, x) : (x, i_dodge) | ||
xy = similar(xy) | ||
fillto = similar(x) | ||
final = similar(xy) | ||
groupby = StructArray(; grp=i_group) | ||
for (grp, inds) in StructArrays.finduniquesorted(groupby) | ||
fromto = stack_from_to_final(i_stack[inds], y[inds]) | ||
fillto[inds] .= fromto.from | ||
xy[inds] .= Point2f.(x[inds], fromto.to) | ||
final[inds] .= Point2f.(x[inds], fromto.final) | ||
end | ||
return (xy=xy, fillto=fillto, final=final) | ||
end | ||
|
||
fromto = lift(stack_bars, p[1], p.dodge, p.stack) | ||
|
||
if p.show_final[] | ||
final_gap = p.final_gap[] === automatic ? p.dodge[] == automatic ? 0 : p.gap : p.final_gap | ||
barplot!( | ||
p, | ||
lift(x -> x.final, fromto); | ||
dodge=p.dodge, | ||
color=p.final_color, | ||
dodge_gap=p.final_dodge_gap, | ||
gap=final_gap, | ||
) | ||
end | ||
|
||
barplot!( | ||
p, | ||
lift(x -> x.xy, fromto); | ||
p.attributes..., | ||
fillto=lift(x -> x.fillto, fromto), | ||
stack=automatic, | ||
) | ||
|
||
if p.show_direction[] | ||
function direction_markers( | ||
fromto, | ||
marker_pos, | ||
marker_neg, | ||
width, | ||
gap, | ||
dodge, | ||
n_dodge, | ||
dodge_gap, | ||
) | ||
xs = first( | ||
compute_x_and_width(first.(fromto.xy), width, gap, dodge, n_dodge, dodge_gap) | ||
) | ||
xy = similar(fromto.xy) | ||
shapes = fill(marker_pos, length(xs)) | ||
for i in eachindex(xs) | ||
y = last(fromto.xy[i]) | ||
fillto = fromto.fillto[i] | ||
xy[i] = (xs[i], (y + fillto) / 2) | ||
if fillto > y | ||
shapes[i] = marker_neg | ||
end | ||
end | ||
return (xy=xy, shapes=shapes) | ||
end | ||
|
||
markers = lift( | ||
direction_markers, | ||
fromto, | ||
p.marker_pos, | ||
p.marker_neg, | ||
p.width, | ||
p.gap, | ||
p.dodge, | ||
p.n_dodge, | ||
p.dodge_gap, | ||
) | ||
|
||
scatter!( | ||
p, | ||
lift(x -> x.xy, markers); | ||
marker=lift(x -> x.shapes, markers), | ||
color=p.direction_color) | ||
end | ||
|
||
return p | ||
end | ||
|
||
function stack_from_to_final(i_stack, y) | ||
order = 1:length(y) # save current order | ||
perm = sortperm(i_stack) # sort by i_stack | ||
inv_perm = sortperm(order[perm]) # restore original order | ||
from, to = stack_from_to_sorted(view(y, perm)) | ||
return (from=view(from, inv_perm), to=view(to, inv_perm), final=last(to)) | ||
end |
1c8d098
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JuliaRegistrator register
1c8d098
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Registration pull request created: JuliaRegistries/General/73325
After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.
This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:
1c8d098
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JuliaRegistrator register subdir=CairoMakie
1c8d098
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JuliaRegistrator register subdir=GLMakie
1c8d098
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Registration pull request created: JuliaRegistries/General/73327
After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.
This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:
1c8d098
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JuliaRegistrator register subdir=WGLMakie
1c8d098
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Registration pull request created: JuliaRegistries/General/73328
After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.
This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:
1c8d098
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JuliaRegistrator register subdir=RPRMakie
1c8d098
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Registration pull request created: JuliaRegistries/General/73329
After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.
This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:
1c8d098
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Registration pull request created: JuliaRegistries/General/73330
After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.
This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via: