diff --git a/src/geom/hvabline.jl b/src/geom/hvabline.jl index 501ece73d..70f5248a1 100755 --- a/src/geom/hvabline.jl +++ b/src/geom/hvabline.jl @@ -157,17 +157,15 @@ function render(geom::ABLineGeometry, theme::Gadfly.Theme, aes::Gadfly.Aesthetic # the line extends to the edges of the graph. if typeof(aes.y) <: Array{Function} - low, high = aes.xmin[1], aes.xmax[1] + lowx, highx = aes.xmin[1], aes.xmax[1] else - xextrema = extrema(aes.x) - yextrema = extrema(aes.y) - low = min(xextrema[1], yextrema[1]) - high = max(xextrema[2], yextrema[2]) + lowx, highx = extrema(aes.x) end - range = high-low - x0 = low-range - x1 = high+range + # extending the line to width 3 times x-range of data should be enough + rangex = highx - lowx + x0 = lowx - rangex + x1 = highx + rangex y0s = [x0 * m + b for (m,b) in zip(aes.slope, aes.intercept)] y1s = [x1 * m + b for (m,b) in zip(aes.slope, aes.intercept)] diff --git a/src/scale.jl b/src/scale.jl index 4936e3e9a..c0ed842ea 100644 --- a/src/scale.jl +++ b/src/scale.jl @@ -600,26 +600,13 @@ const color_continuous_gradient = color_continuous ### WHY HAVE THIS ALIAS? function apply_scale(scale::ContinuousColorScale, aess::Vector{Gadfly.Aesthetics}, datas::Gadfly.Data...) - cmin, cmax = Inf, -Inf - for data in datas - data.color === nothing && continue - - for c in data.color - ismissing(c) && continue - - c = convert(Float64, c) - if c < cmin - cmin = c - end - - if c > cmax - cmax = c - end - end + cdata = skipmissing(Iterators.flatten(i.color for i in datas if i.color != nothing)) + if !isempty(cdata) + cmin, cmax = extrema(cdata) + else + return end - (cmin == Inf || cmax == -Inf) && return - if scale.minvalue != nothing cmin = scale.minvalue end @@ -671,11 +658,11 @@ function apply_scale(scale::ContinuousColorScale, end function apply_scale_typed!(ds, field, scale::ContinuousColorScale, - cmin::Float64, cspan::Float64) + cmin, cspan) for (i, d) in enumerate(field) if isconcrete(d) ds[i] = convert(RGB{Float32}, - scale.f((convert(Float64, scale.trans.f(d)) - cmin) / cspan)) + scale.f((scale.trans.f(d) - cmin) / cspan)) else ds[i] = missing end diff --git a/src/ticks.jl b/src/ticks.jl index 3eee01765..aae6954d5 100644 --- a/src/ticks.jl +++ b/src/ticks.jl @@ -2,7 +2,7 @@ # little opaque because I want to avoid assuming the log function is defined # over typeof(xspan) function bounding_order_of_magnitude(xspan::DT) where DT - one_dt = convert(DT, one(DT)) + one_dt = oneunit(DT) a = 1 step = 1 @@ -69,7 +69,7 @@ function optimize_ticks_typed(x_min::T, x_max::T, extend_ticks, granularity_weight::Float64, simplicity_weight::Float64, coverage_weight::Float64, niceness_weight::Float64, strict_span) where T - one_t = convert(T, one(T)) + one_t = oneunit(T) if x_max - x_min < eps()*one_t R = typeof(1.0 * one_t) return R[x_min], x_min - one_t, x_min + one_t diff --git a/test/REQUIRE b/test/REQUIRE index 91456cd49..60d3fb990 100644 --- a/test/REQUIRE +++ b/test/REQUIRE @@ -2,3 +2,4 @@ DataFrames RDatasets Cairo CSV +Unitful diff --git a/test/testscripts/percent.jl b/test/testscripts/percent.jl index 48d3a79c2..49b8c0bdb 100644 --- a/test/testscripts/percent.jl +++ b/test/testscripts/percent.jl @@ -2,7 +2,7 @@ using Gadfly set_default_plot_size(6inch, 6inch) -import Base: show, +, -, /, *, isless, one, zero, isfinite +import Base: convert, show, +, -, /, *, isless, one, zero, isfinite struct Percent value::Float64 @@ -23,6 +23,7 @@ isless(a::Percent, b::Percent) = isless(a.value, b.value) one(::Type{Percent}) = Percent(0.01) zero(::Type{Percent}) = Percent(0.0) isfinite(a::Percent) = isfinite(a.value) +convert(::Type{Float64}, x::Percent) = x.value show(io::IO, p::Percent) = print(io, round(100 * p.value, digits=4), "%") y=[Percent(0.1), Percent(0.2), Percent(0.3)] diff --git a/test/testscripts/unitful_basic.jl b/test/testscripts/unitful_basic.jl new file mode 100644 index 000000000..8324ac22f --- /dev/null +++ b/test/testscripts/unitful_basic.jl @@ -0,0 +1,19 @@ +using Unitful, Gadfly, DataFrames + +a = -9.81u"m/s^2" +t = (1:0.5:10)u"s" +v = a .* t +v2 = v .+ 2u"m/s" +h = 0.5 * a .* t.^2 +df = DataFrame(time=t, velocity=v, position=h, + unitlesst=ustrip.(t), unitlessv=ustrip.(v), unitlessh=ustrip.(h), + position2=reverse(h)) + +# test basics of point/line plots with Unitful +gridstack(reshape([plot(df, x=:time, y=:velocity), + plot(df, x=:position, y=:time), + plot(df, x=:unitlesst, y=:velocity), + plot(df, x=:time, y=:unitlessh), + plot(df, x=:time, y=:position, Geom.line), + plot(df, layer(x=:time, y=:position, Geom.line), + layer(x=:time, y=:position2))], (3,2))) diff --git a/test/testscripts/unitful_color.jl b/test/testscripts/unitful_color.jl new file mode 100644 index 000000000..3a2e99229 --- /dev/null +++ b/test/testscripts/unitful_color.jl @@ -0,0 +1,15 @@ +using Unitful, Gadfly, DataFrames + +a = -9.81u"m/s^2" +t = (1:0.5:10)u"s" +v = a .* t +v2 = v .+ 2u"m/s" +h = 0.5 * a .* t.^2 +df = DataFrame(time=t, velocity=v, position=h, + unitlesst=ustrip.(t), unitlessv=ustrip.(v), unitlessh=ustrip.(h), + position2=reverse(h)) + +# Test that it's possible to categorize by Unitful quantities +vstack(plot(df, x=:time, y=:position, color=:velocity, Geom.point), + plot(df, x=:time, y=:velocity, color=:position, Geom.line), + plot(df, x=:time, y=:position, color=:unitlessv)) diff --git a/test/testscripts/unitful_geoms.jl b/test/testscripts/unitful_geoms.jl new file mode 100644 index 000000000..1787be49c --- /dev/null +++ b/test/testscripts/unitful_geoms.jl @@ -0,0 +1,26 @@ +using Unitful, Gadfly, DataFrames + +a = -9.81u"m/s^2" +t = (1:0.5:10)u"s" +v = a .* t +v2 = v .+ 2u"m/s" +h = 0.5 * a .* t.^2 +df = DataFrame(time=t, velocity=v, position=h, + unitlesst=ustrip.(t), unitlessv=ustrip.(v), unitlessh=ustrip.(h), + position2=reverse(h)) + +# Test various geometries with Unitful +p1 = plot(df, x=:time, y=:velocity, Geom.bar) +p2 = plot(df, x=:time, y=:position, Geom.point, + intercept=[-80u"m"], slope=[10u"m/s"], Geom.abline) +p3 = plot(df, x=:time, y=:velocity, Geom.line, + yintercept=[-20u"m/s", -40u"m/s"], Geom.hline) +# Currently explicitly stated that it loess and lm require arrays of plain numbers +#p4 = plot(df, x=:time, y=:position, Geom.point, +# Geom.smooth(method=:loess, smoothing=0.2)) +p4 = plot(df, x=:position, y=:velocity, Geom.path) +p5 = plot(df, x=:time, y=:position, Geom.step, + xintercept=[3u"s", 8u"s"], Geom.vline) +p6 = plot(df, layer(x=:time, y=:position, Geom.line), + layer(x=:time, y=:position2, Geom.bar)) +gridstack(reshape([p1,p2,p3,p4,p5,p6], (2,3)))