Skip to content

Commit

Permalink
alpha aes
Browse files Browse the repository at this point in the history
  • Loading branch information
Mattriks committed Mar 4, 2019
1 parent 82922a3 commit 99f54e4
Show file tree
Hide file tree
Showing 18 changed files with 195 additions and 62 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ This is a log of major changes in Gadfly between releases. It is not exhaustive.
Each release typically has a number of minor bug fixes beyond what is listed here.

# Version 1.1.0
* Add `alpha` aesthetic, `Scale.alpha_continuous` and `Scale.alpha_discrete` (#1252)
* Add `limits=(min= , max= )` to `Stat.histogram` (#1249)
* Add dodged boxplots (#1246)
* Add `Stat.dodge` (#1240)
Expand Down
10 changes: 5 additions & 5 deletions docs/src/gallery/geometries.md
Original file line number Diff line number Diff line change
Expand Up @@ -412,13 +412,13 @@ x = -4:0.1:4
Da = [DataFrame(x=0:0.1:20, y=X[:,j], ymin=X[:,j].-0.5, ymax=X[:,j].+0.5, f="$f") for (j,f) in enumerate(["cos","sin"])]
Db = [DataFrame(x=x, ymax=pdf.(Normal(μ),x), ymin=0.0, u="μ=$μ") for μ in [-1,1] ]
# In the line below, 0.4 is the color opacity
p1 = plot(vcat(Da...), x=:x, y=:y, ymin=:ymin, ymax=:ymax, color=:f, Geom.line, Geom.ribbon,
Theme(lowlight_color=c->RGBA{Float32}(c.r, c.g, c.b, 0.4))
# In the line below, 0.6 is the color opacity
p1 = plot(vcat(Da...), x=:x, y=:y, ymin=:ymin, ymax=:ymax, color=:f,
Geom.line, Geom.ribbon, Theme(alphas=[0.6])
)
p2 = plot(vcat(Db...), x = :x, y=:ymax, ymin = :ymin, ymax = :ymax, color = :u,
p2 = plot(vcat(Db...), x = :x, y=:ymax, ymin = :ymin, ymax = :ymax,
color = :u, alpha=:u, Theme(alphas=[0.8,0.2]),
Geom.line, Geom.ribbon, Guide.ylabel("Density"),
Theme(lowlight_color=c->RGBA{Float32}(c.r, c.g, c.b, 0.4)),
Guide.colorkey(title="", pos=[2.5,0.6]), Guide.title("Parametric PDF")
)
hstack(p1,p2)
Expand Down
45 changes: 45 additions & 0 deletions docs/src/gallery/scales.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,50 @@
# Scales

## [`Scale.alpha_continuous`](@ref)

```@example
using Gadfly
set_default_plot_size(21cm, 8cm)
palettef = Scale.lab_gradient("darkgreen", "orange", "blue")
p1 = plot(x=1:10, y=rand(10), color=[1:10;], Geom.point,
Scale.color_continuous(colormap=palettef, minvalue=0, maxvalue=10),
Guide.title("Scale.color_continuous, Theme(alphas=[0.5])"),
Theme(alphas=[0.5], continuous_highlight_color=identity,
point_size=2mm)
)
p2 = plot(x=1:10, y=rand(10), alpha=[1:10;], Geom.point,
Scale.alpha_continuous(minvalue=0, maxvalue=10),
Guide.title("Scale.alpha_continuous, Theme(default_color=\"blue\")"),
Theme(default_color="blue", discrete_highlight_color=c->"gray",
point_size=2mm)
)
hstack(p1, p2)
```

## [`Scale.alpha_discrete`](@ref)

```@example
using DataFrames, Gadfly
set_default_plot_size(21cm, 8cm)
D = DataFrame(x=1:6, y=rand(6), Shape=repeat(["a","b","c"], outer=2))
coord = Coord.cartesian(xmin=0, xmax=7, ymin=0, ymax=1.0)
p1 = plot(D, x=:x, y=:y, color=:x, coord,
Scale.color_discrete, Geom.point, Geom.hair,
Guide.title("Scale.color_discrete, Theme(alphas=[0.5])"),
Theme(alphas=[0.5], discrete_highlight_color=identity,
point_size=2mm)
)
p2 = plot(D, x=:x, y=:y, alpha=:x, shape=:Shape, coord,
Scale.alpha_discrete, Geom.point, Geom.hair,
Guide.title("Scale.alpha_discrete, Theme(default_color=\"green\")"),
Theme(default_color="green", discrete_highlight_color=c->"gray",
point_size=2mm, alphas=[0.0,0.2,0.4,0.6,0.8,1.0])
)
hstack(p1,p2)
```



## [`Scale.color_continuous`](@ref)

```@example
Expand Down
13 changes: 5 additions & 8 deletions docs/src/gallery/statistics.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,15 @@ using Colors, DataFrames, Gadfly, Distributions
set_default_plot_size(21cm, 8cm)
x = -4:0.1:4
Da = [DataFrame(x=x, ymax=pdf.(Normal(μ),x), ymin=0.0, u="μ=$μ") for μ in [-1,1]]
Db = [DataFrame(x=randn(200).+μ, u="μ=$μ") for μ in [-1,1]]
Db = [DataFrame(x=randn(200).+μ, u="μ=$μ") for μ in [-1,1]]
p1 = plot(vcat(Da...), x=:x, y=:ymax, ymin=:ymin, ymax=:ymax, color=:u,
Geom.line, Geom.ribbon, Guide.ylabel("Density"),
Theme(lowlight_color=c->RGBA{Float32}(c.r, c.g, c.b, 0.4)),
Geom.line, Geom.ribbon, Guide.ylabel("Density"), Theme(alphas=[0.6]),
Guide.colorkey(title="", pos=[2.5,0.6]), Guide.title("Parametric PDF")
)
p2 = plot(vcat(Db...), x=:x, color=:u,
p2 = plot(vcat(Db...), x=:x, color=:u, Theme(alphas=[0.6]),
Stat.density(bandwidth=0.5), Geom.polygon(fill=true, preserve_order=true),
Coord.cartesian(xmin=-4, xmax=4),
Theme(lowlight_color=c->RGBA{Float32}(c.r, c.g, c.b, 0.4)),
Coord.cartesian(xmin=-4, xmax=4, ymin=0, ymax=0.4),
Guide.colorkey(title="", pos=[2.5,0.6]), Guide.title("Kernel PDF")
)
hstack(p1,p2)
Expand Down Expand Up @@ -88,8 +86,7 @@ p = plot(salaries[salaries.Rank.=="Prof",:], x=:YrsService, y=:Salary,
layer(Stat.smooth(method=:lm, levels=[0.95, 0.99]), Geom.line, Geom.ribbon)),
Scale.xgroup(levels=["Discipline A", "Discipline B"]),
Guide.colorkey(title="", pos=[0.43w, -0.4h]),
Theme(point_size=2pt,
lowlight_color=c->RGBA{Float32}(c.r, c.g, c.b, 0.2) )
Theme(point_size=2pt, alphas=[0.5])
)
```

Expand Down
6 changes: 4 additions & 2 deletions docs/src/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ All aesthetics (e.g. `x`, `y`, `color`) have a Scale e.g. `Scale.x_continuous()`
| `x` | `x_continuous` | `xticks` |
| `y` | `y_continuous` | `yticks` |
| `color` | `color_continuous` | `colorkey` |
| `size` | `size_continuous` | sizekey (tbd) |
| `size` | `size_continuous` | sizekey (tbd) |
| `alpha` | `alpha_continuous` | alphakey (tbd) |

e.g. `Scale.x_continuous(format= , minvalue= , maxvalue= )`\
`format` can be: `:plain`, `:scientific`, `:engineering`, or `:auto`.
Expand Down Expand Up @@ -213,7 +214,8 @@ hstack(p3, p4)
| `shape` | `shape_discrete` | `shapekey` |
| `size` | `size_discrete` | sizekey (tbd) |
| `linestyle` | `linestyle_discrete` | linekey (tbd) |
| `group` | `group_discrete` | |
| `alpha` | `alpha_discrete` | alphakey (tbd) |
| `group` | `group_discrete` | |
| `xgroup` | `xgroup` | |
| `ygroup` | `ygroup` | |

Expand Down
2 changes: 2 additions & 0 deletions src/Gadfly.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1146,6 +1146,7 @@ const default_aes_scales = Dict{Symbol, Dict}(
:size => Scale.size_continuous(),
:group => Scale.group_discrete(),
:label => Scale.label(),
:alpha => Scale.alpha_continuous(),
:linestyle => Scale.linestyle_discrete()
),

Expand All @@ -1166,6 +1167,7 @@ const default_aes_scales = Dict{Symbol, Dict}(
:size => Scale.size_discrete(),
:group => Scale.group_discrete(),
:label => Scale.label(),
:alpha => Scale.alpha_discrete(),
:linestyle => Scale.linestyle_discrete()
)
)
Expand Down
1 change: 1 addition & 0 deletions src/aesthetics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const NumericalAesthetic =
size, Union{CategoricalAesthetic,Vector,Nothing}
shape, Union{CategoricalAesthetic,Vector,Nothing}
color, Union{CategoricalAesthetic,Vector,Nothing}
alpha, NumericalOrCategoricalAesthetic
linestyle, Union{CategoricalAesthetic,Vector,Nothing}

label, CategoricalAesthetic
Expand Down
1 change: 1 addition & 0 deletions src/data.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
color
group
label
alpha
func
titles, Dict{Symbol, AbstractString}, Dict{Symbol, AbstractString}()
end
Expand Down
12 changes: 9 additions & 3 deletions src/geom/point.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ Draw scatter plots of the `x` and `y` aesthetics.
`Measures` of length(x) specifies the size of each data point explicitly. A
vector of length one specifies the size to use for all points. Default is
`Theme.point_size`.
- `alpha`: Categorical data will use the alpha palette in `Theme.alphas`.
Continuous data will remap from 0-1. Default is `Theme.alphas[1]`.
"""
const point = PointGeometry

element_aesthetics(::PointGeometry) = [:x, :y, :size, :color, :shape]
element_aesthetics(::PointGeometry) = [:x, :y, :size, :color, :shape, :alpha]

# Generate a form for a point geometry.
#
Expand All @@ -48,6 +50,7 @@ function render(geom::PointGeometry, theme::Gadfly.Theme, aes::Gadfly.Aesthetics
default_aes.shape = Function[Shape.circle]
default_aes.color = discretize_make_ia(RGBA{Float32}[theme.default_color])
default_aes.size = Measure[theme.point_size]
default_aes.alpha = [theme.alphas[1]]
aes = inherit(aes, default_aes)

if eltype(aes.size) <: Int
Expand All @@ -57,9 +60,11 @@ function render(geom::PointGeometry, theme::Gadfly.Theme, aes::Gadfly.Aesthetics
interpolate_size(x) = theme.point_size_min + (x-size_min) / size_range * point_size_range
end

aes_alpha = eltype(aes.alpha) <: Int ? theme.alphas[aes.alpha] : aes.alpha

ctx = context()

for (x, y, color, size, shape) in Compose.cyclezip(aes.x, aes.y, aes.color, aes.size, aes.shape)
for (x, y, color, size, shape, alpha) in Compose.cyclezip(aes.x, aes.y, aes.color, aes.size, aes.shape, aes_alpha)
shapefun = typeof(shape) <: Function ? shape : theme.point_shapes[shape]
sizeval = typeof(size) <: Int ? interpolate_size(size) : size
strokecolor = aes.color_key_continuous != nothing && aes.color_key_continuous ?
Expand All @@ -68,7 +73,8 @@ function render(geom::PointGeometry, theme::Gadfly.Theme, aes::Gadfly.Aesthetics
class = svg_color_class_from_label(aes.color_label([color])[1])
compose!(ctx, (context(),
(context(), shapefun([x], [y], [sizeval]), svgclass("marker")),
fill(color), stroke(strokecolor), svgclass(class)))
fill(color), stroke(strokecolor), fillopacity(alpha),
svgclass(class)))
end

compose!(ctx, linewidth(theme.highlight_width))
Expand Down
22 changes: 14 additions & 8 deletions src/geom/polygon.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ PolygonGeometry(default_statistic=Gadfly.Stat.identity(); order=0, fill=false, p
Geom.polygon[(; order=0, fill=false, preserve_order=false)]
Draw polygons with vertices specified by the `x` and `y` aesthetics.
Optionally plot multiple polygons according to the `group`, `color` and/or `linestyle`
Optionally plot multiple polygons according to the `group`, `color`, `linestyle`, and/or `alpha`
aesthetics. `order` controls whether the polygon(s) are underneath or on top
of other forms. If `fill=true`, fill the polygons using `Theme.lowlight_color` and stroke the polygons using
`Theme.discrete_highlight_color`. If `fill=false` stroke the polygons using `Theme.lowlight_color` and `Theme.line_style`.
Expand All @@ -22,7 +22,7 @@ around their centroid.
"""
const polygon = PolygonGeometry

element_aesthetics(::PolygonGeometry) = [:x, :y, :color, :group, :linestyle]
element_aesthetics(::PolygonGeometry) = [:x, :y, :color, :group, :linestyle, :alpha]

"""
Geom.ellipse[(; distribution=MvNormal, levels=[0.95], nsegments=51, fill=false)]
Expand Down Expand Up @@ -54,13 +54,14 @@ function render(geom::PolygonGeometry, theme::Gadfly.Theme, aes::Gadfly.Aestheti
default_aes.group = IndirectArray(fill(1,length(aes.x)))
default_aes.color = fill(theme.default_color, length(aes.x))
default_aes.linestyle = fill(1, length(aes.x))
default_aes.alpha = fill(1, length(aes.x))
aes = inherit(aes, default_aes)

aes_x, aes_y, aes_color, aes_linestyle, aes_group = concretize(aes.x, aes.y, aes.color, aes.linestyle, aes.group)
aes_x, aes_y, aes_color, aes_linestyle, aes_group, aes_alpha = concretize(aes.x, aes.y, aes.color, aes.linestyle, aes.group, aes.alpha)

XT, YT, CT, GT, LST = eltype(aes_x), eltype(aes_y), eltype(aes_color), eltype(aes_group), eltype(aes_linestyle)
XT, YT, CT, GT, LST, AT = eltype(aes_x), eltype(aes_y), eltype(aes_color), eltype(aes_group), eltype(aes_linestyle), eltype(aes_alpha)

groups = collect((Tuple{CT, GT, LST}), zip(aes_color, aes_group, aes_linestyle))
groups = collect((Tuple{CT, GT, LST, AT}), zip(aes_color, aes_group, aes_linestyle, aes_alpha))
ug = unique(groups)

n = length(ug)
Expand All @@ -69,20 +70,25 @@ function render(geom::PolygonGeometry, theme::Gadfly.Theme, aes::Gadfly.Aestheti
colors = Vector{CT}(undef, n)
line_styles = Vector{LST}(undef, n)
linestyle_palette_length = length(theme.line_style)
alphas = Vector{Float64}(undef, n)
alpha_discrete = AT <: Int

for (k,g) in enumerate(ug)
i = groups.==[g]
polys[k] = polygon_points(aes_x[i], aes_y[i], geom.preserve_order)
colors[k] = first(aes_color[i])
line_styles[k] = mod1(first(aes_linestyle[i]), linestyle_palette_length)
line_styles[k] = mod1(first(aes_linestyle[i]), linestyle_palette_length)
alphas[k] = first(alpha_discrete ? theme.alphas[aes_alpha[i]] : aes_alpha[i])
end

plinestyles = Gadfly.get_stroke_vector.(theme.line_style[line_styles])
pcolors = theme.lowlight_color.(colors)

properties = geom.fill ? (fill(pcolors), stroke(theme.discrete_highlight_color.(colors))) :
properties = geom.fill ? (fill(pcolors), stroke(theme.discrete_highlight_color.(colors)), fillopacity(alphas)) :
(fill(nothing), stroke(pcolors), strokedash(plinestyles))

ctx = compose!(context(order=geom.order), Compose.polygon(polys, geom.tag), properties...)
ctx = context(order=geom.order)
compose!(ctx, Compose.polygon(polys, geom.tag), properties...)

return compose!(ctx, linewidth(theme.line_width), svgclass("geometry"))
end
52 changes: 31 additions & 21 deletions src/geom/ribbon.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,46 @@ RibbonGeometry(default_statistic=Gadfly.Stat.identity(); fill=true, tag=empty_ta
RibbonGeometry(default_statistic, fill, tag)

"""
Geom.ribbon
Geom.ribbon[(; fill=true)]
Draw a ribbon at the positions in `x` bounded above and below by `ymax` and
`ymin`, respectively. Optionally draw multiple ribbons by grouping with `color`.
`ymin`, respectively. Optionally draw multiple ribbons by grouping with `color` and `alpha` (for `fill=true`),
or `color` and `linestyle` (for `fill=false`).
"""
const ribbon = RibbonGeometry

default_statistic(geom::RibbonGeometry) = geom.default_statistic

element_aesthetics(::RibbonGeometry) = [:x, :ymin, :ymax, :color, :linestyle]
element_aesthetics(::RibbonGeometry) = [:x, :ymin, :ymax, :color, :linestyle, :alpha]

function render(geom::RibbonGeometry, theme::Gadfly.Theme, aes::Gadfly.Aesthetics)
Gadfly.assert_aesthetics_defined("Geom.ribbon", aes, :x, :ymin, :ymax)
Gadfly.assert_aesthetics_equal_length("Geom.ribbon", aes,
element_aesthetics(geom)...)
Gadfly.assert_aesthetics_equal_length("Geom.ribbon", aes, element_aesthetics(geom)...)

default_aes = Gadfly.Aesthetics()
default_aes.linestyle = fill(1, length(aes.x))
default_aes.color = fill(theme.default_color, length(aes.x))
default_aes.alpha = fill(1, length(aes.x))
aes = inherit(aes, default_aes)

aes_x, aes_ymin, aes_ymax, aes_color, aes_linestyle = concretize(aes.x, aes.ymin, aes.ymax, aes.color, aes.linestyle)
XT, CT, LST = eltype(aes_x), eltype(aes_color), eltype(aes_linestyle)
aes_x, aes_ymin, aes_ymax, aes_color, aes_linestyle, aes_alpha =
concretize(aes.x, aes.ymin, aes.ymax, aes.color, aes.linestyle, aes.alpha)
XT, CT, LST, AT = eltype(aes_x), eltype(aes_color), eltype(aes_linestyle), eltype(aes_alpha)
YT = Float64
groups = collect((Tuple{CT, LST}), zip(aes_color, aes_linestyle))
groups = collect((Tuple{CT, LST, AT}), zip(aes_color, aes_linestyle, aes_alpha))
ug = unique(groups)

V = Vector{Tuple{XT, YT}}
K = Tuple{CT, LST}
K = Tuple{CT, LST, AT}

max_points = Dict{K, V}(g=>V[] for g in ug)
for (x, y, c, ls) in zip(aes_x, aes_ymax, aes_color, aes_linestyle)
push!(max_points[(c,ls)], (x, y))
for (x, y, c, ls, a) in zip(aes_x, aes_ymax, aes_color, aes_linestyle, aes_alpha)
push!(max_points[(c,ls,a)], (x, y))
end

min_points = Dict{K, V}(g=>V[] for g in ug)
for (x, y, c, ls) in zip(aes_x, aes_ymin, aes_color, aes_linestyle)
push!(min_points[(c,ls)], (x, y))
for (x, y, c, ls, a) in zip(aes_x, aes_ymin, aes_color, aes_linestyle, aes_alpha)
push!(min_points[(c,ls,a)], (x, y))
end

for k in keys(max_points)
Expand All @@ -56,14 +58,22 @@ function render(geom::RibbonGeometry, theme::Gadfly.Theme, aes::Gadfly.Aesthetic
polys = [collect(Tuple{XT, YT}, Iterators.flatten((min_points[k], max_points[k]))) for k in kys]
lines = [collect(Tuple{XT, YT}, Iterators.flatten((min_points[k], [(last(min_points[k])[1], NaN)], max_points[k]))) for k in kys]

colors = [theme.lowlight_color(c) for (c,ls) in kys]
linestyles = [Gadfly.get_stroke_vector(theme.line_style[ls]) for (c,ls) in kys]
n = length(kys)
colors = Vector{Union{Colorant, String}}(undef, n)
linestyles = Vector{Vector{Measure}}(undef, n)
alphas = Vector{Float64}(undef, n)
alpha_discrete = AT <: Int

ctx = geom.fill ? compose!(context(), Compose.polygon(polys, geom.tag), fill(colors)) :
compose!(context(), Compose.line(lines, geom.tag), fill(nothing), stroke(colors), strokedash(linestyles))
for (i, (c,ls,a)) in enumerate(kys)
colors[i] = theme.lowlight_color(c)
linestyles[i] = Gadfly.get_stroke_vector(theme.line_style[ls])
alphas[i] = alpha_discrete ? theme.alphas[a] : a
end

ctx = context()

geom.fill ? compose!(ctx, Compose.polygon(polys, geom.tag), fill(colors), fillopacity(alphas)) :
compose!(ctx, Compose.line(lines, geom.tag), fill(nothing), stroke(colors), strokedash(linestyles))

return compose!(
ctx,
svgclass("geometry"),
linewidth(theme.line_width))
return compose!(ctx, svgclass("geometry"), linewidth(theme.line_width))
end
9 changes: 3 additions & 6 deletions src/guide.jl
Original file line number Diff line number Diff line change
Expand Up @@ -250,11 +250,8 @@ function render_discrete_color_key(colors::Vector{C},
swatches_shapes = Shape.circle([0.5cy], 1:nrows, [swatch_size/2])
end
cs = colors[m+1:m+nrows]
swatches = compose!(
context(),
swatches_shapes,
stroke(nothing),
fill(cs))
swatches = compose!(context(), swatches_shapes, stroke(theme.discrete_highlight_color.(cs)),
fill(cs), fillopacity(theme.alphas[1]))

swatch_labels = compose!(
context(),
Expand Down Expand Up @@ -346,7 +343,7 @@ function render_continuous_color_key(colors::Dict,

fill([color_function((i-1) / (theme.key_color_gradations - 1))
for i in 1:theme.key_color_gradations]),
stroke(nothing),
stroke(nothing), fillopacity(theme.alphas[1]),
svgattribute("shape-rendering", "crispEdges")))

compose!(ctx,
Expand Down
3 changes: 2 additions & 1 deletion src/guide/keys.jl
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ function render_discrete_key(labels::Vector{String}, title_ctx::Context, title_w
clrs = colors[m+1:m+nrows]
shps = shapes[m+1:m+nrows]
swatches_shapes = [f(x, [y].*cy, [swatch_size/1.5]) for (y,f) in enumerate(shps)]
sw1 = [(context(), s, fill(c)) for (s,c) in zip(swatches_shapes, clrs)]
sw1 = [(context(), s, fill(c), fillopacity(theme.alphas[1]), stroke(theme.discrete_highlight_color(c)))
for (s,c) in zip(swatches_shapes, clrs)]
swatches = compose!(context(), sw1...)

swatch_labels = compose!(
Expand Down
Loading

0 comments on commit 99f54e4

Please sign in to comment.