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

Segment Geometry #823

Merged
merged 1 commit into from
Sep 1, 2016
Merged
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
49 changes: 49 additions & 0 deletions doc/geom_segment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
title: segment
author: Mattriks
part: Geometry
order: 1019
...
Draw separate line segments/vectors/arrows.
Note that if you want arrows, then you need to provide a `Scale` object for both axes. See example below.

# Aesthetics

* `x`: Start of line segment.
* `y`: Start of line segment.
* `xend`: End of line segment.
* `yend`: End of line segment.
* `color` (optional): Color of line segments.

# Arguments

* `arrow`: Default behavior for `Geom.segment` is to draw line segments without arrows.
`Geom.vector()` is `Geom.segment(arrow=true)`.


# Examples

```{.julia hide="true" results="none"}
using RDatasets
using Gadfly

Gadfly.set_default_plot_size(6.6inch, 6.6inch)
```

```julia
seals = RDatasets.dataset("ggplot2","seals")
seals[:Latb] = seals[:Lat] + seals[:DeltaLat]
seals[:Longb] = seals[:Long] + seals[:DeltaLong]
seals[:Angle] = atan2(seals[:DeltaLat], seals[:DeltaLong])

coord = Coord.cartesian(xmin=-175.0, xmax=-119, ymin=29, ymax=50)
# Geom.vector also needs scales for both axes:
xsc = Scale.x_continuous(minvalue=-175.0, maxvalue=-119)
ysc = Scale.y_continuous(minvalue=29, maxvalue=50)
colsc = Scale.color_continuous(minvalue=-3, maxvalue=3)

layer1 = layer(seals, x=:Long, y=:Lat, xend=:Longb, yend=:Latb, Geom.vector, color=:Angle)

plot(layer1, xsc, ysc, colsc, coord)
```

6 changes: 5 additions & 1 deletion src/Gadfly.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1124,7 +1124,9 @@ const default_aes_scales = @compat Dict{Symbol, Dict}(
:numerical => Dict{Symbol, Any}(:x => Scale.x_continuous(),
:xmin => Scale.x_continuous(),
:xmax => Scale.x_continuous(),
:xintercept => Scale.x_continuous(),
:xintercept => Scale.x_continuous(),
:xend => Scale.x_continuous(),
:yend => Scale.y_continuous(),
:y => Scale.y_continuous(),
:ymin => Scale.y_continuous(),
:ymax => Scale.y_continuous(),
Expand All @@ -1145,6 +1147,8 @@ const default_aes_scales = @compat Dict{Symbol, Dict}(
:xmin => Scale.x_discrete(),
:xmax => Scale.x_discrete(),
:xintercept => Scale.x_discrete(),
:xend => Scale.x_discrete(),
:yend => Scale.y_discrete(),
:y => Scale.y_discrete(),
:ymin => Scale.y_discrete(),
:ymax => Scale.y_discrete(),
Expand Down
2 changes: 2 additions & 0 deletions src/aesthetics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ typealias NumericalAesthetic
x, @compat(Union{NumericalOrCategoricalAesthetic, Distribution})
y, @compat(Union{NumericalOrCategoricalAesthetic, Distribution})
z, @compat(Union{(@compat Void), Function, Matrix})
xend, NumericalAesthetic
yend, NumericalAesthetic
size, Maybe(Vector{Measure})
shape, CategoricalAesthetic
color, Maybe(@compat(Union{AbstractVector{RGBA{Float32}},
Expand Down
2 changes: 2 additions & 0 deletions src/data.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
x
y
z
xend
yend
xmin
xmax
ymin
Expand Down
117 changes: 117 additions & 0 deletions src/geom/segment.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@

abstract SegmentGeometry <: Gadfly.GeometryElement

# Geometry for vectors/arrows/segments
immutable SegmentGeom <: SegmentGeometry

arrow::Bool
filled::Bool
tag::Symbol

function SegmentGeom(;arrow=false, filled=false, tag=empty_tag)
new(arrow, filled, tag)
end
end

const segment = SegmentGeom

# Leave this as a function, pending extra arguments e.g. arrow attributes
function vector(;filled::Bool=false, tag::Symbol=empty_tag)
return SegmentGeom(arrow=true, filled=filled, tag=tag)
end


function element_aesthetics(::SegmentGeom)
return [:x, :y, :xend, :yend, :color]
end


function Gadfly.render(geom::SegmentGeom, theme::Gadfly.Theme, aes::Gadfly.Aesthetics,
subplot_layer_aess::@compat(Union{(@compat Void), Vector{Gadfly.Aesthetics}}),
subplot_layer_datas::@compat(Union{(@compat Void), Vector{Gadfly.Data}}),
scales::Dict{Symbol, Gadfly.ScaleElement})
render(geom, theme, aes, scales)
end





function render(geom::SegmentGeom, theme::Gadfly.Theme, aes::Gadfly.Aesthetics,
scales::Dict{Symbol, Gadfly.ScaleElement})

Gadfly.assert_aesthetics_defined("Geom.segment", aes, :x, :y, :xend, :yend)

function arrow{T<:Real}(x::T, y::T, xmax::T, ymax::T, xyrange::Vector{T})
dx = xmax-x
dy = ymax-y
vl = 0.225*hypot(dy/xyrange[2], dx/xyrange[1])
θ = atan2(dy/xyrange[2], dx/xyrange[1])
ϕ = pi/15
xr = -vl*xyrange[1]*[cos(θ+ϕ), cos(θ-ϕ)]
yr = -vl*xyrange[2]*[sin(θ+ϕ), sin(θ-ϕ)]
arr = [(xmax+xr[1],ymax+yr[1]), (xmax,ymax), (xmax+xr[2],ymax+yr[2]) ]
return arr
end

n = length(aes.x)
color = ColorTypes.RGBA{Float32}(theme.default_color)
default_aes = Gadfly.Aesthetics()
default_aes.color = DataArrays.DataArray(fill(color,n))

aes = inherit(aes, default_aes)

# line_style = Gadfly.get_stroke_vector(theme.line_style)
line_style = theme.line_style
if is(line_style, nothing)
line_style = []
end


# Geom.vector requires information about scales

if geom.arrow
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the top-level if statement necessary because render doesn't get scale information right now? Because this looks a bit hacky.

xscale = scales[:x]
yscale = scales[:y]
check = [xscale.minvalue, xscale.maxvalue, yscale.minvalue, yscale.maxvalue]
if any( map(x -> is(x,nothing), check) )
error("For Geom.vector, Scale minvalue and maxvalue must be manually provided for both axes")
end
fx = xscale.trans.f
fy = yscale.trans.f
xyrange = [fx(xscale.maxvalue)-fx(xscale.minvalue),
fy(yscale.maxvalue)-fy(yscale.minvalue)]

arrows = [ arrow(x, y, xend, yend, xyrange)
for (x, y, xend, yend) in zip(aes.x, aes.y, aes.xend, aes.yend) ]

end


segments = [ [(x,y), (xend,yend)]
for (x, y, xend, yend) in zip(aes.x, aes.y, aes.xend, aes.yend) ]

classes = [string("geometry ", svg_color_class_from_label( aes.color_label([c])[1] ))
for c in aes.color ]

ctx = context()

compose!( ctx, Compose.line(segments, geom.tag), stroke(aes.color), linewidth(theme.line_width),
strokedash(line_style), svgclass( classes ) )
if geom.arrow
if geom.filled
compose!(ctx, (context(), Compose.polygon(arrows), fill(aes.color), strokedash([])) )
else
compose!(ctx, (context(), Compose.line(arrows), stroke(aes.color), linewidth(theme.line_width),
strokedash([])) )
end
end


return ctx
end





1 change: 1 addition & 0 deletions src/geometry.jl
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,6 @@ include("geom/ribbon.jl")
include("geom/violin.jl")
include("geom/polygon.jl")
include("geom/beeswarm.jl")
include("geom/segment.jl")

end # module Geom
4 changes: 2 additions & 2 deletions src/scale.jl
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,10 @@ function make_labeler(scale::ContinuousScale)
end


const x_vars = [:x, :xmin, :xmax, :xintercept, :xviewmin, :xviewmax]
const x_vars = [:x, :xmin, :xmax, :xintercept, :xviewmin, :xviewmax, :xend]
const y_vars = [:y, :ymin, :ymax, :yintercept, :middle,
:upper_fence, :lower_fence, :upper_hinge, :lower_hinge,
:yviewmin, :yviewmax]
:yviewmin, :yviewmax, :yend]

function continuous_scale_partial(vars::Vector{Symbol},
trans::ContinuousScaleTransform)
Expand Down
3 changes: 2 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ tests = [
("rug", 6inch, 3inch),
("beeswarm", 6inch, 3inch),
("issue871", 6inch, 3inch),
("issue882", 6inch, 3inch)
("issue882", 6inch, 3inch),
("vector", 3.3inch, 3.3inch)
]


Expand Down
14 changes: 14 additions & 0 deletions test/vector.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@


using DataFrames, Gadfly


srand(123)
D = convert(DataFrame, 99*rand(4, 4)+0.5)

xsc = Scale.x_continuous(minvalue=0.0, maxvalue=100)
ysc = Scale.y_continuous(minvalue=0.0, maxvalue=100)

plot(D, x=:x1, y=:x2, xend=:x3, yend=:x4, Geom.segment(arrow=true), xsc, ysc)
plot(D, x=:x1, y=:x2, xend=:x3, yend=:x4, Geom.vector, xsc, ysc)