Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

color2 #1436

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

color2 #1436

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Each release typically has a number of minor bug fixes beyond what is listed her

# Version 1.x

* Add aesthetic `color2`, a second color scale (#1436)
* Enable `color` aesthetic for `Stat.qq` (#1434)
* Add `Geom.bar(position=:identity)` + alpha enabled (#1428)
* Enable stacked guides (#1423)
Expand Down
18 changes: 18 additions & 0 deletions docs/src/gallery/guides.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,24 @@ hstack(pa, pb)
```


## [`Guide.color2key`](@ref)
```@example
using Gadfly, RDatasets
set_default_plot_size(14cm, 9cm)

iris = dataset("datasets","iris")
gp = Geom.polygon(preserve_order=true, fill=true)
plot(iris,
layer(x=:SepalLength, y=:SepalWidth, color2=:Species, alpha=[1.0]),
layer(x=:SepalLength, y=:SepalWidth, gp, order=1,
Stat.density2d(levels=[0.05:0.05:0.4;]),
Theme(alphas=[0.15], lowlight_color=identity)),
Scale.color_continuous,
Guide.colorkey, Guide.color2key(title="Iris"),
Theme(point_size=3pt, key_swatch_shape=Shape.circle, alphas=[0.7]))
```


## [`Guide.manual_color_key`](@ref)

```@example
Expand Down
21 changes: 15 additions & 6 deletions docs/src/gallery/scales.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,21 @@ hstack(pa,pb)
## [`Scale.color_none`](@ref)

```@example
using Gadfly
set_default_plot_size(21cm, 8cm)
xs = ys = 1:10.
zs = Float64[x^2*log(y) for x in xs, y in ys]
p1 = plot(x=xs, y=ys, z=zs, Geom.contour);
p2 = plot(x=xs, y=ys, z=zs, Geom.contour, Scale.color_none);
using Gadfly, RDatasets
set_default_plot_size(21cm, 9cm)

iris = dataset("datasets", "iris")
p1 = plot(iris, x=:SepalLength, y=:SepalWidth, color2=:Species,
layer(Geom.density2d(levels=[0.1:0.1:0.4;]), order=1),
Geom.point, Scale.color_continuous,
Guide.colorkey, Guide.color2key(title="Iris"),
Theme(point_size=3pt, key_swatch_shape=Shape.circle, line_width=1.5pt)
)
p2 = plot(iris, x=:SepalLength, y=:SepalWidth, color2=:Species,
layer(Geom.density2d(levels=[0.1:0.1:0.4;]), order=1),
Geom.point, Scale.color_none, Guide.color2key(title="Iris"),
Theme(default_color="gray", point_size=3pt, key_swatch_shape=Shape.circle)
)
hstack(p1,p2)
```

Expand Down
1 change: 1 addition & 0 deletions docs/src/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ hstack(p3, p4)
| `x` | `x_discrete` | `xticks` | |
| `y` | `y_discrete` | `yticks` | |
| `color` | `color_discrete` | `colorkey` | (tbd) |
| `color2` | `color2_discrete` | `color2key` | `color2s` |
| `shape` | `shape_discrete` | `shapekey` | `point_shapes` |
| `size` | `size_discrete` | --- | `point_size_min`, `point_size_max` |
| | `size_discrete2`| `sizekey` | `discrete_sizemap` |
Expand Down
8 changes: 5 additions & 3 deletions src/Gadfly.jl
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ function render_prepare(plot::Plot)
datas..., subplot_datas...)

# set defaults for key titles
keyvars = [:color, :shape, :size]
keyvars = [:color, :shape, :size, :color2]
for (i, layer) in enumerate(plot.layers)
for kv in keyvars
fflag = (getfield(layer_aess[i], Symbol(kv,"_key_title")) == nothing) && haskey(layer.mapping, kv) && !isa(layer.mapping[kv], AbstractArray)
Expand Down Expand Up @@ -704,7 +704,7 @@ function render_prepare(plot::Plot)
Stat.apply_statistics(statistics, scales, coord, plot_aes)

# Add some default guides determined by defined aesthetics
keytypes = [Guide.ColorKey, Guide.ShapeKey, Guide.SizeKey]
keytypes = [Guide.ColorKey, Guide.ShapeKey, Guide.SizeKey, Guide.Color2Key]
supress_keys = false
for layer in plot.layers
if isa(layer.geom, Geom.SubplotGeometry) && any(haskey.((layer.geom.guides,), keytypes))
Expand Down Expand Up @@ -1136,6 +1136,7 @@ const default_aes_scales = Dict{Symbol, Dict}(
:shape => Scale.shape_identity(),
:size => Scale.size_identity(),
:color => Scale.color_identity(),
:color2 => Scale.color2_identity()
),

:numerical => Dict{Symbol, Any}(
Expand Down Expand Up @@ -1184,7 +1185,8 @@ const default_aes_scales = Dict{Symbol, Dict}(
:group => Scale.group_discrete(),
:label => Scale.label(),
:alpha => Scale.alpha_discrete(),
:linestyle => Scale.linestyle_discrete()
:linestyle => Scale.linestyle_discrete(),
:color2 => Scale.color2_discrete()
)
)

Expand Down
3 changes: 3 additions & 0 deletions src/aesthetics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const NumericalOrCategoricalAesthetic =
color, Union{CategoricalAesthetic,Vector,Nothing}
alpha, NumericalOrCategoricalAesthetic
linestyle, Union{CategoricalAesthetic,Vector,Nothing}
color2, Union{IndirectArray, Vector, Nothing}

label, CategoricalAesthetic
group, CategoricalAesthetic
Expand Down Expand Up @@ -66,6 +67,7 @@ const NumericalOrCategoricalAesthetic =
shape_key_title, Maybe(AbstractString)
size_key_title, Maybe(AbstractString)
size_key_vals, Maybe(AbstractDict)
color2_key_title, Maybe(AbstractString)

# mark some ticks as initially invisible
xtickvisible, Maybe(Vector{Bool})
Expand All @@ -91,6 +93,7 @@ const NumericalOrCategoricalAesthetic =
ygroup_label, Function, showoff
shape_label, Function, showoff
size_label, Function, showoff
color2_label, Function, showoff

# pseudo-aesthetics
pad_categorical_x, Union{Missing,Bool}, missing
Expand Down
1 change: 1 addition & 0 deletions src/data.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
xsize
ysize
color
color2
group
label
alpha
Expand Down
9 changes: 7 additions & 2 deletions src/geom/point.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Draw scatter plots of the `x` and `y` aesthetics.
"""
const point = PointGeometry

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

# Generate a form for a point geometry.
#
Expand Down Expand Up @@ -64,10 +64,15 @@ function render(geom::PointGeometry, theme::Gadfly.Theme, aes::Gadfly.Aesthetics
end

aes_alpha = eltype(aes.alpha) <: Int ? theme.alphas[aes.alpha] : aes.alpha
aes_color = if aes.color2 !== nothing
eltype(aes.color2) <: Int ? theme.color2s[aes.color2] : aes.color2
else
aes.color
end

ctx = context()

for (x, y, color, size, shape, alpha) in Compose.cyclezip(aes.x, aes.y, aes.color, aes_size, aes.shape, aes_alpha)
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]
strokecolor = aes.color_key_continuous != nothing && aes.color_key_continuous ?
theme.continuous_highlight_color(color) :
Expand Down
53 changes: 52 additions & 1 deletion src/guide/keys.jl
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ SizeKey(v::Nothing) = SizeKey(visible=false)
SizeKey(title::AbstractString, labels::Vector{String}, pos::Vector) = SizeKey(title, labels, pos, true)

"""
Guide.sizekey[(; title="size", labels=String[], pos=[])]
Guide.sizekey[(; title="Size", labels=String[], pos=[])]
Guide.sizekey(title, labels, pos)

Enable control of the sizekey. Set the key `title` and the item `labels`.
Expand Down Expand Up @@ -260,3 +260,54 @@ function render(guide::SizeKey, theme::Gadfly.Theme, aes::Gadfly.Aesthetics)
end



struct Color2Key <: Gadfly.GuideElement
title::AbstractString
labels::Vector{String}
pos::Vector
visible::Bool
end
Color2Key(;title="Color2", labels=String[], pos=Float64[], visible=true) = Color2Key(title, labels, pos, visible)
Color2Key(v::Nothing) = Color2Key(visible=false)
Color2Key(title::AbstractString, labels::Vector{String}, pos::Vector) = Color2Key(title, labels, pos, true)

"""
Guide.color2key[(; title="Color2", labels=String[], pos=[])]
Guide.color2key(title, labels, pos)

Enable control of the color2key. Set the key `title` and the item `labels`.
`pos` overrides [Theme(key_position=)](@ref Gadfly) and can be in either
relative (e.g. [0.7w, 0.2h] is the lower right quadrant), absolute (e.g. [0mm,
0mm]), or plot scale (e.g. [0,0]) coordinates. `Guide.color2key(nothing)` will hide the key.
"""
const color2key = Color2Key

function render(guide::Color2Key, theme::Gadfly.Theme, aes::Gadfly.Aesthetics)

(theme.key_position==:none || !guide.visible || (eltype(aes.color2)<:Colorant)) && return PositionedGuide[]
gpos = guide.pos
(theme.key_position==:inside) && isempty(gpos) && (gpos = [0.7w, 0.25h])

# Aesthetics for keys: color2_key_title, color2_label (Function)
ncolors = length(unique(aes.color2))
guide_title = (guide.title≠"Color2" || aes.color2_key_title==nothing) ? guide.title : aes.color2_key_title
color2_key_labels = isempty(guide.labels) ? aes.color2_label(1:ncolors) : guide.labels

title_context, title_width = render_key_title2(guide_title, theme)
ctxs = render_discrete_key(color2_key_labels, title_context, title_width, theme, colors=theme.color2s[1:ncolors])

position, stackable = right_guide_position, true
if !isempty(gpos)
position, stackable = over_guide_position, false
ctxs = [compose(context(), (context(gpos[1],gpos[2]), ctxs[1]))]
elseif theme.key_position == :left
position = left_guide_position
elseif theme.key_position == :top
position = top_guide_position
elseif theme.key_position == :bottom
position = bottom_guide_position
end

return [PositionedGuide(ctxs, 0, position, stackable)]
end

18 changes: 16 additions & 2 deletions src/scale.jl
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,15 @@ alpha_discrete(; labels=nothing, levels=nothing, order=nothing) =
@doc type_discrete_docstr("linestyle") linestyle_discrete(; labels=nothing, levels=nothing, order=nothing) =
DiscreteScale([:linestyle], labels=labels, levels=levels, order=order)

"""
color2_discrete[(; labels=nothing, levels=nothing, order=nothing)]

Similar to [`Scale.x_discrete`](@ref), except applied to the `color2` aesthetic. The color2 palette
is set by `Theme(color2s=[])`.
"""
color2_discrete(; labels=nothing, levels=nothing, order=nothing) =
DiscreteScale([:color2], labels=labels, levels=levels, order=order)


function apply_scale(scale::DiscreteScale, aess::Vector{Gadfly.Aesthetics}, datas::Gadfly.Data...)

Expand Down Expand Up @@ -751,8 +760,9 @@ element_aesthetics(scale::IdentityScale) = [scale.var]
function apply_scale(scale::IdentityScale,
aess::Vector{Gadfly.Aesthetics}, datas::Gadfly.Data...)
for (aes, data) in zip(aess, datas)
getfield(data, scale.var) === nothing && continue
setfield!(aes, scale.var, getfield(data, scale.var))
datavar = getfield(data, scale.var)
datavar===nothing && continue
setfield!(aes, scale.var, datavar)
end
end

Expand Down Expand Up @@ -787,6 +797,10 @@ shape_identity() = IdentityScale(:shape)
"""
size_identity() = IdentityScale(:size)

"""
color2_identity()
"""
color2_identity() = IdentityScale(:color2)

include("scale/scales.jl")

Expand Down
3 changes: 3 additions & 0 deletions src/theme.jl
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ $(FIELDS)
"Alpha palette. The default palette is [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0]. Customize using a Vector of length one or greater, with 0.0≤values≤1.0",
alphas, Vector{Float64}, [1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0]

"Discrete colors for `color2`. The default palette is `Scale.default_discrete_colors(50)`. Customize using a `Vector{<:Color}`.",
color2s, (Vector{<:Color}), Scale.default_discrete_colors(50)

"Background color used in the main plot panel. (Color or Nothing)",
panel_fill, ColorOrNothing, nothing

Expand Down
29 changes: 29 additions & 0 deletions test/testscripts/scale_color2.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Gadfly, RDatasets

set_default_plot_size(6.6inch, 4inch)

quakes = dataset("datasets", "quakes")
quakes.Richter = floor.(Int, quakes.Mag)
m = Matrix(quakes[:,[2,1]])
X = [ones(1000) m m.^2]
B = X'X \ X'quakes.Depth
fn(x,y) = ([1 x y x^2 y^2]*B)[1]

# p1 is an example of Scale.color2_identity
p1 = plot(quakes, x=:Depth, y=:Mag,
layer(x=:Depth, y=:Mag, color2=[colorant"gray"], alpha=[0.3], size=[2pt]),
layer(Geom.density2d(levels=7), order=1), Scale.color_continuous,
Theme(key_position=:none)
)

p2 = plot(quakes,
layer(x=:Long, y=:Lat, color2=:Richter, alpha=[0.7]),
layer(fn, 165, 190, -40, 0, Stat.contour(levels=[0:250:1500;])),
Scale.color_continuous(minvalue=0),
Scale.color2_discrete(levels=[4,5,6]),
Guide.colorkey(title="Depth"),
Theme(point_size=1.5pt, key_swatch_shape=Shape.circle,
discrete_highlight_color=c->nothing)
)

hstack(p1, p2)
2 changes: 2 additions & 0 deletions test/testscripts/shape_hvline.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Gadfly

set_default_plot_size(6inch, 3inch)

hstack(plot(y=[1,2,3],shape=[Shape.vline], Theme(discrete_highlight_color=x->x)),
plot(y=[1,2,3],shape=[Shape.hline], Theme(discrete_highlight_color=x->x)))