From 7531c48e3871fc74fe8acdadbdd9ce34b2eade5d Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Wed, 16 Mar 2016 13:12:01 -0400 Subject: [PATCH] shape linetype; supported in gadfly; gadfly cleanup --- src/args.jl | 9 +- src/backends/gadfly.jl | 833 ++++++++++++++++++-------------------- src/backends/supported.jl | 3 +- src/components.jl | 13 +- src/plot.jl | 31 ++ 5 files changed, 430 insertions(+), 459 deletions(-) diff --git a/src/args.jl b/src/args.jl index 990d0b61..c8438cd9 100644 --- a/src/args.jl +++ b/src/args.jl @@ -11,7 +11,7 @@ const _3dTypes = [:path3d, :scatter3d, :surface, :wireframe] const _allTypes = vcat([ :none, :line, :path, :steppre, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :hist2d, :hist3d, :density, :bar, :hline, :vline, :ohlc, - :contour, :pie + :contour, :pie, :shape ], _3dTypes) @compat const _typeAliases = Dict( :n => :none, @@ -35,6 +35,9 @@ const _allTypes = vcat([ :line3d => :path3d, :surf => :surface, :wire => :wireframe, + :shapes => :shape, + :poly => :shape, + :polygon => :shape, ) ishistlike(lt::Symbol) = lt in (:hist, :density) @@ -515,7 +518,7 @@ function processFillArg(d::Dict, arg) d[:fillalpha] = arg elseif !handleColors!(d, arg, :fillcolor) - + d[:fillrange] = arg end end @@ -801,5 +804,3 @@ function getSeriesArgs(pkg::AbstractBackend, plotargs::Dict, kw, commandIndex::I d end - - diff --git a/src/backends/gadfly.jl b/src/backends/gadfly.jl index 3beb01e9..1d036b50 100644 --- a/src/backends/gadfly.jl +++ b/src/backends/gadfly.jl @@ -3,11 +3,11 @@ function _initialize_backend(::GadflyBackend; kw...) - @eval begin - import Gadfly, Compose - export Gadfly, Compose - include(joinpath(Pkg.dir("Plots"), "src", "backends", "gadfly_shapes.jl")) - end + @eval begin + import Gadfly, Compose + export Gadfly, Compose + include(joinpath(Pkg.dir("Plots"), "src", "backends", "gadfly_shapes.jl")) + end end # --------------------------------------------------------------------------- @@ -17,152 +17,116 @@ end # Base.getindex(v::MissingVec, i::Integer) = 0.0 function createGadflyPlotObject(d::Dict) - gplt = Gadfly.Plot() - gplt.mapping = Dict() - gplt.data_source = Gadfly.DataFrames.DataFrame() - # gplt.layers = gplt.layers[1:0] - gplt.layers = [Gadfly.layer(Gadfly.Geom.point(tag=:remove), x=zeros(1), y=zeros(1));] # x=MissingVec(), y=MissingVec());] - gplt.guides = Gadfly.GuideElement[Gadfly.Guide.xlabel(d[:xlabel]), + gplt = Gadfly.Plot() + gplt.mapping = Dict() + gplt.data_source = Gadfly.DataFrames.DataFrame() + # gplt.layers = gplt.layers[1:0] + gplt.layers = [Gadfly.layer(Gadfly.Geom.point(tag=:remove), x=zeros(1), y=zeros(1));] # x=MissingVec(), y=MissingVec());] + gplt.guides = Gadfly.GuideElement[Gadfly.Guide.xlabel(d[:xlabel]), Gadfly.Guide.ylabel(d[:ylabel]), Gadfly.Guide.title(d[:title])] - gplt + gplt end # --------------------------------------------------------------------------- function getLineGeom(d::Dict) - lt = d[:linetype] - xbins, ybins = maketuple(d[:nbins]) - if lt == :hexbin - Gadfly.Geom.hexbin(xbincount = xbins, ybincount = ybins) - elseif lt == :hist2d - Gadfly.Geom.histogram2d(xbincount = xbins, ybincount = ybins) - elseif lt == :hist - Gadfly.Geom.histogram(bincount = xbins) - elseif lt == :path - Gadfly.Geom.path - elseif lt in (:bar, :sticks) - Gadfly.Geom.bar - elseif lt == :steppost - Gadfly.Geom.step - elseif lt == :steppre - Gadfly.Geom.step(direction = :vh) - elseif lt == :hline - Gadfly.Geom.hline - elseif lt == :vline - Gadfly.Geom.vline - elseif lt == :contour - Gadfly.Geom.contour(levels = d[:levels]) - else - nothing - end + lt = d[:linetype] + xbins, ybins = maketuple(d[:nbins]) + if lt == :hexb + Gadfly.Geom.hexbin(xbincount = xbins, ybincount = ybins) + elseif lt == :hist2d + Gadfly.Geom.histogram2d(xbincount = xbins, ybincount = ybins) + elseif lt == :hist + Gadfly.Geom.histogram(bincount = xbins) + elseif lt == :path + Gadfly.Geom.path + elseif lt in (:bar, :sticks) + Gadfly.Geom.bar + elseif lt == :steppost + Gadfly.Geom.step + elseif lt == :steppre + Gadfly.Geom.step(direction = :vh) + elseif lt == :hline + Gadfly.Geom.hline + elseif lt == :vline + Gadfly.Geom.vline + elseif lt == :contour + Gadfly.Geom.contour(levels = d[:levels]) + # elseif lt == :shape + # Gadfly.Geom.polygon(fill = true, preserve_order = true) + else + nothing + end end function get_extra_theme_args(d::Dict, k::Symbol) - # gracefully handles old Gadfly versions - extra_theme_args = Dict() - try - extra_theme_args[:line_style] = Gadfly.get_stroke_vector(d[k]) - catch err - if string(err) == "UndefVarError(:get_stroke_vector)" - Base.warn_once("Gadfly.get_stroke_vector failed... do you have an old version of Gadfly?") - else - rethrow() + # gracefully handles old Gadfly versions + extra_theme_args = Dict() + try + extra_theme_args[:line_style] = Gadfly.get_stroke_vector(d[k]) + catch err + if string(err) == "UndefVarError(:get_stroke_vector)" + Base.warn_once("Gadfly.get_stroke_vector failed... do you have an old version of Gadfly?") + else + rethrow() + end end - end - extra_theme_args + extra_theme_args end function getGadflyLineTheme(d::Dict) - - lc = convertColor(getColor(d[:linecolor]), d[:linealpha]) - # lc = getColor(d[:linecolor]) - # α = d[:linealpha] - # if α != nothing - # lc = RGBA(lc, α) - # end + lc = convertColor(getColor(d[:linecolor]), d[:linealpha]) + fc = convertColor(getColor(d[:fillcolor]), d[:fillalpha]) - fc = convertColor(getColor(d[:fillcolor]), d[:fillalpha]) - # fc = getColor(d[:fillcolor]) - # α = d[:fillalpha] - # if α != nothing - # fc = RGBA(fc, α) - # end - - - Gadfly.Theme(; - default_color = lc, - line_width = (d[:linetype] == :sticks ? 1 : d[:linewidth]) * Gadfly.px, - # line_style = Gadfly.get_stroke_vector(d[:linestyle]), - lowlight_color = x->RGB(fc), # fill/ribbon - lowlight_opacity = alpha(fc), # fill/ribbon - bar_highlight = RGB(lc), # bars - get_extra_theme_args(d, :linestyle)... + Gadfly.Theme(; + default_color = lc, + line_width = (d[:linetype] == :sticks ? 1 : d[:linewidth]) * Gadfly.px, + # line_style = Gadfly.get_stroke_vector(d[:linestyle]), + lowlight_color = x->RGB(fc), # fill/ribbon + lowlight_opacity = alpha(fc), # fill/ribbon + bar_highlight = RGB(lc), # bars + get_extra_theme_args(d, :linestyle)... ) end # add a line as a new layer function addGadflyLine!(plt::Plot, numlayers::Int, d::Dict, geoms...) - gplt = getGadflyContext(plt) - gfargs = vcat(geoms..., - getGadflyLineTheme(d)) - kwargs = Dict() - lt = d[:linetype] + gplt = getGadflyContext(plt) + gfargs = vcat(geoms..., getGadflyLineTheme(d)) + kwargs = Dict() + lt = d[:linetype] - # add a fill? - if d[:fillrange] != nothing && lt != :contour - fillmin, fillmax = map(makevec, maketuple(d[:fillrange])) - nmin, nmax = length(fillmin), length(fillmax) - kwargs[:ymin] = Float64[min(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(d[:y])] - kwargs[:ymax] = Float64[max(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(d[:y])] - push!(gfargs, Gadfly.Geom.ribbon) - end - - if lt in (:hline, :vline) - kwargs[lt == :hline ? :yintercept : :xintercept] = d[:y] - - else - if lt == :sticks - w = 0.01 * mean(diff(d[:x])) - kwargs[:xmin] = d[:x] - w - kwargs[:xmax] = d[:x] + w - elseif lt == :contour - # d[:y] = reverse(d[:y]) - kwargs[:z] = d[:z].surf - addGadflyContColorScale(plt, d[:linecolor]) + # add a fill? + if d[:fillrange] != nothing && lt != :contour + fillmin, fillmax = map(makevec, maketuple(d[:fillrange])) + nmin, nmax = length(fillmin), length(fillmax) + kwargs[:ymin] = Float64[min(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(d[:y])] + kwargs[:ymax] = Float64[max(y, fillmin[mod1(i, nmin)], fillmax[mod1(i, nmax)]) for (i,y) in enumerate(d[:y])] + push!(gfargs, Gadfly.Geom.ribbon) end - kwargs[:x] = d[lt == :hist ? :y : :x] - kwargs[:y] = d[:y] + if lt in (:hline, :vline) + kwargs[lt == :hline ? :yintercept : :xintercept] = d[:y] - end + else + if lt == :sticks + w = 0.01 * mean(diff(d[:x])) + kwargs[:xmin] = d[:x] - w + kwargs[:xmax] = d[:x] + w + elseif lt == :contour + kwargs[:z] = d[:z].surf + addGadflyContColorScale(plt, d[:linecolor]) + end - # # h/vlines - # if lt == :hline - # kwargs[:yintercept] = d[:y] - # elseif lt == :vline - # kwargs[:xintercept] = d[:y] - # elseif lt == :sticks - # w = 0.01 * mean(diff(d[:x])) - # kwargs[:xmin] = d[:x] - w - # kwargs[:xmax] = d[:x] + w - # elseif lt == :contour - # d[:y] = reverse(d[:y]) - # kwargs[:z] = d[:surface] - # end + kwargs[:x] = d[lt == :hist ? :y : :x] + kwargs[:y] = d[:y] - # if lt == :hist - # kwargs[:x] = kwargs[:y] = d[:y] - # elseif lt != :hline && lt != :vline - # kwargs[:x] = d[:x] - # kwargs[:y] = d[:y] - # end - - # # add the layer - # x = d[d[:linetype] == :hist ? :y : :x] - # Gadfly.layer(gfargs...; x = x, y = d[:y], order=numlayers, kwargs...) - Gadfly.layer(gfargs...; order=numlayers, kwargs...) + end + + # # add the layer + Gadfly.layer(gfargs...; order=numlayers, kwargs...) end @@ -172,109 +136,99 @@ end getMarkerGeom(shape::Shape) = gadflyshape(shape) getMarkerGeom(shape::Symbol) = gadflyshape(_shapes[shape]) getMarkerGeom(shapes::AVec) = map(getMarkerGeom, shapes) -getMarkerGeom(d::Dict) = getMarkerGeom(d[:markershape]) - -# function getMarkerGeom(d::Dict) -# shape = d[:markershape] -# gadflyshape(isa(shape, Shape) ? shape : _shapes[shape]) -# end - +function getMarkerGeom(d::Dict) + if d[:linetype] == :shape + Gadfly.Geom.polygon(fill = true, preserve_order = true) + else + getMarkerGeom(d[:markershape]) + end +end function getGadflyMarkerTheme(d::Dict, plotargs::Dict) - c = getColor(d[:markercolor]) - α = d[:markeralpha] - if α != nothing - c = RGBA(RGB(c), α) - end + c = getColor(d[:markercolor]) + α = d[:markeralpha] + if α != nothing + c = RGBA(RGB(c), α) + end - ms = d[:markersize] - ms = if typeof(ms) <: AVec - warn("Gadfly doesn't support variable marker sizes... using the average: $(mean(ms))") - mean(ms) * Gadfly.px - else - ms * Gadfly.px - end + ms = d[:markersize] + ms = if typeof(ms) <: AVec + warn("Gadfly doesn't support variable marker sizes... using the average: $(mean(ms))") + mean(ms) * Gadfly.px + else + ms * Gadfly.px + end - # fg = getColor(plotargs[:foreground_color]) - Gadfly.Theme(; - default_color = c, - default_point_size = ms, - discrete_highlight_color = c -> RGB(getColor(d[:markerstrokecolor])), - highlight_width = d[:markerstrokewidth] * Gadfly.px, - # get_extra_theme_args(d, :markerstrokestyle)... + Gadfly.Theme(; + default_color = c, + default_point_size = ms, + discrete_highlight_color = c -> RGB(getColor(d[:markerstrokecolor])), + highlight_width = d[:markerstrokewidth] * Gadfly.px, + line_width = d[:markerstrokewidth] * Gadfly.px, + # get_extra_theme_args(d, :markerstrokestyle)... ) end function addGadflyContColorScale(plt::Plot{GadflyBackend}, c) - plt.plotargs[:colorbar] == :none && return - if !isa(c, ColorGradient) - c = colorscheme(:bluesreds) - end - push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(c, p)))) + plt.plotargs[:colorbar] == :none && return + if !isa(c, ColorGradient) + c = colorscheme(:bluesreds) + end + push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(c, p)))) end function addGadflyMarker!(plt::Plot, numlayers::Int, d::Dict, plotargs::Dict, geoms...) - gfargs = vcat(geoms..., - getGadflyMarkerTheme(d, plotargs), - getMarkerGeom(d)) - kwargs = Dict() + gfargs = vcat(geoms..., getGadflyMarkerTheme(d, plotargs), getMarkerGeom(d)) + kwargs = Dict() - # handle continuous color scales for the markers - zcolor = d[:zcolor] - if zcolor != nothing && typeof(zcolor) <: AVec - kwargs[:color] = zcolor - addGadflyContColorScale(plt, d[:markercolor]) - # if !isa(d[:markercolor], ColorGradient) - # d[:markercolor] = colorscheme(:bluesreds) - # end - # push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(d[:markercolor], p)))) - end + # handle continuous color scales for the markers + zcolor = d[:zcolor] + if zcolor != nothing && typeof(zcolor) <: AVec + kwargs[:color] = zcolor + addGadflyContColorScale(plt, d[:markercolor]) + end - Gadfly.layer(gfargs...; x = d[:x], y = d[:y], order=numlayers, kwargs...) + Gadfly.layer(gfargs...; x = d[:x], y = d[:y], order=numlayers, kwargs...) end # --------------------------------------------------------------------------- function addToGadflyLegend(plt::Plot, d::Dict) + if plt.plotargs[:legend] != :none && d[:label] != "" + gplt = getGadflyContext(plt) - # add the legend? - if plt.plotargs[:legend] != :none && d[:label] != "" - gplt = getGadflyContext(plt) - - # add the legend if needed - if all(g -> !isa(g, Gadfly.Guide.ManualColorKey), gplt.guides) - unshift!(gplt.guides, Gadfly.Guide.manual_color_key("", @compat(AbstractString)[], Color[])) - end - - # now add the series to the legend - for guide in gplt.guides - if isa(guide, Gadfly.Guide.ManualColorKey) - # TODO: there's a BUG in gadfly if you pass in the same color more than once, - # since gadfly will call unique(colors), but doesn't also merge the rows that match - # Should ensure from this side that colors which are the same are merged together - - c = getColor(d[d[:markershape] == :none ? :linecolor : :markercolor]) - foundit = false - - # extend the label if we found this color - for i in 1:length(guide.colors) - if RGB(c) == guide.colors[i] - guide.labels[i] *= ", " * d[:label] - foundit = true - end + # add the legend if needed + if all(g -> !isa(g, Gadfly.Guide.ManualColorKey), gplt.guides) + unshift!(gplt.guides, Gadfly.Guide.manual_color_key("", @compat(AbstractString)[], Color[])) end - # didn't find the color, so add a new entry into the legend - if !foundit - push!(guide.labels, d[:label]) - push!(guide.colors, c) + # now add the series to the legend + for guide in gplt.guides + if isa(guide, Gadfly.Guide.ManualColorKey) + # TODO: there's a BUG in gadfly if you pass in the same color more than once, + # since gadfly will call unique(colors), but doesn't also merge the rows that match + # Should ensure from this side that colors which are the same are merged together + + c = getColor(d[d[:markershape] == :none ? :linecolor : :markercolor]) + foundit = false + + # extend the label if we found this color + for i in 1:length(guide.colors) + if RGB(c) == guide.colors[i] + guide.labels[i] *= ", " * d[:label] + foundit = true + end + end + + # didn't find the color, so add a new entry into the legend + if !foundit + push!(guide.labels, d[:label]) + push!(guide.colors, c) + end + end end - end end - - end - end getGadflySmoothing(smooth::Bool) = smooth ? [Gadfly.Geom.smooth(method=:lm)] : Any[] @@ -282,43 +236,40 @@ getGadflySmoothing(smooth::Real) = [Gadfly.Geom.smooth(method=:loess, smoothing= function addGadflySeries!(plt::Plot, d::Dict) + layers = Gadfly.Layer[] + gplt = getGadflyContext(plt) - layers = Gadfly.Layer[] - gplt = getGadflyContext(plt) + # add a regression line? + # TODO: make more flexible + smooth = getGadflySmoothing(d[:smooth]) - # add a regression line? - # TODO: make more flexible - smooth = getGadflySmoothing(d[:smooth]) + # lines + geom = getLineGeom(d) + if geom != nothing + prepend!(layers, addGadflyLine!(plt, length(gplt.layers), d, geom, smooth...)) + smooth = Any[] # don't add a regression for markers too + end - # lines - geom = getLineGeom(d) - if geom != nothing - prepend!(layers, addGadflyLine!(plt, length(gplt.layers), d, geom, smooth...)) + # special handling for ohlc and scatter + lt = d[:linetype] + if lt == :ohlc + error("Haven't re-implemented after refactoring") + elseif lt in (:hist2d, :hexbin) && (isa(d[:linecolor], ColorGradient) || isa(d[:linecolor], ColorFunction)) + push!(gplt.scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(d[:linecolor], p)))) + elseif lt == :scatter && d[:markershape] == :none + d[:markershape] = :ellipse + end - # don't add a regression for markers too - smooth = Any[] - end + # markers + if d[:markershape] != :none || lt == :shape + prepend!(layers, addGadflyMarker!(plt, length(gplt.layers), d, plt.plotargs, smooth...)) + end - # special handling for ohlc and scatter - lt = d[:linetype] - if lt == :ohlc - error("Haven't re-implemented after refactoring") - elseif lt in (:hist2d, :hexbin) && (isa(d[:linecolor], ColorGradient) || isa(d[:linecolor], ColorFunction)) - push!(gplt.scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(d[:linecolor], p)))) - elseif lt == :scatter && d[:markershape] == :none - d[:markershape] = :ellipse - end + lt in (:hist2d, :hexbin, :contour) || addToGadflyLegend(plt, d) - # markers - if d[:markershape] != :none - prepend!(layers, addGadflyMarker!(plt, length(gplt.layers), d, plt.plotargs, smooth...)) - end - - lt in (:hist2d, :hexbin, :contour) || addToGadflyLegend(plt, d) - - # now save the layers that apply to this series - d[:gadflylayers] = layers - prepend!(gplt.layers, layers) + # now save the layers that apply to this series + d[:gadflylayers] = layers + prepend!(gplt.layers, layers) end @@ -349,36 +300,36 @@ end function addGadflyTicksGuide(gplt, ticks, isx::Bool) - ticks == :auto && return + ticks == :auto && return - # remove the ticks? - if ticks in (:none, false, nothing) - return addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false) - end + # remove the ticks? + if ticks in (:none, false, nothing) + return addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false) + end - ttype = ticksType(ticks) + ttype = ticksType(ticks) - # just the values... put ticks here, but use standard labels - if ttype == :ticks - gtype = isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks - replaceType(gplt.guides, gtype(ticks = collect(ticks))) + # just the values... put ticks here, but use standard labels + if ttype == :ticks + gtype = isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks + replaceType(gplt.guides, gtype(ticks = collect(ticks))) - # set the ticks and the labels - elseif ttype == :ticks_and_labels - gtype = isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks - replaceType(gplt.guides, gtype(ticks = collect(ticks[1]))) + # set the ticks and the labels + elseif ttype == :ticks_and_labels + gtype = isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks + replaceType(gplt.guides, gtype(ticks = collect(ticks[1]))) - # TODO add xtick_label function (given tick, return label??) - # Scale.x_discrete(; labels=nothing, levels=nothing, order=nothing) - filterGadflyScale(gplt, isx) - gfunc = isx ? Gadfly.Scale.x_discrete : Gadfly.Scale.y_discrete - labelmap = Dict(zip(ticks...)) - labelfunc = val -> labelmap[val] - push!(gplt.scales, gfunc(levels = collect(ticks[1]), labels = labelfunc)) + # TODO add xtick_label function (given tick, return label??) + # Scale.x_discrete(; labels=nothing, levels=nothing, order=nothing) + filterGadflyScale(gplt, isx) + gfunc = isx ? Gadfly.Scale.x_discrete : Gadfly.Scale.y_discrete + labelmap = Dict(zip(ticks...)) + labelfunc = val -> labelmap[val] + push!(gplt.scales, gfunc(levels = collect(ticks[1]), labels = labelfunc)) - else - error("Invalid input for $(isx ? "xticks" : "yticks"): ", ticks) - end + else + error("Invalid input for $(isx ? "xticks" : "yticks"): ", ticks) + end end continuousAndSameAxis(scale, isx::Bool) = isa(scale, Gadfly.Scale.ContinuousScale) && scale.vars[1] == (isx ? :x : :y) @@ -386,169 +337,158 @@ filterGadflyScale(gplt, isx::Bool) = filter!(scale -> !continuousAndSameAxis(sca function getGadflyScaleFunction(d::Dict, isx::Bool) - scalekey = isx ? :xscale : :yscale - hasScaleKey = haskey(d, scalekey) - if hasScaleKey - scale = d[scalekey] - scale == :ln && return isx ? Gadfly.Scale.x_log : Gadfly.Scale.y_log, hasScaleKey - scale == :log2 && return isx ? Gadfly.Scale.x_log2 : Gadfly.Scale.y_log2, hasScaleKey - scale == :log10 && return isx ? Gadfly.Scale.x_log10 : Gadfly.Scale.y_log10, hasScaleKey - scale == :asinh && return isx ? Gadfly.Scale.x_asinh : Gadfly.Scale.y_asinh, hasScaleKey - scale == :sqrt && return isx ? Gadfly.Scale.x_sqrt : Gadfly.Scale.y_sqrt, hasScaleKey - end - isx ? Gadfly.Scale.x_continuous : Gadfly.Scale.y_continuous, hasScaleKey + scalekey = isx ? :xscale : :yscale + hasScaleKey = haskey(d, scalekey) + if hasScaleKey + scale = d[scalekey] + scale == :ln && return isx ? Gadfly.Scale.x_log : Gadfly.Scale.y_log, hasScaleKey + scale == :log2 && return isx ? Gadfly.Scale.x_log2 : Gadfly.Scale.y_log2, hasScaleKey + scale == :log10 && return isx ? Gadfly.Scale.x_log10 : Gadfly.Scale.y_log10, hasScaleKey + scale == :asinh && return isx ? Gadfly.Scale.x_asinh : Gadfly.Scale.y_asinh, hasScaleKey + scale == :sqrt && return isx ? Gadfly.Scale.x_sqrt : Gadfly.Scale.y_sqrt, hasScaleKey + end + isx ? Gadfly.Scale.x_continuous : Gadfly.Scale.y_continuous, hasScaleKey end function addGadflyLimitsScale(gplt, d::Dict, isx::Bool) + gfunc, hasScaleKey = getGadflyScaleFunction(d, isx) - # get the correct scale function - gfunc, hasScaleKey = getGadflyScaleFunction(d, isx) - - # do we want to add min/max limits for the axis? - limsym = isx ? :xlims : :ylims - limargs = Any[] + # do we want to add min/max limits for the axis? + limsym = isx ? :xlims : :ylims + limargs = Any[] - # map :auto to nothing, otherwise add to limargs - lims = get(d, limsym, :auto) - # lims == :auto && return - if lims == :auto - lims = nothing - else - if limsType(lims) == :limits - push!(limargs, (:minvalue, min(lims...))) - push!(limargs, (:maxvalue, max(lims...))) + # map :auto to nothing, otherwise add to limargs + lims = get(d, limsym, :auto) + if lims == :auto + lims = nothing else - error("Invalid input for $(isx ? "xlims" : "ylims"): ", lims) + if limsType(lims) == :limits + push!(limargs, (:minvalue, min(lims...))) + push!(limargs, (:maxvalue, max(lims...))) + else + error("Invalid input for $(isx ? "xlims" : "ylims"): ", lims) + end end - end - # replace any current scales with this one - if hasScaleKey || !isempty(limargs) - filterGadflyScale(gplt, isx) - push!(gplt.scales, gfunc(; limargs...)) - end + # replace any current scales with this one + if hasScaleKey || !isempty(limargs) + filterGadflyScale(gplt, isx) + push!(gplt.scales, gfunc(; limargs...)) + end - lims + lims end function updateGadflyAxisFlips(gplt, d::Dict, xlims, ylims) - if isa(gplt.coord, Gadfly.Coord.Cartesian) - gplt.coord = Gadfly.Coord.cartesian( - gplt.coord.xvars, - gplt.coord.yvars; - xmin = xlims == nothing ? gplt.coord.xmin : minimum(xlims), - xmax = xlims == nothing ? gplt.coord.xmax : maximum(xlims), - ymin = ylims == nothing ? gplt.coord.ymin : minimum(ylims), - ymax = ylims == nothing ? gplt.coord.ymax : maximum(ylims), - xflip = get(d, :xflip, gplt.coord.xflip), - yflip = get(d, :yflip, gplt.coord.yflip), - fixed = gplt.coord.fixed, - aspect_ratio = gplt.coord.aspect_ratio, - raster = gplt.coord.raster - ) - else - gplt.coord = Gadfly.Coord.Cartesian( - xflip = get(d, :xflip, false), - yflip = get(d, :yflip, false) - ) - end + if isa(gplt.coord, Gadfly.Coord.Cartesian) + gplt.coord = Gadfly.Coord.cartesian( + gplt.coord.xvars, + gplt.coord.yvars; + xmin = xlims == nothing ? gplt.coord.xmin : minimum(xlims), + xmax = xlims == nothing ? gplt.coord.xmax : maximum(xlims), + ymin = ylims == nothing ? gplt.coord.ymin : minimum(ylims), + ymax = ylims == nothing ? gplt.coord.ymax : maximum(ylims), + xflip = get(d, :xflip, gplt.coord.xflip), + yflip = get(d, :yflip, gplt.coord.yflip), + fixed = gplt.coord.fixed, + aspect_ratio = gplt.coord.aspect_ratio, + raster = gplt.coord.raster + ) + else + gplt.coord = Gadfly.Coord.Cartesian( + xflip = get(d, :xflip, false), + yflip = get(d, :yflip, false) + ) + end end function findGuideAndSet(gplt, t::DataType, args...; kw...) #s::@compat(AbstractString)) - for (i,guide) in enumerate(gplt.guides) - if isa(guide, t) - gplt.guides[i] = t(args...; kw...) + for (i,guide) in enumerate(gplt.guides) + if isa(guide, t) + gplt.guides[i] = t(args...; kw...) + end end - end end function updateGadflyGuides(plt::Plot, d::Dict) - gplt = getGadflyContext(plt) - haskey(d, :title) && findGuideAndSet(gplt, Gadfly.Guide.title, string(d[:title])) - haskey(d, :xlabel) && findGuideAndSet(gplt, Gadfly.Guide.xlabel, string(d[:xlabel])) - haskey(d, :ylabel) && findGuideAndSet(gplt, Gadfly.Guide.ylabel, string(d[:ylabel])) + gplt = getGadflyContext(plt) + haskey(d, :title) && findGuideAndSet(gplt, Gadfly.Guide.title, string(d[:title])) + haskey(d, :xlabel) && findGuideAndSet(gplt, Gadfly.Guide.xlabel, string(d[:xlabel])) + haskey(d, :ylabel) && findGuideAndSet(gplt, Gadfly.Guide.ylabel, string(d[:ylabel])) - xlims = addGadflyLimitsScale(gplt, d, true) - ylims = addGadflyLimitsScale(gplt, d, false) + xlims = addGadflyLimitsScale(gplt, d, true) + ylims = addGadflyLimitsScale(gplt, d, false) - ticks = get(d, :xticks, :auto) - if ticks == :none - _remove_axis(plt, true) - else - addGadflyTicksGuide(gplt, ticks, true) - end - ticks = get(d, :yticks, :auto) - if ticks == :none - _remove_axis(plt, false) - else - addGadflyTicksGuide(gplt, ticks, false) - end - # haskey(d, :yticks) && addGadflyTicksGuide(gplt, d[:yticks], false) + ticks = get(d, :xticks, :auto) + if ticks == :none + _remove_axis(plt, true) + else + addGadflyTicksGuide(gplt, ticks, true) + end + ticks = get(d, :yticks, :auto) + if ticks == :none + _remove_axis(plt, false) + else + addGadflyTicksGuide(gplt, ticks, false) + end - updateGadflyAxisFlips(gplt, d, xlims, ylims) + updateGadflyAxisFlips(gplt, d, xlims, ylims) end function updateGadflyPlotTheme(plt::Plot, d::Dict) - kwargs = Dict() + kwargs = Dict() - # # get the full plotargs, overriding any new settings - # # TODO: should this be part of the main `plot` command in plot.jl??? - # d = merge!(plt.plotargs, d) + # # hide the legend? + leg = d[d[:legend] == :none ? :colorbar : :legend] + if leg != :best + kwargs[:key_position] = leg == :inside ? :right : leg + end - # # hide the legend? - # if !get(d, :legend, true) - # kwargs[:key_position] = :none - # end - leg = d[d[:legend] == :none ? :colorbar : :legend] - if leg != :best - kwargs[:key_position] = leg == :inside ? :right : leg - end + if !get(d, :grid, true) + kwargs[:grid_color] = getColor(d[:background_color]) + end - if !get(d, :grid, true) - kwargs[:grid_color] = getColor(d[:background_color]) - end + # fonts + tfont, gfont, lfont = d[:tickfont], d[:guidefont], d[:legendfont] - # fonts - tfont, gfont, lfont = d[:tickfont], d[:guidefont], d[:legendfont] - - fg = getColor(d[:foreground_color]) - getGadflyContext(plt).theme = Gadfly.Theme(; - background_color = getColor(d[:background_color]), - minor_label_color = fg, - minor_label_font = tfont.family, - minor_label_font_size = tfont.pointsize * Gadfly.pt, - major_label_color = fg, - major_label_font = gfont.family, - major_label_font_size = gfont.pointsize * Gadfly.pt, - key_title_color = fg, - key_title_font = gfont.family, - key_title_font_size = gfont.pointsize * Gadfly.pt, - key_label_color = fg, - key_label_font = lfont.family, - key_label_font_size = lfont.pointsize * Gadfly.pt, - plot_padding = 1 * Gadfly.mm, - kwargs... - ) + fg = getColor(d[:foreground_color]) + getGadflyContext(plt).theme = Gadfly.Theme(; + background_color = getColor(d[:background_color]), + minor_label_color = fg, + minor_label_font = tfont.family, + minor_label_font_size = tfont.pointsize * Gadfly.pt, + major_label_color = fg, + major_label_font = gfont.family, + major_label_font_size = gfont.pointsize * Gadfly.pt, + key_title_color = fg, + key_title_font = gfont.family, + key_title_font_size = gfont.pointsize * Gadfly.pt, + key_label_color = fg, + key_label_font = lfont.family, + key_label_font_size = lfont.pointsize * Gadfly.pt, + plot_padding = 1 * Gadfly.mm, + kwargs... + ) end # ---------------------------------------------------------------- function createGadflyAnnotationObject(x, y, val::@compat(AbstractString)) - Gadfly.Guide.annotation(Compose.compose( - Compose.context(), + Gadfly.Guide.annotation(Compose.compose( + Compose.context(), Compose.text(x, y, val) )) end function createGadflyAnnotationObject(x, y, txt::PlotText) - halign = (txt.font.halign == :hcenter ? Compose.hcenter : (txt.font.halign == :left ? Compose.hleft : Compose.hright)) - valign = (txt.font.valign == :vcenter ? Compose.vcenter : (txt.font.valign == :top ? Compose.vtop : Compose.vbottom)) - rotations = (txt.font.rotation == 0.0 ? [] : [Compose.Rotation(txt.font.rotation, Compose.Point(Compose.x_measure(x), Compose.y_measure(y)))]) - Gadfly.Guide.annotation(Compose.compose( - Compose.context(), + halign = (txt.font.halign == :hcenter ? Compose.hcenter : (txt.font.halign == :left ? Compose.hleft : Compose.hright)) + valign = (txt.font.valign == :vcenter ? Compose.vcenter : (txt.font.valign == :top ? Compose.vtop : Compose.vbottom)) + rotations = (txt.font.rotation == 0.0 ? [] : [Compose.Rotation(txt.font.rotation, Compose.Point(Compose.x_measure(x), Compose.y_measure(y)))]) + Gadfly.Guide.annotation(Compose.compose( + Compose.context(), Compose.text(x, y, txt.str, halign, valign, rotations...), Compose.font(string(txt.font.family)), Compose.fontsize(txt.font.pointsize * Gadfly.pt), @@ -558,9 +498,9 @@ function createGadflyAnnotationObject(x, y, txt::PlotText) end function _add_annotations{X,Y,V}(plt::Plot{GadflyBackend}, anns::AVec{@compat(Tuple{X,Y,V})}) - for ann in anns - push!(plt.o.guides, createGadflyAnnotationObject(ann...)) - end + for ann in anns + push!(plt.o.guides, createGadflyAnnotationObject(ann...)) + end end @@ -568,32 +508,31 @@ end # create a blank Gadfly.Plot object function _create_plot(pkg::GadflyBackend; kw...) - d = Dict(kw) - gplt = createGadflyPlotObject(d) - Plot(gplt, pkg, 0, d, Dict[]) + d = Dict(kw) + gplt = createGadflyPlotObject(d) + Plot(gplt, pkg, 0, d, Dict[]) end # plot one data series function _add_series(::GadflyBackend, plt::Plot; kw...) - - # first clear out the temporary layer - gplt = getGadflyContext(plt) - if gplt.layers[1].geom.tag == :remove - gplt.layers = gplt.layers[2:end] - end + # first clear out the temporary layer + gplt = getGadflyContext(plt) + if gplt.layers[1].geom.tag == :remove + gplt.layers = gplt.layers[2:end] + end - d = Dict(kw) - addGadflySeries!(plt, d) - push!(plt.seriesargs, d) - plt + d = Dict(kw) + addGadflySeries!(plt, d) + push!(plt.seriesargs, d) + plt end function _update_plot(plt::Plot{GadflyBackend}, d::Dict) - updateGadflyGuides(plt, d) - updateGadflyPlotTheme(plt, d) + updateGadflyGuides(plt, d) + updateGadflyPlotTheme(plt, d) end @@ -603,20 +542,20 @@ end # TODO: need to save all the layer indices which apply to this series function getGadflyMappings(plt::Plot, i::Integer) - @assert i > 0 && i <= plt.n - mappings = [l.mapping for l in plt.seriesargs[i][:gadflylayers]] + @assert i > 0 && i <= plt.n + mappings = [l.mapping for l in plt.seriesargs[i][:gadflylayers]] end function Base.getindex(plt::Plot{GadflyBackend}, i::Integer) - mapping = getGadflyMappings(plt, i)[1] - mapping[:x], mapping[:y] + mapping = getGadflyMappings(plt, i)[1] + mapping[:x], mapping[:y] end function Base.setindex!(plt::Plot{GadflyBackend}, xy::Tuple, i::Integer) - for mapping in getGadflyMappings(plt, i) - mapping[:x], mapping[:y] = xy - end - plt + for mapping in getGadflyMappings(plt, i) + mapping[:x], mapping[:y] = xy + end + plt end # ---------------------------------------------------------------- @@ -624,22 +563,22 @@ end # create the underlying object (each backend will do this differently) function _create_subplot(subplt::Subplot{GadflyBackend}, isbefore::Bool) - isbefore && return false # wait until after plotting to create the subplots - subplt.o = nothing - true + isbefore && return false # wait until after plotting to create the subplots + subplt.o = nothing + true end function _remove_axis(plt::Plot{GadflyBackend}, isx::Bool) - gplt = getGadflyContext(plt) - addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false) - addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "") + gplt = getGadflyContext(plt) + addOrReplace(gplt.guides, isx ? Gadfly.Guide.xticks : Gadfly.Guide.yticks; label=false) + addOrReplace(gplt.guides, isx ? Gadfly.Guide.xlabel : Gadfly.Guide.ylabel, "") end function _expand_limits(lims, plt::Plot{GadflyBackend}, isx::Bool) - for l in getGadflyContext(plt).layers - _expand_limits(lims, l.mapping[isx ? :x : :y]) - end + for l in getGadflyContext(plt).layers + _expand_limits(lims, l.mapping[isx ? :x : :y]) + end end @@ -651,22 +590,22 @@ getGadflyContext(subplt::Subplot{GadflyBackend}) = buildGadflySubplotContext(sub # create my Compose.Context grid by hstacking and vstacking the Gadfly.Plot objects function buildGadflySubplotContext(subplt::Subplot) - rows = Any[] - row = Any[] - for (i,(r,c)) in enumerate(subplt.layout) + rows = Any[] + row = Any[] + for (i,(r,c)) in enumerate(subplt.layout) - # add the Plot object to the row - push!(row, getGadflyContext(subplt.plts[i])) + # add the Plot object to the row + push!(row, getGadflyContext(subplt.plts[i])) - # add the row - if c == ncols(subplt.layout, r) - push!(rows, Gadfly.hstack(row...)) - row = Any[] + # add the row + if c == ncols(subplt.layout, r) + push!(rows, Gadfly.hstack(row...)) + row = Any[] + end end - end - # stack the rows - Gadfly.vstack(rows...) + # stack the rows + Gadfly.vstack(rows...) end setGadflyDisplaySize(w,h) = Compose.set_default_graphic_size(w * Compose.px, h * Compose.px) @@ -676,9 +615,9 @@ setGadflyDisplaySize(subplt::Subplot) = setGadflyDisplaySize(getplotargs(subplt, function dowritemime{P<:Union{GadflyBackend,ImmerseBackend}}(io::IO, func, plt::AbstractPlot{P}) - gplt = getGadflyContext(plt) - setGadflyDisplaySize(plt) - Gadfly.draw(func(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt) + gplt = getGadflyContext(plt) + setGadflyDisplaySize(plt) + Gadfly.draw(func(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt) end getGadflyWriteFunc(::MIME"image/png") = Gadfly.PNG @@ -690,37 +629,35 @@ getGadflyWriteFunc(::MIME"application/x-tex") = Gadfly.PGF getGadflyWriteFunc(m::MIME) = error("Unsupported in Gadfly/Immerse: ", m) for mime in (MIME"image/png", MIME"image/svg+xml", MIME"application/pdf", MIME"application/postscript", MIME"application/x-tex") - @eval function Base.writemime{P<:Union{GadflyBackend,ImmerseBackend}}(io::IO, ::$mime, plt::AbstractPlot{P}) - func = getGadflyWriteFunc($mime()) - dowritemime(io, func, plt) - end + @eval function Base.writemime{P<:Union{GadflyBackend,ImmerseBackend}}(io::IO, ::$mime, plt::AbstractPlot{P}) + func = getGadflyWriteFunc($mime()) + dowritemime(io, func, plt) + end end function Base.display(::PlotsDisplay, plt::Plot{GadflyBackend}) - setGadflyDisplaySize(plt.plotargs[:size]...) - display(plt.o) + setGadflyDisplaySize(plt.plotargs[:size]...) + display(plt.o) end - function Base.display(::PlotsDisplay, subplt::Subplot{GadflyBackend}) - setGadflyDisplaySize(getplotargs(subplt,1)[:size]...) - ctx = buildGadflySubplotContext(subplt) + setGadflyDisplaySize(getplotargs(subplt,1)[:size]...) + ctx = buildGadflySubplotContext(subplt) + # taken from Gadfly since I couldn't figure out how to do it directly - # taken from Gadfly since I couldn't figure out how to do it directly + filename = string(Gadfly.tempname(), ".html") + output = open(filename, "w") - filename = string(Gadfly.tempname(), ".html") - output = open(filename, "w") - - plot_output = IOBuffer() - Gadfly.draw(Gadfly.SVGJS(plot_output, Compose.default_graphic_width, + plot_output = IOBuffer() + Gadfly.draw(Gadfly.SVGJS(plot_output, Compose.default_graphic_width, Compose.default_graphic_height, false), ctx) - plotsvg = takebuf_string(plot_output) + plotsvg = takebuf_string(plot_output) - write(output, + write(output, """ @@ -739,6 +676,6 @@ function Base.display(::PlotsDisplay, subplt::Subplot{GadflyBackend}) """) - close(output) - Gadfly.open_file(filename) + close(output) + Gadfly.open_file(filename) end diff --git a/src/backends/supported.jl b/src/backends/supported.jl index 11168686..c6248bfc 100644 --- a/src/backends/supported.jl +++ b/src/backends/supported.jl @@ -81,7 +81,7 @@ supportedArgs(::GadflyBackend) = [ supportedAxes(::GadflyBackend) = [:auto, :left] supportedTypes(::GadflyBackend) = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter, :hist2d, :hexbin, :hist, :bar, - :hline, :vline, :contour] + :hline, :vline, :contour, :shape] supportedStyles(::GadflyBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] supportedMarkers(::GadflyBackend) = vcat(_allMarkers, Shape) supportedScales(::GadflyBackend) = [:identity, :ln, :log2, :log10, :asinh, :sqrt] @@ -770,4 +770,3 @@ supportedStyles(::PGFPlotsBackend) = [:auto, :solid] #, :dash, :dot, :dashdot, : supportedMarkers(::PGFPlotsBackend) = [:none, :auto, :ellipse] #, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape) supportedScales(::PGFPlotsBackend) = [:identity] #, :log, :log2, :log10, :asinh, :sqrt] subplotSupported(::PGFPlotsBackend) = false - diff --git a/src/components.jl b/src/components.jl index a7ffa742..3b413e2f 100644 --- a/src/components.jl +++ b/src/components.jl @@ -3,6 +3,9 @@ immutable Shape vertices::AVec end +get_xs(shape::Shape) = Float64[v[1] for v in shape.vertices] +get_ys(shape::Shape) = Float64[v[2] for v in shape.vertices] + "get an array of tuples of points on a circle with radius `r`" function partialcircle(start_θ, end_θ, n = 20, r=1) @compat(Tuple{Float64,Float64})[(r*cos(u),r*sin(u)) for u in linspace(start_θ, end_θ, n)] @@ -48,7 +51,7 @@ function makecross(; offset = -0.5, radius = 1.0) z1 = z2 - π/8 outercircle = partialcircle(z1, z1 + 2π, 9, radius) innercircle = partialcircle(z2, z2 + 2π, 5, 0.5radius) - Shape(weave(outercircle, innercircle, + Shape(weave(outercircle, innercircle, ordering=Vector[outercircle,innercircle,outercircle])[1:end-2]) end @@ -87,7 +90,7 @@ end "Create a Font from a list of unordered features" function font(args...) - + # defaults family = "Helvetica" pointsize = 14 @@ -266,7 +269,7 @@ end BezierCurve, curve_points, directed_curve - + typealias P2 FixedSizeArrays.Vec{2,Float64} typealias P3 FixedSizeArrays.Vec{3,Float64} @@ -298,7 +301,7 @@ end miny, maxy = minimum(yview), maximum(yview) diffpct = P2(diff[1] / (maxx - minx), diff[2] / (maxy - miny)) - + # these points give the initial/final "rise" # vertical_offset = P2(0, (maxy - miny) * max(0.03, min(abs(0.5diffpct[2]), 1.0))) vertical_offset = P2(0, max(0.15, 0.5norm(diff))) @@ -319,7 +322,7 @@ end else [] end - + BezierCurve([p, upper_control, inside_control_points..., lower_control, q]) end diff --git a/src/plot.jl b/src/plot.jl index 11a27c1c..ece75768 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -444,6 +444,37 @@ function createKWargsList{T<:Real}(plt::AbstractPlot, x::AMat{T}, y::AMat{T}, zm createKWargsList(plt, Any[x], Any[y]; d...) #kw..., z = surf, linetype = :contour) end +# plotting arbitrary shapes/polygons +function createKWargsList(plt::AbstractPlot, shape::Shape; kw...) + x, y = unzip(shape.vertices) + createKWargsList(plt, x, y; linetype = :shape, kw...) +end + +function shape_coords(shapes::AVec{Shape}) + xs = map(get_xs, shapes) + ys = map(get_ys, shapes) + x, y = unzip(shapes[1].vertices) + for shape in shapes[2:end] + tmpx, tmpy = unzip(shape.vertices) + x = vcat(x, NaN, tmpx) + y = vcat(y, NaN, tmpy) + end + x, y +end + +function createKWargsList(plt::AbstractPlot, shapes::AVec{Shape}; kw...) + x, y = shape_coords(shapes) + createKWargsList(plt, x, y; linetype = :shape, kw...) +end +function createKWargsList(plt::AbstractPlot, shapes::AMat{Shape}; kw...) + x, y = [], [] + for j in 1:size(shapes, 2) + tmpx, tmpy = shape_coords(vec(shapes[:,j])) + push!(x, tmpx) + push!(y, tmpy) + end + createKWargsList(plt, x, y; linetype = :shape, kw...) +end function createKWargsList(plt::AbstractPlot, surf::Surface; kw...) createKWargsList(plt, 1:size(surf.surf,1), 1:size(surf.surf,2), convert(Matrix{Float64}, surf.surf); kw...)