diff --git a/README.md b/README.md index 1b8c97cb..21a8fee8 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,8 @@ histogram(args...; kw...) = plot(args...; kw..., linetype = :hist) histogram!(args...; kw...) = plot!(args...; kw..., linetype = :hist) heatmap(args...; kw...) = plot(args...; kw..., linetype = :heatmap) heatmap!(args...; kw...) = plot!(args...; kw..., linetype = :heatmap) +sticks(args...; kw...) = plot(args...; kw..., linetype = :sticks, marker = :ellipse) +sticks!(args...; kw...) = plot!(args...; kw..., linetype = :sticks, marker = :ellipse) ``` Some keyword arguments you can set: diff --git a/REQUIRE b/REQUIRE index 0ac42a92..1488666b 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,4 +1,3 @@ julia 0.4- Colors -FactCheck diff --git a/src/Plots.jl b/src/Plots.jl index 158d7083..c2a9125b 100644 --- a/src/Plots.jl +++ b/src/Plots.jl @@ -19,6 +19,7 @@ export bar, histogram, heatmap, + sticks, currentPlot!, plotDefault!, @@ -26,6 +27,7 @@ export bar!, histogram!, heatmap!, + sticks!, savepng, @@ -62,6 +64,8 @@ histogram(args...; kw...) = plot(args...; kw..., linetype = :hist) histogram!(args...; kw...) = plot!(args...; kw..., linetype = :hist) heatmap(args...; kw...) = plot(args...; kw..., linetype = :heatmap) heatmap!(args...; kw...) = plot!(args...; kw..., linetype = :heatmap) +sticks(args...; kw...) = plot(args...; kw..., linetype = :sticks, marker = :ellipse) +sticks!(args...; kw...) = plot!(args...; kw..., linetype = :sticks, marker = :ellipse) # --------------------------------------------------------- diff --git a/src/args.jl b/src/args.jl index 8850857f..af73a65a 100644 --- a/src/args.jl +++ b/src/args.jl @@ -24,7 +24,7 @@ PLOT_DEFAULTS[:linetype] = :line PLOT_DEFAULTS[:linestyle] = :solid PLOT_DEFAULTS[:marker] = :none PLOT_DEFAULTS[:markercolor] = :match -PLOT_DEFAULTS[:markersize] = 3 +PLOT_DEFAULTS[:markersize] = 6 PLOT_DEFAULTS[:nbins] = 100 # number of bins for heatmaps and hists PLOT_DEFAULTS[:heatmap_c] = (0.15, 0.5) PLOT_DEFAULTS[:fillto] = nothing # fills in the area diff --git a/src/backends/gadfly.jl b/src/backends/gadfly.jl index aa0eba5d..f8e39674 100644 --- a/src/backends/gadfly.jl +++ b/src/backends/gadfly.jl @@ -41,20 +41,14 @@ function getLineGeoms(d::Dict) # lt == :dots && return [Gadfly.Geom.point] lt == :bar && return [Gadfly.Geom.bar] lt == :step && return [Gadfly.Geom.step] - lt == :sticks && return [Gadfly.Geom.bar] + # lt == :sticks && return [Gadfly.Geom.bar] error("linetype $lt not currently supported with Gadfly") end - -# serious hack (I think?) to draw my own shapes as annotations... will it work? who knows... -function getMarkerGeomsAndGuides(d::Dict) - marker = d[:marker] - if marker == :none - return [],[] - - # special handling for other marker shapes... gotta create Compose contexts and map them to series points using Guide.Annotation - elseif marker == :rect +function createGadflyAnnotation(d::Dict) + + if d[:marker] == :rect # get the width/height of the square (both are sz) sz = d[:markersize] * Gadfly.px halfsz = sz/2 @@ -64,7 +58,7 @@ function getMarkerGeomsAndGuides(d::Dict) ys = map(z -> Gadfly.Compose.Measure(;cy=z) + halfsz, float(d[:y])) # return an Annotation which will add those shapes to each point in the series - return [], [Gadfly.Guide.annotation(Gadfly.compose(Gadfly.context(), Gadfly.rectangle(xs,ys,[sz],[sz]), Gadfly.fill(d[:markercolor]), Gadfly.stroke(nothing)))] + return Gadfly.Guide.annotation(Gadfly.compose(Gadfly.context(), Gadfly.rectangle(xs,ys,[sz],[sz]), Gadfly.fill(d[:markercolor]), Gadfly.stroke(nothing))) else # make circles @@ -73,20 +67,66 @@ function getMarkerGeomsAndGuides(d::Dict) ys = collect(float(d[:y])) # return an Annotation which will add those shapes to each point in the series - return [], [Gadfly.Guide.annotation(Gadfly.compose(Gadfly.context(), Gadfly.circle(xs,ys,[sz]), Gadfly.fill(d[:markercolor]), Gadfly.stroke(nothing)))] + return Gadfly.Guide.annotation(Gadfly.compose(Gadfly.context(), Gadfly.circle(xs,ys,[sz]), Gadfly.fill(d[:markercolor]), Gadfly.stroke(nothing))) end - - # otherwise just return a Geom.point - # [Gadfly.Geom.point], [] end +# serious hack (I think?) to draw my own shapes as annotations... will it work? who knows... +function getMarkerGeomsAndGuides(d::Dict) + marker = d[:marker] + if marker == :none + return [],[] + end + return [], [createGadflyAnnotation(d)] +end + + # # special handling for other marker shapes... gotta create Compose contexts and map them to series points using Guide.Annotation + # elseif marker == :rect + # # get the width/height of the square (both are sz) + # sz = d[:markersize] * Gadfly.px + # halfsz = sz/2 + + # # remap x/y to the corner position of the squares + # xs = map(z -> Gadfly.Compose.Measure(;cx=z) - halfsz, float(d[:x])) + # ys = map(z -> Gadfly.Compose.Measure(;cy=z) + halfsz, float(d[:y])) + + # # return an Annotation which will add those shapes to each point in the series + # return [], [Gadfly.Guide.annotation(Gadfly.compose(Gadfly.context(), Gadfly.rectangle(xs,ys,[sz],[sz]), Gadfly.fill(d[:markercolor]), Gadfly.stroke(nothing)))] + + # else + # # make circles + # sz = 0.5 * d[:markersize] * Gadfly.px + # xs = collect(float(d[:x])) + # ys = collect(float(d[:y])) + + # # return an Annotation which will add those shapes to each point in the series + # return [], [Gadfly.Guide.annotation(Gadfly.compose(Gadfly.context(), Gadfly.circle(xs,ys,[sz]), Gadfly.fill(d[:markercolor]), Gadfly.stroke(nothing)))] + + # end + + # otherwise just return a Geom.point + # [Gadfly.Geom.point], [] +# end + + function addGadflySeries!(gplt, d::Dict) + + # first things first... lets so the sticks hack + if d[:linetype] == :sticks + d, dScatter = sticksHack(;d...) + + # add the annotation + if dScatter[:marker] != :none + push!(gplt.guides, createGadflyAnnotation(dScatter)) + end + end + gfargs = [] # add the Geoms - append!(gfargs, getLineGeoms(d)) #[:linetype], d[:marker], d[:markercolor], d[:nbins])) + append!(gfargs, getLineGeoms(d)) # handle markers geoms, guides = getMarkerGeomsAndGuides(d) diff --git a/src/utils.jl b/src/utils.jl index b7e1bddd..ce10dae8 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -70,6 +70,41 @@ function barHack(; kw...) end +doc""" +A hacky replacement for a sticks graph when the backend doesn't support sticks directly. +Convert it into a line chart that traces the sticks, and a scatter that sets markers at the points. +""" +function sticksHack(; kw...) + dLine = Dict(kw) + dScatter = copy(dLine) + + # these are the line vertices + x = Float64[] + y = Float64[] + fillto = dLine[:fillto] == nothing ? 0.0 : dLine[:fillto] + + # calculate the vertices + yScatter = dScatter[:y] + for (i,xi) in enumerate(dScatter[:x]) + yi = yScatter[i] + for j in 1:3 push!(x, xi) end + append!(y, [fillto, yScatter[i], fillto]) + end + + # change the line args + dLine[:x] = x + dLine[:y] = y + dLine[:linetype] = :line + dLine[:marker] = :none + dLine[:fillto] = nothing + + # change the scatter args + dScatter[:linetype] = :none + + dLine, dScatter +end + + # Some conversion functions # note: I borrowed these conversion constants from Compose.jl's Measure const INCH_SCALAR = 25.4 diff --git a/test/REQUIRE b/test/REQUIRE new file mode 100644 index 00000000..89b650ca --- /dev/null +++ b/test/REQUIRE @@ -0,0 +1,8 @@ +julia 0.4- + +Colors +FactCheck +PyPlot +UnicodePlots +Gadfly +Immerse