From dae9dad2f781752a49d70e95c9b2c05682da3c33 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Wed, 25 May 2016 13:06:08 -0400 Subject: [PATCH] working on GR; series_list and should_add_to_legend; series recipes fix; hist and bar recipes --- src/args.jl | 25 +- src/backends/gr.jl | 754 ++++++++++++++++++++++----------------- src/backends/pyplot.jl | 19 +- src/backends/template.jl | 6 +- src/output.jl | 34 +- src/plot.jl | 19 +- src/recipes.jl | 49 +++ src/series_new.jl | 3 +- src/subplots.jl | 10 + 9 files changed, 550 insertions(+), 369 deletions(-) diff --git a/src/args.jl b/src/args.jl index 6bfef5b2..4c74b10a 100644 --- a/src/args.jl +++ b/src/args.jl @@ -232,13 +232,14 @@ const _axis_defaults = KW( :foreground_color_guide => :match, # guide text color, ) -const _suppress_warnings = KW( - :x_discrete_indices => nothing, - :y_discrete_indices => nothing, - :z_discrete_indices => nothing, - :subplot => nothing, - :subplot_index => nothing, -) +const _suppress_warnings = Set{Symbol}([ + :x_discrete_indices, + :y_discrete_indices, + :z_discrete_indices, + :subplot, + :subplot_index, + :series_plotindex, +]) # add defaults for the letter versions const _axis_defaults_byletter = KW() @@ -433,9 +434,7 @@ function default(k::Symbol) return defaults[k] end end - if !haskey(_suppress_warnings, k) - error("Unknown key: ", k) - end + k in _suppress_warnings || error("Unknown key: ", k) end function default(k::Symbol, v) @@ -446,9 +445,7 @@ function default(k::Symbol, v) return v end end - if !haskey(_suppress_warnings, k) - error("Unknown key: ", k) - end + k in _suppress_warnings || error("Unknown key: ", k) end function default(; kw...) @@ -789,7 +786,7 @@ end function warnOnUnsupportedArgs(pkg::AbstractBackend, d::KW) for k in sortedkeys(d) k in supportedArgs(pkg) && continue - haskey(_suppress_warnings, k) && continue + k in _suppress_warnings && continue if d[k] != default(k) warn("Keyword argument $k not supported with $pkg. Choose from: $(supportedArgs(pkg))") end diff --git a/src/backends/gr.jl b/src/backends/gr.jl index c700b903..e9d19fac 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -37,8 +37,8 @@ supportedArgs(::GRBackend) = [ ] supportedAxes(::GRBackend) = _allAxes supportedTypes(::GRBackend) = [ - :none, :line, :path, :steppre, :steppost, - :scatter, :hist2d, :hexbin, :hist, :density, + :path, :steppre, :steppost, + :scatter, :hist2d, :hexbin, :bar, :sticks, :hline, :vline, :heatmap, :pie, :image, #:ohlc, :contour, :path3d, :scatter3d, :surface, :wireframe @@ -121,7 +121,7 @@ function gr_getcolorind(v) return convert(Int, GR.inqcolorfromrgb(c.r, c.g, c.b)) end -function gr_getaxisind(p) +function gr_getaxisind(d) axis = :left if axis in [:none, :left] return 1 @@ -130,25 +130,25 @@ function gr_getaxisind(p) end end -function gr_setmarkershape(p) - if p[:markershape] != :none - shape = p[:markershape] +function gr_setmarkershape(d) + if d[:markershape] != :none + shape = d[:markershape] if isa(shape, Shape) - p[:vertices] = vertices(shape) + d[:vertices] = vertices(shape) else GR.setmarkertype(gr_markertype[shape]) - p[:vertices] = :none + d[:vertices] = :none end end end -function gr_polymarker(p, x, y) - if p[:vertices] != :none - vertices= p[:vertices] +function gr_polymarker(d, x, y) + if d[:vertices] != :none + vertices= d[:vertices] dx = Float64[el[1] for el in vertices] * 0.01 dy = Float64[el[2] for el in vertices] * 0.01 GR.selntran(0) - GR.setfillcolorind(gr_getcolorind(p[:markercolor])) + GR.setfillcolorind(gr_getcolorind(d[:markercolor])) GR.setfillintstyle(GR.INTSTYLE_SOLID) for i = 1:length(x) xn, yn = GR.wctondc(x[i], y[i]) @@ -213,23 +213,42 @@ function gr_polaraxes(rmin, rmax) GR.restorestate() end -function gr_getzlims(d, zmin, zmax, adjust) - if d[:zlims] != :auto - zlims = d[:zlims] - if zlims[1] != NaN - zmin = zlims[1] - end - if zlims[2] != NaN - zmax = zlims[2] - end - adjust = false +# function gr_getzlims(d, zmin, zmax, adjust) +# if d[:zlims] != :auto +# zlims = d[:zlims] +# if zlims[1] != NaN +# zmin = zlims[1] +# end +# if zlims[2] != NaN +# zmax = zlims[2] +# end +# adjust = false +# end +# if adjust +# zmin, zmax = GR.adjustrange(zmin, zmax) +# end +# zmin, zmax +# end + +# using the axis extrema and limit overrides, return the min/max value for this axis +gr_x_axislims(sp::Subplot) = axis_limits(sp.attr[:xaxis], :x) +gr_y_axislims(sp::Subplot) = axis_limits(sp.attr[:yaxis], :y) +gr_z_axislims(sp::Subplot) = axis_limits(sp.attr[:zaxis], :z) +gr_xy_axislims(sp::Subplot) = gr_x_axislims(sp)..., gr_y_axislims(sp)... + +function gr_lims(axis::Axis, adjust::Bool, expand = nothing) + if expand != nothing + expand_extrema!(axis, expand) end + lims = axis_limits(axis, axis[:letter]) if adjust - zmin, zmax = GR.adjustrange(zmin, zmax) + GR.adjustrange(lims...) + else + lims end - zmin, zmax end + function gr_fill_viewport(vp::AVec{Float64}, c) GR.savestate() GR.selntran(0) @@ -240,12 +259,38 @@ function gr_fill_viewport(vp::AVec{Float64}, c) GR.restorestate() end -# -------------------------------------------------------------------------------------- - -function _update_min_padding!(sp::Subplot{GRBackend}) - sp.minpad = (20mm, 5mm, 2mm, 10mm) +function gr_fillrect(series::Series, l, r, b, t) + GR.setfillcolorind(gr_getcolorind(series.d[:fillcolor])) + GR.setfillintstyle(GR.INTSTYLE_SOLID) + # GR.fillrect(i-0.4, i+0.4, max(0, ymin), y[i]) + GR.fillrect(l, r, b, t) + GR.setfillcolorind(gr_getcolorind(series.d[:linecolor])) + GR.setfillintstyle(GR.INTSTYLE_HOLLOW) + # GR.fillrect(i-0.4, i+0.4, max(0, ymin), y[i]) + GR.fillrect(l, r, b, t) end +function gr_barplot(series::Series, x, y) + # x, y = d[:x], d[:y] + n = length(y) + if length(x) == n + 1 + # x is edges + for i=1:n + gr_fillrect(series, x[i], x[i+1], 0, y[i]) + end + elseif length(x) == n + # x is centers + leftwidth = length(x) > 1 ? abs(0.5 * (x[2] - x[1])) : 0.5 + for i=1:n + rightwidth = (i == n ? leftwidth : abs(0.5 * (x[i+1] - x[i]))) + gr_fillrect(series, x[i] - leftwidth, x[i] + rightwidth, 0, y[i]) + end + else + error("gr_barplot: x must be same length as y (centers), or one more than y (edges).\n\t\tlength(x)=$(length(x)), length(y)=$(length(y))") + end +end + + # -------------------------------------------------------------------------------------- # # convert a bounding box from absolute coords to percentages... @@ -258,21 +303,26 @@ end # mms ./ Float64[figw.value, figh.value, figw.value, figh.value] # end -function gr_viewport_from_bbox(bb::BoundingBox, w, h, canvas) +function gr_viewport_from_bbox(bb::BoundingBox, w, h, viewport_canvas) viewport = zeros(4) - viewport[1] = canvas[2] * (left(bb) / w) - viewport[2] = canvas[2] * (right(bb) / w) - viewport[3] = canvas[4] * (1.0 - bottom(bb) / h) - viewport[4] = canvas[4] * (1.0 - top(bb) / h) + viewport[1] = viewport_canvas[2] * (left(bb) / w) + viewport[2] = viewport_canvas[2] * (right(bb) / w) + viewport[3] = viewport_canvas[4] * (1.0 - bottom(bb) / h) + viewport[4] = viewport_canvas[4] * (1.0 - top(bb) / h) viewport end -# this is our new display func... set up the canvas, compute bounding boxes, and display each subplot +function gr_set_gradient(c) + grad = isa(c, ColorGradient) ? c : default_gradient() + for (i,z) in enumerate(linspace(0, 1, 256)) + c = getColorZ(grad, z) + GR.setcolorrep(999+i, red(c), green(c), blue(c)) + end +end + +# this is our new display func... set up the viewport_canvas, compute bounding boxes, and display each subplot function gr_display(plt::Plot) - # before starting, lets compute bounding boxes for the full layout tree - w, h = plt.attr[:size] - plt.layout.bbox = BoundingBox(0px, 0px, w*px, h*px) - update_child_bboxes!(plt.layout) + GR.clearws() # collect some monitor/display sizes in meters and pixels display_width_meters, display_height_meters, display_width_px, display_height_px = GR.inqdspsize() @@ -281,6 +331,7 @@ function gr_display(plt::Plot) # compute the viewport_canvas, normalized to the larger dimension viewport_canvas = Float64[0,1,0,1] + w, h = plt.attr[:size] if w > h ratio = float(h) / w msize = display_width_ratio * w @@ -290,35 +341,30 @@ function gr_display(plt::Plot) viewport_canvas[4] *= ratio else ratio = float(w) / h - msize = display_height_meters * h / display_height_px + msize = display_height_ratio * h GR.setwsviewport(0, msize * ratio, 0, msize) GR.setwswindow(0, ratio, 0, 1) viewport_canvas[1] *= ratio viewport_canvas[2] *= ratio end - # fill in the canvas background + # fill in the viewport_canvas background gr_fill_viewport(viewport_canvas, plt.attr[:background_color_outside]) @show "PLOT SETUP" plt.layout.bbox ratio viewport_canvas # subplots: - for sp in plt.subplots gr_display(sp, w*px, h*px, viewport_canvas) - end + + GR.updatews() end -# using the axis extrema and limit overrides, return the min/max value for this axis -gr_x_axislims(sp::Subplot) = axis_limits(sp.attr[:xaxis], :x) -gr_y_axislims(sp::Subplot) = axis_limits(sp.attr[:yaxis], :y) -gr_z_axislims(sp::Subplot) = axis_limits(sp.attr[:zaxis], :z) -gr_xy_axislims(sp::Subplot) = gr_x_axislims(sp)..., gr_y_axislims(sp)... -function gr_display(sp::Subplot{GRBackend}, w, h, canvas) +function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) # the viewports for this subplot - viewport_subplot = gr_viewport_from_bbox(bbox(sp), w*px, h*px, viewport_canvas) - viewport_plotarea = gr_viewport_from_bbox(plotarea(sp), w*px, h*px, viewport_canvas) + viewport_subplot = gr_viewport_from_bbox(bbox(sp), w, h, viewport_canvas) + viewport_plotarea = gr_viewport_from_bbox(plotarea(sp), w, h, viewport_canvas) @show "SUBPLOT",sp.attr[:subplot_index] bbox(sp) plotarea(sp) viewport_subplot viewport_plotarea # fill in the plot area background @@ -334,7 +380,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, canvas) # # clear && GR.clearws() # # # tbreloff notes: -# # - `GR.selntran(0)` changes the commands to be relative to the canvas, 1 means go back to the viewport you set +# # - `GR.selntran(0)` changes the commands to be relative to the viewport_canvas, 1 means go back to the viewport you set # # # display_width_meters, display_height_meters, display_width_px, display_height_px = GR.inqdspsize() # # w, h = plt.attr[:size] @@ -388,7 +434,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, canvas) # # # GR.restorestate() # # gr_fill_viewport(viewport_plotarea, sp.attr[:background_color_inside]) - extrema = zeros(2, 4) num_axes = 1 grid_flag = sp.attr[:grid] @@ -416,34 +461,34 @@ function gr_display(sp::Subplot{GRBackend}, w, h, canvas) # for axis = 1:2 # xmin = ymin = typemax(Float64) # xmax = ymax = typemin(Float64) - # for p in plt.seriesargs - # st = p[:seriestype] + # for d in plt.seriesargs + # st = d[:seriestype] # if get(d, :polar, false) # st = :polar # end - # if axis == gr_getaxisind(p) + # if axis == gr_getaxisind(d) # if axis == 2 # num_axes = 2 # end # if st == :bar - # x, y = 1:length(p[:y]), p[:y] + # x, y = 1:length(d[:y]), d[:y] # elseif st in [:hist, :density] - # x, y = Base.hist(p[:y], p[:bins]) + # x, y = Base.hist(d[:y], d[:bins]) # elseif st in [:hist2d, :hexbin] - # E = zeros(length(p[:x]),2) - # E[:,1] = p[:x] - # E[:,2] = p[:y] - # if isa(p[:bins], Tuple) - # xbins, ybins = p[:bins] + # E = zeros(length(d[:x]),2) + # E[:,1] = d[:x] + # E[:,2] = d[:y] + # if isa(d[:bins], Tuple) + # xbins, ybins = d[:bins] # else - # xbins = ybins = p[:bins] + # xbins = ybins = d[:bins] # end # cmap = true # x, y, H = Base.hist2d(E, xbins, ybins) # elseif st in [:pie, :polar] # axes_2d = false # xmin, xmax, ymin, ymax = 0, 1, 0, 1 - # x, y = p[:x], p[:y] + # x, y = d[:x], d[:y] # else # if st in [:contour, :surface, :heatmap] # cmap = true @@ -454,14 +499,14 @@ function gr_display(sp::Subplot{GRBackend}, w, h, canvas) # if st == :heatmap # outside_ticks = true # end - # x, y = p[:x], p[:y] + # x, y = d[:x], d[:y] # end # if !(st in [:pie, :polar]) # xmin = min(minimum(x), xmin) # xmax = max(maximum(x), xmax) # ymin = min(minimum(y), ymin) # ymax = max(maximum(y), ymax) - # if p[:xerror] != nothing || p[:yerror] != nothing + # if d[:xerror] != nothing || d[:yerror] != nothing # dx = xmax - xmin # xmin -= 0.02 * dx # xmax += 0.02 * dx @@ -491,10 +536,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, canvas) # compute extrema lims = gr_xy_axislims(sp) - for i=1:4 - extrema[:,i] = lims[i] - end + extrema = Float64[lims[c] for r=1:2,c=1:4] + # TODO: this should be accounted for in `_update_min_padding!` if num_axes == 2 || !axes_2d # note: add extra midpadding on the right for a second (right) axis viewport_plotarea[2] -= 0.0525 @@ -503,16 +547,27 @@ function gr_display(sp::Subplot{GRBackend}, w, h, canvas) # note: add extra midpadding on the right for the colorbar viewport_plotarea[2] -= 0.1 end + + # set our plot area view GR.setviewport(viewport_plotarea[1], viewport_plotarea[2], viewport_plotarea[3], viewport_plotarea[4]) - scale = 0 - d[:xscale] == :log10 && (scale |= GR.OPTION_X_LOG) - d[:yscale] == :log10 && (scale |= GR.OPTION_Y_LOG) - get(d, :xflip, false) && (scale |= GR.OPTION_FLIP_X) - get(d, :yflip, false) && (scale |= GR.OPTION_FLIP_Y) + # these are the Axis objects, which hold scale, lims, etc + xaxis = sp.attr[:xaxis] + yaxis = sp.attr[:yaxis] + zaxis = sp.attr[:zaxis] - for axis = 1:num_axes - xmin, xmax, ymin, ymax = extrema[axis,:] + scale = 0 + xaxis[:scale] == :log10 && (scale |= GR.OPTION_X_LOG) + yaxis[:scale] == :log10 && (scale |= GR.OPTION_X_LOG) + xaxis[:flip] && (scale |= GR.OPTION_X_LOG) + yaxis[:flip] && (scale |= GR.OPTION_X_LOG) + # d[:xscale] == :log10 && (scale |= GR.OPTION_X_LOG) + # d[:yscale] == :log10 && (scale |= GR.OPTION_Y_LOG) + # get(d, :xflip, false) && (scale |= GR.OPTION_FLIP_X) + # get(d, :yflip, false) && (scale |= GR.OPTION_FLIP_Y) + + for axis_idx = 1:num_axes + xmin, xmax, ymin, ymax = extrema[axis_idx,:] if scale & GR.OPTION_X_LOG == 0 xmin, xmax = GR.adjustlimits(xmin, xmax) majorx = 5 @@ -538,34 +593,35 @@ function gr_display(sp::Subplot{GRBackend}, w, h, canvas) yorg = (ymax, ymin) end - extrema[axis,:] = [xmin, xmax, ymin, ymax] + extrema[axis_idx,:] = [xmin, xmax, ymin, ymax] GR.setwindow(xmin, xmax, ymin, ymax) GR.setscale(scale) diag = sqrt((viewport_plotarea[2] - viewport_plotarea[1])^2 + (viewport_plotarea[4] - viewport_plotarea[3])^2) charheight = max(0.018 * diag, 0.01) GR.setcharheight(charheight) - GR.settextcolorind(fg) + GR.settextcolorind(gr_getcolorind(xaxis[:foreground_color_text])) if axes_2d GR.setlinewidth(1) - GR.setlinecolorind(gr_getcolorind(d[:foreground_color_grid])) + GR.setlinecolorind(gr_getcolorind(sp.attr[:foreground_color_grid])) ticksize = 0.0075 * diag if outside_ticks ticksize = -ticksize end if grid_flag - if dark_bg - GR.grid(xtick * majorx, ytick * majory, 0, 0, 1, 1) - else + # if dark_bg + # GR.grid(xtick * majorx, ytick * majory, 0, 0, 1, 1) + # else GR.grid(xtick, ytick, 0, 0, majorx, majory) - end + # end end - GR.setlinecolorind(gr_getcolorind(d[:foreground_color_axis])) + # TODO: this should be done for each axis separately + GR.setlinecolorind(gr_getcolorind(xaxis[:foreground_color_axis])) if num_axes == 1 GR.axes(xtick, ytick, xorg[1], yorg[1], majorx, majory, ticksize) GR.axes(xtick, ytick, xorg[2], yorg[2], -majorx, -majory, -ticksize) - elseif axis == 1 + elseif axis_idx == 1 GR.axes(xtick, ytick, xorg[1], yorg[1], majorx, majory, ticksize) else GR.axes(xtick, ytick, xorg[2], yorg[2], -majorx, majory, -ticksize) @@ -573,26 +629,26 @@ function gr_display(sp::Subplot{GRBackend}, w, h, canvas) end end - if get(d, :title, "") != "" + if sp.attr[:title] != "" GR.savestate() GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP) - GR.settextcolorind(fg) - GR.text(0.5 * (viewport_plotarea[1] + viewport_plotarea[2]), viewport_canvas[4], d[:title]) + GR.settextcolorind(gr_getcolorind(sp.attr[:foreground_color_title])) + GR.text(0.5 * (viewport_plotarea[1] + viewport_plotarea[2]), viewport_subplot[4], sp.attr[:title]) GR.restorestate() end - if get(d, :xguide, "") != "" + if xaxis[:guide] != "" GR.savestate() GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_BOTTOM) - GR.settextcolorind(fg) - GR.text(0.5 * (viewport_plotarea[1] + viewport_plotarea[2]), viewport_canvas[3], d[:xguide]) + GR.settextcolorind(gr_getcolorind(xaxis[:foreground_color_guide])) + GR.text(0.5 * (viewport_plotarea[1] + viewport_plotarea[2]), viewport_subplot[3], xaxis[:guide]) GR.restorestate() end - if get(d, :yguide, "") != "" + if yaxis[:guide] != "" GR.savestate() GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP) GR.setcharup(-1, 0) - GR.settextcolorind(fg) - GR.text(viewport_canvas[1], 0.5 * (viewport_plotarea[3] + viewport_plotarea[4]), d[:yguide]) + GR.settextcolorind(gr_getcolorind(yaxis[:foreground_color_guide])) + GR.text(viewport_subplot[1], 0.5 * (viewport_plotarea[3] + viewport_plotarea[4]), yaxis[:guide]) GR.restorestate() end # if get(d, :yrightlabel, "") != "" @@ -600,164 +656,202 @@ function gr_display(sp::Subplot{GRBackend}, w, h, canvas) # GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP) # GR.setcharup(1, 0) # GR.settextcolorind(fg) - # GR.text(viewport_canvas[2], 0.5 * (viewport_plotarea[3] + viewport_plotarea[4]), d[:yrightlabel]) + # GR.text(viewport_subplot[2], 0.5 * (viewport_plotarea[3] + viewport_plotarea[4]), d[:yrightlabel]) # GR.restorestate() # end GR.setcolormap(1000 + GR.COLORMAP_COOLWARM) - legend = falses(length(plt.seriesargs)) + # legend = falses(length(plt.seriesargs)) - for (ind, p) in enumerate(plt.seriesargs) - st = p[:seriestype] + # for (idx, d) in enumerate(plt.seriesargs) + for (idx, series) in enumerate(series_list(sp)) + d = series.d + # idx = d[:series_plotindex] + st = d[:seriestype] if st in (:hist2d, :hexbin, :contour, :surface, :wireframe, :heatmap) - if isa(p[:fillcolor], ColorGradient) - grad = p[:fillcolor] - else - grad = default_gradient() - end - cs = [getColorZ(grad, z) for z in linspace(0, 1, 256)] - for (i, c) in enumerate(cs) - GR.setcolorrep(999+i, red(c), green(c), blue(c)) - end - end - if get(d, :polar, false) - st = :polar + # grad = isa(d[:fillcolor], ColorGradient) ? d[:fillcolor] : default_gradient() + # cs = [getColorZ(grad, z) for z in linspace(0, 1, 256)] + # for (i, c) in enumerate(cs) + # GR.setcolorrep(999+i, red(c), green(c), blue(c)) + # end + gr_set_gradient(d[:fillcolor]) end + # if get(d, :polar, false) + # st = :polar + # end GR.savestate() - xmin, xmax, ymin, ymax = extrema[gr_getaxisind(p),:] + xmin, xmax, ymin, ymax = extrema[gr_getaxisind(d),:] GR.setwindow(xmin, xmax, ymin, ymax) if st in [:path, :line, :steppre, :steppost, :sticks, :hline, :vline, :polar] - GR.setlinetype(gr_linetype[p[:linestyle]]) - GR.setlinewidth(p[:linewidth]) - GR.setlinecolorind(gr_getcolorind(p[:linecolor])) + GR.setlinetype(gr_linetype[d[:linestyle]]) + GR.setlinewidth(d[:linewidth]) + GR.setlinecolorind(gr_getcolorind(d[:linecolor])) end - if st == :path - if length(p[:x]) > 1 - if p[:fillrange] != nothing - GR.setfillcolorind(gr_getcolorind(p[:fillcolor])) + + if ispolar(sp) + xmin, xmax, ymin, ymax = viewport_plotarea + ymax -= 0.05 * (xmax - xmin) + xcenter = 0.5 * (xmin + xmax) + ycenter = 0.5 * (ymin + ymax) + r = 0.5 * min(xmax - xmin, ymax - ymin) + GR.setviewport(xcenter -r, xcenter + r, ycenter - r, ycenter + r) + GR.setwindow(-1, 1, -1, 1) + rmin, rmax = GR.adjustrange(minimum(r), maximum(r)) + gr_polaraxes(rmin, rmax) + phi, r = d[:x], d[:y] + r = 0.5 * (r - rmin) / (rmax - rmin) + n = length(r) + x = zeros(n) + y = zeros(n) + for i in 1:n + x[i] = r[i] * cos(phi[i]) + y[i] = r[i] * sin(phi[i]) + end + GR.polyline(x, y) + + elseif st == :path + if length(d[:x]) > 1 + if d[:fillrange] != nothing + GR.setfillcolorind(gr_getcolorind(d[:fillcolor])) GR.setfillintstyle(GR.INTSTYLE_SOLID) - GR.fillarea([p[:x][1]; p[:x]; p[:x][length(p[:x])]], [p[:fillrange]; p[:y]; p[:fillrange]]) + GR.fillarea([d[:x][1]; d[:x]; d[:x][length(d[:x])]], [d[:fillrange]; d[:y]; d[:fillrange]]) end - GR.polyline(p[:x], p[:y]) + GR.polyline(d[:x], d[:y]) end - legend[ind] = true - end - if st == :line - if length(p[:x]) > 1 - gr_polyline(p[:x], p[:y]) - end - legend[ind] = true + # legend[idx] = true + + # # TODO: use recipe + # elseif st == :line + # if length(d[:x]) > 1 + # gr_polyline(d[:x], d[:y]) + # end + # # legend[idx] = true + + # TODO: use recipe elseif st in [:steppre, :steppost] - n = length(p[:x]) + n = length(d[:x]) x = zeros(2*n + 1) y = zeros(2*n + 1) - x[1], y[1] = p[:x][1], p[:y][1] + x[1], y[1] = d[:x][1], d[:y][1] j = 2 for i = 2:n if st == :steppre - x[j], x[j+1] = p[:x][i-1], p[:x][i] - y[j], y[j+1] = p[:y][i], p[:y][i] + x[j], x[j+1] = d[:x][i-1], d[:x][i] + y[j], y[j+1] = d[:y][i], d[:y][i] else - x[j], x[j+1] = p[:x][i], p[:x][i] - y[j], y[j+1] = p[:y][i-1], p[:y][i] + x[j], x[j+1] = d[:x][i], d[:x][i] + y[j], y[j+1] = d[:y][i-1], d[:y][i] end j += 2 end if n > 1 GR.polyline(x, y) end - legend[ind] = true + # legend[idx] = true + + # TODO: use recipe elseif st == :sticks - x, y = p[:x], p[:y] + x, y = d[:x], d[:y] for i = 1:length(y) GR.polyline([x[i], x[i]], [ymin, y[i]]) end - legend[ind] = true - elseif st == :scatter || (p[:markershape] != :none && axes_2d) - GR.setmarkercolorind(gr_getcolorind(p[:markercolor])) - gr_setmarkershape(p) - if typeof(p[:markersize]) <: Number - GR.setmarkersize(p[:markersize] / 4.0) - if length(p[:x]) > 0 - gr_polymarker(p, p[:x], p[:y]) + # legend[idx] = true + + elseif st == :scatter || (d[:markershape] != :none && axes_2d) + GR.setmarkercolorind(gr_getcolorind(d[:markercolor])) + gr_setmarkershape(d) + if typeof(d[:markersize]) <: Number + GR.setmarkersize(d[:markersize] / 4.0) + if length(d[:x]) > 0 + gr_polymarker(d, d[:x], d[:y]) end else - c = p[:markercolor] + c = d[:markercolor] GR.setcolormap(-GR.COLORMAP_GLOWING) - for i = 1:length(p[:x]) - if isa(c, ColorGradient) && p[:marker_z] != nothing - ci = round(Int, 1000 + p[:marker_z][i] * 255) + for i = 1:length(d[:x]) + if isa(c, ColorGradient) && d[:marker_z] != nothing + ci = round(Int, 1000 + d[:marker_z][i] * 255) GR.setmarkercolorind(ci) end - GR.setmarkersize(p[:markersize][i] / 4.0) - gr_polymarker(p, [p[:x][i]], [p[:y][i]]) + GR.setmarkersize(d[:markersize][i] / 4.0) + gr_polymarker(d, [d[:x][i]], [d[:y][i]]) end end - legend[ind] = true + # legend[idx] = true - # NOTE: these should just use the series recipes - # elseif st == :bar - # y = p[:y] - # for i = 1:length(y) - # GR.setfillcolorind(gr_getcolorind(p[:fillcolor])) - # GR.setfillintstyle(GR.INTSTYLE_SOLID) - # GR.fillrect(i-0.4, i+0.4, max(0, ymin), y[i]) - # GR.setfillcolorind(fg) - # GR.setfillintstyle(GR.INTSTYLE_HOLLOW) - # GR.fillrect(i-0.4, i+0.4, max(0, ymin), y[i]) - # end + # TODO: use recipe + elseif st == :bar + gr_barplot(series, d[:x], d[:y]) + # for i = 1:length(y) + # gr_fillrect(series, i-0.4, i+0.4, max(0, ymin), y[i]) + # # GR.setfillcolorind(gr_getcolorind(d[:fillcolor])) + # # GR.setfillintstyle(GR.INTSTYLE_SOLID) + # # GR.fillrect(i-0.4, i+0.4, max(0, ymin), y[i]) + # # GR.setfillcolorind(fg) + # # GR.setfillintstyle(GR.INTSTYLE_HOLLOW) + # # GR.fillrect(i-0.4, i+0.4, max(0, ymin), y[i]) + # end + + # # TODO: use recipe # elseif st in [:hist, :density] - # h = Base.hist(p[:y], p[:bins]) - # x, y = float(collect(h[1])), float(h[2]) - # for i = 2:length(y) - # GR.setfillcolorind(gr_getcolorind(p[:fillcolor])) - # GR.setfillintstyle(GR.INTSTYLE_SOLID) - # GR.fillrect(x[i-1], x[i], ymin, y[i]) - # GR.setfillcolorind(fg) - # GR.setfillintstyle(GR.INTSTYLE_HOLLOW) - # GR.fillrect(x[i-1], x[i], ymin, y[i]) - # end - # elseif st in [:hline, :vline] - # for xy in p[:y] - # if st == :hline - # GR.polyline([xmin, xmax], [xy, xy]) - # else - # GR.polyline([xy, xy], [ymin, ymax]) - # end - # end - # elseif st in [:hist2d, :hexbin] - # E = zeros(length(p[:x]),2) - # E[:,1] = p[:x] - # E[:,2] = p[:y] - # if isa(p[:bins], Tuple) - # xbins, ybins = p[:bins] - # else - # xbins = ybins = p[:bins] - # end - # x, y, H = Base.hist2d(E, xbins, ybins) - # counts = round(Int32, 1000 + 255 * H / maximum(H)) - # n, m = size(counts) - # GR.cellarray(xmin, xmax, ymin, ymax, n, m, counts) - # - # # NOTE: set viewport to the colorbar area, get character height, draw it, then reset viewport - # GR.setviewport(viewport_plotarea[2] + 0.02, viewport_plotarea[2] + 0.05, viewport_plotarea[3], viewport_plotarea[4]) - # zmin, zmax = gr_getzlims(d, 0, maximum(counts), false) - # GR.setspace(zmin, zmax, 0, 90) - # diag = sqrt((viewport_plotarea[2] - viewport_plotarea[1])^2 + (viewport_plotarea[4] - viewport_plotarea[3])^2) - # charheight = max(0.016 * diag, 0.01) - # GR.setcharheight(charheight) - # GR.colormap() - # GR.setviewport(viewport_plotarea[1], viewport_plotarea[2], viewport_plotarea[3], viewport_plotarea[4]) + # edges, counts = Base.hist(d[:y], d[:bins]) + # gr_barplot(series, edges, counts) + # # x, y = float(collect(h[1])), float(h[2]) + # # for i = 2:length(y) + # # GR.setfillcolorind(gr_getcolorind(d[:fillcolor])) + # # GR.setfillintstyle(GR.INTSTYLE_SOLID) + # # GR.fillrect(x[i-1], x[i], ymin, y[i]) + # # GR.setfillcolorind(fg) + # # GR.setfillintstyle(GR.INTSTYLE_HOLLOW) + # # GR.fillrect(x[i-1], x[i], ymin, y[i]) + # # end + + # TODO: use recipe + elseif st in [:hline, :vline] + for xy in d[:y] + if st == :hline + GR.polyline([xmin, xmax], [xy, xy]) + else + GR.polyline([xy, xy], [ymin, ymax]) + end + end + + # TODO: use recipe + elseif st in [:hist2d, :hexbin] + E = zeros(length(d[:x]),2) + E[:,1] = d[:x] + E[:,2] = d[:y] + if isa(d[:bins], Tuple) + xbins, ybins = d[:bins] + else + xbins = ybins = d[:bins] + end + x, y, H = Base.hist2d(E, xbins, ybins) + counts = round(Int32, 1000 + 255 * H / maximum(H)) + n, m = size(counts) + GR.cellarray(xmin, xmax, ymin, ymax, n, m, counts) + + # NOTE: set viewport to the colorbar area, get character height, draw it, then reset viewport + GR.setviewport(viewport_plotarea[2] + 0.02, viewport_plotarea[2] + 0.05, viewport_plotarea[3], viewport_plotarea[4]) + # zmin, zmax = gr_getzlims(d, 0, maximum(counts), false) + zmin, zmax = gr_lims(zaxis, false, (0, maximum(counts))) + GR.setspace(zmin, zmax, 0, 90) + diag = sqrt((viewport_plotarea[2] - viewport_plotarea[1])^2 + (viewport_plotarea[4] - viewport_plotarea[3])^2) + charheight = max(0.016 * diag, 0.01) + GR.setcharheight(charheight) + GR.colormap() + GR.setviewport(viewport_plotarea[1], viewport_plotarea[2], viewport_plotarea[3], viewport_plotarea[4]) elseif st == :contour - x, y, z = p[:x], p[:y], transpose_z(p, p[:z].surf, false) - zmin, zmax = gr_getzlims(d, minimum(z), maximum(z), false) + x, y, z = d[:x], d[:y], transpose_z(d, d[:z].surf, false) + # zmin, zmax = gr_getzlims(d, minimum(z), maximum(z), false) + zmin, zmax = gr_lims(zaxis, false) GR.setspace(zmin, zmax, 0, 90) - if typeof(p[:levels]) <: Array - h = p[:levels] + if typeof(d[:levels]) <: Array + h = d[:levels] else - h = linspace(zmin, zmax, p[:levels]) + h = linspace(zmin, zmax, d[:levels]) end GR.contour(x, y, h, reshape(z, length(x) * length(y)), 1000) GR.setviewport(viewport_plotarea[2] + 0.02, viewport_plotarea[2] + 0.05, viewport_plotarea[3], viewport_plotarea[4]) @@ -770,9 +864,11 @@ function gr_display(sp::Subplot{GRBackend}, w, h, canvas) GR.setcharheight(charheight) GR.axes(0, ztick, xmax, zmin, 0, 1, 0.005) GR.setviewport(viewport_plotarea[1], viewport_plotarea[2], viewport_plotarea[3], viewport_plotarea[4]) + elseif st in [:surface, :wireframe] - x, y, z = p[:x], p[:y], transpose_z(p, p[:z].surf, false) - zmin, zmax = gr_getzlims(d, minimum(z), maximum(z), true) + x, y, z = d[:x], d[:y], transpose_z(d, d[:z].surf, false) + # zmin, zmax = gr_getzlims(d, minimum(z), maximum(z), true) + zmin, zmax = gr_lims(zaxis, true) GR.setspace(zmin, zmax, 40, 70) xtick = GR.tick(xmin, xmax) / 2 ytick = GR.tick(ymin, ymax) / 2 @@ -800,9 +896,11 @@ function gr_display(sp::Subplot{GRBackend}, w, h, canvas) GR.setviewport(viewport_plotarea[2] + 0.07, viewport_plotarea[2] + 0.1, viewport_plotarea[3], viewport_plotarea[4]) GR.colormap() end + elseif st == :heatmap - x, y, z = p[:x], p[:y], transpose_z(p, p[:z].surf, false) - zmin, zmax = gr_getzlims(d, minimum(z), maximum(z), true) + x, y, z = d[:x], d[:y], transpose_z(d, d[:z].surf, false) + # zmin, zmax = gr_getzlims(d, minimum(z), maximum(z), true) + zmin, zmax = gr_lims(zaxis, true) GR.setspace(zmin, zmax, 0, 90) z = reshape(z, length(x) * length(y)) GR.surface(x, y, z, GR.OPTION_COLORED_MESH) @@ -811,9 +909,11 @@ function gr_display(sp::Subplot{GRBackend}, w, h, canvas) GR.colormap() GR.setviewport(viewport_plotarea[1], viewport_plotarea[2], viewport_plotarea[3], viewport_plotarea[4]) end + elseif st in [:path3d, :scatter3d] - x, y, z = p[:x], p[:y], p[:z] - zmin, zmax = gr_getzlims(d, minimum(z), maximum(z), true) + x, y, z = d[:x], d[:y], d[:z] + # zmin, zmax = gr_getzlims(d, minimum(z), maximum(z), true) + zmin, zmax = gr_lims(zaxis, true) GR.setspace(zmin, zmax, 40, 70) xtick = GR.tick(xmin, xmax) / 2 ytick = GR.tick(ymin, ymax) / 2 @@ -827,15 +927,15 @@ function gr_display(sp::Subplot{GRBackend}, w, h, canvas) GR.grid3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0) end if st == :scatter3d - GR.setmarkercolorind(gr_getcolorind(p[:markercolor])) - gr_setmarkershape(p) + GR.setmarkercolorind(gr_getcolorind(d[:markercolor])) + gr_setmarkershape(d) for i = 1:length(z) - px, py = GR.wc3towc(x[i], y[i], z[i]) - gr_polymarker(p, [px], [py]) + xi, yi = GR.wc3towc(x[i], y[i], z[i]) + gr_polymarker(d, [xi], [yi]) end else if length(x) > 0 - GR.setlinewidth(p[:linewidth]) + GR.setlinewidth(d[:linewidth]) GR.polyline3d(x, y, z) end end @@ -843,6 +943,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, canvas) GR.setcharheight(charheight) GR.axes3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2, -ticksize) GR.axes3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0, ticksize) + elseif st == :pie GR.selntran(0) GR.setfillintstyle(GR.INTSTYLE_SOLID) @@ -857,7 +958,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, canvas) r = 0.5 * (xmax - xmin) ymin, ymax = ycenter - r, ycenter + r end - labels, slices = p[:x], p[:y] + labels, slices = d[:x], d[:y] numslices = length(slices) total = sum(slices) a1 = 0 @@ -888,8 +989,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, canvas) a1 = a2 end GR.selntran(1) + elseif st == :image - img = p[:z].surf + img = d[:z].surf w, h = size(img) if eltype(img) <: Colors.AbstractGray grey = round(UInt8, float(img) * 255) @@ -901,103 +1003,90 @@ function gr_display(sp::Subplot{GRBackend}, w, h, canvas) round(Int, red(c) * 255) ), img) end GR.drawimage(xmin, xmax, ymin, ymax, w, h, rgba) - elseif st == :polar - xmin, xmax, ymin, ymax = viewport_plotarea - ymax -= 0.05 * (xmax - xmin) - xcenter = 0.5 * (xmin + xmax) - ycenter = 0.5 * (ymin + ymax) - r = 0.5 * min(xmax - xmin, ymax - ymin) - GR.setviewport(xcenter -r, xcenter + r, ycenter - r, ycenter + r) - GR.setwindow(-1, 1, -1, 1) - rmin, rmax = GR.adjustrange(minimum(r), maximum(r)) - gr_polaraxes(rmin, rmax) - phi, r = p[:x], p[:y] - r = 0.5 * (r - rmin) / (rmax - rmin) - n = length(r) - x = zeros(n) - y = zeros(n) - for i in 1:n - x[i] = r[i] * cos(phi[i]) - y[i] = r[i] * sin(phi[i]) - end - GR.polyline(x, y) end + GR.restorestate() end - if d[:legend] != :none && any(legend) == true + if sp.attr[:legend] != :none #&& any(legend) == true GR.savestate() GR.selntran(0) GR.setscale(0) w = 0 i = 0 n = 0 - for (ind, p) in enumerate(plt.seriesargs) - if !legend[ind] || p[:label] == "" - continue - end + # for (idx, d) in enumerate(plt.seriesargs) + for series in series_list(sp) + should_add_to_legend(series) || continue + # if !legend[idx] || d[:label] == "" + # continue + # end n += 1 - if typeof(p[:label]) <: Array + if typeof(series.d[:label]) <: Array i += 1 - lab = p[:label][i] + lab = series.d[:label][i] else - lab = p[:label] + lab = series.d[:label] end tbx, tby = GR.inqtext(0, 0, lab) w = max(w, tbx[3]) end - px = viewport_plotarea[2] - 0.05 - w - py = viewport_plotarea[4] - 0.06 + xpos = viewport_plotarea[2] - 0.05 - w + ypos = viewport_plotarea[4] - 0.06 dy = 0.03 * sqrt((viewport_plotarea[2] - viewport_plotarea[1])^2 + (viewport_plotarea[4] - viewport_plotarea[3])^2) GR.setfillintstyle(GR.INTSTYLE_SOLID) - GR.setfillcolorind(gr_getcolorind(d[:background_color_legend])) - GR.fillrect(px - 0.08, px + w + 0.02, py + dy, py - dy * n) + GR.setfillcolorind(gr_getcolorind(sp.attr[:background_color_legend])) + GR.fillrect(xpos - 0.08, xpos + w + 0.02, ypos + dy, ypos - dy * n) GR.setlinetype(1) GR.setlinewidth(1) - GR.drawrect(px - 0.08, px + w + 0.02, py + dy, py - dy * n) + GR.drawrect(xpos - 0.08, xpos + w + 0.02, ypos + dy, ypos - dy * n) i = 0 - for (ind, p) in enumerate(plt.seriesargs) - if !legend[ind] || p[:label] == "" - continue + # for (idx, d) in enumerate(plt.seriesargs) + for series in series_list(sp) + should_add_to_legend(series) || continue + # if !legend[idx] || d[:label] == "" + # continue + # end + d = series.d + st = d[:seriestype] + GR.setlinewidth(d[:linewidth]) + if d[:seriestype] in [:path, :line, :steppre, :steppost, :sticks] + GR.setlinecolorind(gr_getcolorind(d[:linecolor])) + GR.setlinetype(gr_linetype[d[:linestyle]]) + GR.polyline([xpos - 0.07, xpos - 0.01], [ypos, ypos]) end - GR.setlinewidth(p[:linewidth]) - if p[:seriestype] in [:path, :line, :steppre, :steppost, :sticks] - GR.setlinecolorind(gr_getcolorind(p[:linecolor])) - GR.setlinetype(gr_linetype[p[:linestyle]]) - GR.polyline([px - 0.07, px - 0.01], [py, py]) - end - if p[:seriestype] == :scatter || p[:markershape] != :none - GR.setmarkercolorind(gr_getcolorind(p[:markercolor])) - gr_setmarkershape(p) - if p[:seriestype] in [:path, :line, :steppre, :steppost, :sticks] - gr_polymarker(p, [px - 0.06, px - 0.02], [py, py]) + if d[:seriestype] == :scatter || d[:markershape] != :none + GR.setmarkercolorind(gr_getcolorind(d[:markercolor])) + gr_setmarkershape(d) + if d[:seriestype] in [:path, :line, :steppre, :steppost, :sticks] + gr_polymarker(d, [xpos - 0.06, xpos - 0.02], [ypos, ypos]) else - gr_polymarker(p, [px - 0.06, px - 0.04, px - 0.02], [py, py, py]) + gr_polymarker(d, [xpos - 0.06, xpos - 0.04, xpos - 0.02], [ypos, ypos, ypos]) end end - if typeof(p[:label]) <: Array + if typeof(d[:label]) <: Array i += 1 - lab = p[:label][i] + lab = d[:label][i] else - lab = p[:label] + lab = d[:label] end GR.settextalign(GR.TEXT_HALIGN_LEFT, GR.TEXT_VALIGN_HALF) - GR.settextcolorind(gr_getcolorind(d[:foreground_color_legend])) - GR.text(px, py, lab) - py -= dy + GR.settextcolorind(gr_getcolorind(sp.attr[:foreground_color_legend])) + GR.text(xpos, ypos, lab) + ypos -= dy end GR.selntran(1) GR.restorestate() end - if haskey(d, :annotations) + if haskey(sp.attr, :annotations) GR.savestate() - for ann in d[:anns] + for ann in sp.attr[:annotations] x, y, val = ann x, y = GR.wctondc(x, y) alpha = val.font.rotation family = lowercase(val.font.family) - GR.setcharheight(0.7 * val.font.pointsize / d[:size][2]) + GR.setcharheight(0.7 * val.font.pointsize / sp.plt.attr[:size][2]) GR.setcharup(sin(val.font.rotation), cos(val.font.rotation)) if haskey(gr_font_family, family) GR.settextfontprec(100 + gr_font_family[family], GR.TEXT_PRECISION_STRING) @@ -1012,50 +1101,75 @@ function gr_display(sp::Subplot{GRBackend}, w, h, canvas) # update && GR.updatews() end + # ---------------------------------------------------------------- -# clear, display, and update the plot... using in all output modes -function gr_finalize(plt::Plot{GRBackend}) - GR.clearws() +# Set the (left, top, right, bottom) minimum padding around the plot area +# to fit ticks, tick labels, guides, colorbars, etc. +function _update_min_padding!(sp::Subplot{GRBackend}) + sp.minpad = (10mm, 5mm, 3mm, 8mm) +end + +# # clear, display, and update the plot... using in all output modes +# function gr_finalize(plt::Plot{GRBackend}) +# GR.clearws() +# gr_display(plt) +# GR.updatews() +# end + +# # setup and tear down gks before and after displaying... used in IO output +# function gr_finalize_mime(plt::Plot{GRBackend}, wstype) +# GR.emergencyclosegks() +# ENV["GKS_WSTYPE"] = wstype +# gr_display(plt) +# GR.emergencyclosegks() +# end + +# ---------------------------------------------------------------- + +const _gr_mimeformats = Dict( + "application/pdf" => "pdf", + "image/png" => "png", + "application/postscript" => "ps", + "image/svg+xml" => "svg", +) + + +for (mime, fmt) in _gr_mimeformats + # @eval function Base.writemime(io::IO, ::MIME{symbol($mime)}, plt::Plot{PyPlotBackend}) + @eval function _writemime(io::IO, ::MIME{symbol($mime)}, plt::Plot{GRBackend}) + GR.emergencyclosegks() + ENV["GKS_WSTYPE"] = $fmt + gr_display(plt) + GR.emergencyclosegks() + write(io, readall("gks." * $fmt)) + end +end + +# function Base.writemime(io::IO, m::MIME"image/png", plt::Plot{GRBackend}) +# gr_display(plt, "png") +# write(io, readall("gks.png")) +# end +# +# function Base.writemime(io::IO, m::MIME"image/svg+xml", plt::Plot{GRBackend}) +# gr_display(plt, "svg") +# write(io, readall("gks.svg")) +# end +# +# # function Base.writemime(io::IO, m::MIME"text/html", plt::Plot{GRBackend}) +# # writemime(io, MIME("image/svg+xml"), plt) +# # end +# +# function Base.writemime(io::IO, m::MIME"application/pdf", plt::Plot{GRBackend}) +# gr_display(plt, "pdf") +# write(io, readall("gks.pdf")) +# end +# +# function Base.writemime(io::IO, m::MIME"application/postscript", plt::Plot{GRBackend}) +# gr_display(plt, "ps") +# write(io, readall("gks.ps")) +# end + +function _display(plt::Plot{GRBackend}) gr_display(plt) - GR.updatews() -end - -# setup and tear down gks before and after displaying... used in IO output -function gr_finalize(plt::Plot{GRBackend}, wstype) - GR.emergencyclosegks() - ENV["GKS_WSTYPE"] = wstype - gr_finalize(plt) - GR.emergencyclosegks() -end - -# ---------------------------------------------------------------- - -function Base.writemime(io::IO, m::MIME"image/png", plt::Plot{GRBackend}) - gr_finalize(plt, "png") - write(io, readall("gks.png")) -end - -function Base.writemime(io::IO, m::MIME"image/svg+xml", plt::Plot{GRBackend}) - gr_finalize(plt, "svg") - write(io, readall("gks.svg")) -end - -function Base.writemime(io::IO, m::MIME"text/html", plt::Plot{GRBackend}) - writemime(io, MIME("image/svg+xml"), plt) -end - -function Base.writemime(io::IO, m::MIME"application/pdf", plt::Plot{GRBackend}) - gr_finalize(plt, "pdf") - write(io, readall("gks.pdf")) -end - -function Base.writemime(io::IO, m::MIME"application/postscript", plt::Plot{GRBackend}) - gr_finalize(plt, "ps") - write(io, readall("gks.ps")) -end - -function Base.display(::PlotsDisplay, plt::Plot{GRBackend}) - # gr_display(plt) - gr_finalize(plt) end diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index b3337c11..9d1c03c4 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -1127,13 +1127,16 @@ function addPyPlotLegend(plt::Plot, sp::Subplot, ax) # gotta do this to ensure both axes are included labels = [] handles = [] - for series in plt.series_list - if get_subplot(series) === sp && - series.d[:label] != "" && - !(series.d[:seriestype] in ( - :hexbin,:hist2d,:hline,:vline, - :contour,:contour3d,:surface,:wireframe, - :heatmap,:path3d,:scatter3d, :pie, :image)) + # for series in plt.series_list + # if get_subplot(series) === sp && + # series.d[:label] != "" && + # !(series.d[:seriestype] in ( + # :hexbin,:hist2d,:hline,:vline, + # :contour,:contour3d,:surface,:wireframe, + # :heatmap,:path3d,:scatter3d, :pie, :image)) + for series in series_list(sp) + if should_add_to_legend(series) + # add a line/marker and a label push!(handles, if series.d[:seriestype] == :hist PyPlot.plt[:Line2D]((0,1),(0,0), color=pyfillcolor(series.d), linewidth=4) else @@ -1142,6 +1145,8 @@ function addPyPlotLegend(plt::Plot, sp::Subplot, ax) push!(labels, series.d[:label]) end end + + # if anything was added, call ax.legend and set the colors if !isempty(handles) leg = ax[:legend](handles, labels, diff --git a/src/backends/template.jl b/src/backends/template.jl index 6d989518..3d0efdc1 100644 --- a/src/backends/template.jl +++ b/src/backends/template.jl @@ -20,11 +20,11 @@ function _create_backend_figure(plt::Plot{[PkgName]Backend}) end # this is called early in the pipeline, use it to make the plot current or something -function _prepare_plot_object(plt::Plot{[PkgName]}) +function _prepare_plot_object(plt::Plot{[PkgName]Backend}) end # Set up the subplot within the backend object. -function _initialize_subplot(plt::Plot{PyPlotBackend}, sp::Subplot{PyPlotBackend}) +function _initialize_subplot(plt::Plot{[PkgName]Backend}, sp::Subplot{[PkgName]Backend}) end # --------------------------------------------------------------------------- @@ -42,7 +42,7 @@ end # called just before updating layout bounding boxes... in case you need to prep # for the calcs -function _before_layout_calcs(plt::Plot) +function _before_layout_calcs(plt::Plot{[PkgName]Backend}) end # Set the (left, top, right, bottom) minimum padding around the plot area diff --git a/src/output.jl b/src/output.jl index 6e0d0654..cf29734c 100644 --- a/src/output.jl +++ b/src/output.jl @@ -1,8 +1,8 @@ -defaultOutputFormat(plt::AbstractPlot) = "png" +defaultOutputFormat(plt::Plot) = "png" -function png(plt::AbstractPlot, fn::@compat(AbstractString)) +function png(plt::Plot, fn::@compat(AbstractString)) fn = addExtension(fn, "png") io = open(fn, "w") writemime(io, MIME("image/png"), plt) @@ -10,7 +10,7 @@ function png(plt::AbstractPlot, fn::@compat(AbstractString)) end png(fn::@compat(AbstractString)) = png(current(), fn) -function svg(plt::AbstractPlot, fn::@compat(AbstractString)) +function svg(plt::Plot, fn::@compat(AbstractString)) fn = addExtension(fn, "svg") io = open(fn, "w") writemime(io, MIME("image/svg+xml"), plt) @@ -19,7 +19,7 @@ end svg(fn::@compat(AbstractString)) = svg(current(), fn) -function pdf(plt::AbstractPlot, fn::@compat(AbstractString)) +function pdf(plt::Plot, fn::@compat(AbstractString)) fn = addExtension(fn, "pdf") io = open(fn, "w") writemime(io, MIME("application/pdf"), plt) @@ -28,7 +28,7 @@ end pdf(fn::@compat(AbstractString)) = pdf(current(), fn) -function ps(plt::AbstractPlot, fn::@compat(AbstractString)) +function ps(plt::Plot, fn::@compat(AbstractString)) fn = addExtension(fn, "ps") io = open(fn, "w") writemime(io, MIME("application/postscript"), plt) @@ -37,7 +37,7 @@ end ps(fn::@compat(AbstractString)) = ps(current(), fn) -function tex(plt::AbstractPlot, fn::@compat(AbstractString)) +function tex(plt::Plot, fn::@compat(AbstractString)) fn = addExtension(fn, "tex") io = open(fn, "w") writemime(io, MIME("application/x-tex"), plt) @@ -78,7 +78,7 @@ function addExtension(fn::@compat(AbstractString), ext::@compat(AbstractString)) end end -function savefig(plt::AbstractPlot, fn::@compat(AbstractString)) +function savefig(plt::Plot, fn::@compat(AbstractString)) # get the extension local ext @@ -101,7 +101,7 @@ savefig(fn::@compat(AbstractString)) = savefig(current(), fn) # --------------------------------------------------------- -gui(plt::AbstractPlot = current()) = display(PlotsDisplay(), plt) +gui(plt::Plot = current()) = display(PlotsDisplay(), plt) function Base.display(::PlotsDisplay, plt::Plot) prepare_output(plt) @@ -109,7 +109,7 @@ function Base.display(::PlotsDisplay, plt::Plot) end # override the REPL display to open a gui window -Base.display(::Base.REPL.REPLDisplay, ::MIME"text/plain", plt::AbstractPlot) = gui(plt) +Base.display(::Base.REPL.REPLDisplay, ::MIME"text/plain", plt::Plot) = gui(plt) # --------------------------------------------------------- @@ -123,12 +123,12 @@ const _mimeformats = Dict( ) # a backup for html... passes to svg -function Base.writemime(io::IO, ::MIME"text/html", plt::AbstractPlot) +function Base.writemime(io::IO, ::MIME"text/html", plt::Plot) writemime(io, MIME("image/svg+xml"), plt) end for mime in keys(_mimeformats) - @eval function writemime(io::IO, m::MIME{Symbol($mime)}, plt::Plot) + @eval function Base.writemime(io::IO, m::MIME{Symbol($mime)}, plt::Plot) prepare_output(plt) _writemime(io, m, plt) end @@ -151,13 +151,13 @@ function setup_ijulia() global _ijulia_output _ijulia_output[1] = mimestr end - function IJulia.display_dict(plt::AbstractPlot) + function IJulia.display_dict(plt::Plot) global _ijulia_output Dict{ASCIIString, ByteString}(_ijulia_output[1] => sprint(writemime, _ijulia_output[1], plt)) end end - # IJulia.display_dict(plt::AbstractPlot) = Dict{ASCIIString, ByteString}("text/html" => sprint(writemime, "text/html", plt)) + # IJulia.display_dict(plt::Plot) = Dict{ASCIIString, ByteString}("text/html" => sprint(writemime, "text/html", plt)) set_ijulia_output("text/html") end end @@ -174,15 +174,15 @@ function setup_atom() # connects the render function for T in (GadflyBackend,ImmerseBackend,PyPlotBackend,GRBackend) - Atom.Media.media(AbstractPlot{T}, Atom.Media.Plot) + Atom.Media.media(Plot{T}, Atom.Media.Plot) end # Atom.Media.media{T <: Union{GadflyBackend,ImmerseBackend,PyPlotBackend,GRBackend}}(Plot{T}, Atom.Media.Plot) - # Atom.displaysize(::AbstractPlot) = (535, 379) - # Atom.displaytitle(plt::AbstractPlot) = "Plots.jl (backend: $(backend(plt)))" + # Atom.displaysize(::Plot) = (535, 379) + # Atom.displaytitle(plt::Plot) = "Plots.jl (backend: $(backend(plt)))" # this is like "display"... sends an html div with the plot to the PlotPane - function Atom.Media.render(pane::Atom.PlotPane, plt::AbstractPlot) + function Atom.Media.render(pane::Atom.PlotPane, plt::Plot) Atom.Media.render(pane, Atom.div(Atom.d(), Atom.HTML(stringmime(MIME("text/html"), plt)))) end diff --git a/src/plot.jl b/src/plot.jl index bb2bca6f..efb27403 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -95,6 +95,7 @@ end # natively by the backend function _apply_series_recipe(plt::Plot, d::KW) st = d[:seriestype] + @show st if st in supportedTypes() # getting ready to add the series... last update to subplot from anything @@ -138,7 +139,7 @@ function _apply_series_recipe(plt::Plot, d::KW) else # get a sub list of series for this seriestype - series_list = try + datalist = try RecipesBase.apply_recipe(d, Val{st}, d[:x], d[:y], d[:z]) catch warn("Exception during apply_recipe(Val{$st}, ...) with types ($(typeof(d[:x])), $(typeof(d[:y])), $(typeof(d[:z])))") @@ -146,9 +147,9 @@ function _apply_series_recipe(plt::Plot, d::KW) end # assuming there was no error, recursively apply the series recipes - for series in series_list - if isa(series, Series) - _apply_series_recipe(plt, series.d) + for data in datalist + if isa(data, RecipeData) + _apply_series_recipe(plt, data.d) else warn("Unhandled series: $(series_list)") break @@ -221,6 +222,10 @@ function _plot!(plt::Plot, d::KW, args...) kw[:fillrange] = (kw[:y] - rib, kw[:y] + rib) end + # add the plot index + plt.n += 1 + kw[:series_plotindex] = plt.n + # check that the backend will support the command and add it to the list warnOnUnsupportedScales(plt.backend, kw) push!(kw_list, kw) @@ -248,9 +253,9 @@ function _plot!(plt::Plot, d::KW, args...) # this is it folks! # TODO: we probably shouldn't use i for tracking series index, but rather explicitly track it in recipes for (i,kw) in enumerate(kw_list) - if !(get(kw, :seriestype, :none) in (:xerror, :yerror)) - plt.n += 1 - end + # if !(get(kw, :seriestype, :none) in (:xerror, :yerror)) + # plt.n += 1 + # end # get the Subplot object to which the series belongs sp = get(kw, :subplot, :auto) diff --git a/src/recipes.jl b/src/recipes.jl index 236de2c8..9423237c 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -226,6 +226,55 @@ end () end +# create a path from steps +@recipe function f(::Type{Val{:steppre}}, x, y, z) + +end + +# create a bar plot as a filled step function +@recipe function f(::Type{Val{:bar}}, x, y, z) + nx, ny = length(x), length(y) + d[:x] = if nx == ny + # x is centers + halfwidths = 0.5 * diff(x) + vcat(halfwidths[1], halfwidths, halfwidths[end]) + elseif nx == ny + 1 + # x is edges + x + else + error("bar recipe: x must be same length as y (centers), or one more than y (edges).\n\t\tlength(x)=$(length(x)), length(y)=$(length(y))") + end + + # TODO: use y/fillrange to compute new y/fillrange vectors + + d[:seriestype] = :steppre + () +end + + + # # x is edges + # for i=1:n + # gr_fillrect(series, x[i], x[i+1], 0, y[i]) + # end + # elseif length(x) == n + # # x is centers + # leftwidth = length(x) > 1 ? abs(0.5 * (x[2] - x[1])) : 0.5 + # for i=1:n + # rightwidth = (i == n ? leftwidth : abs(0.5 * (x[i+1] - x[i]))) + # gr_fillrect(series, x[i] - leftwidth, x[i] + rightwidth, 0, y[i]) + # end + # else + # error("gr_barplot: x must be same length as y (centers), or one more than y (edges).\n\t\tlength(x)=$(length(x)), length(y)=$(length(y))") + # end + +@recipe function f(::Type{Val{:hist}}, x, y, z) + edges, counts = Base.hist(y, d[:bins]) + d[:x] = edges + d[:y] = counts + d[:seriestype] = :bar + () +end + # --------------------------------------------------------------------------- # Box Plot diff --git a/src/series_new.jl b/src/series_new.jl index bb590e23..6c12b9aa 100644 --- a/src/series_new.jl +++ b/src/series_new.jl @@ -7,7 +7,8 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int) # n = plt.n # attr = getattr(plt, n) # plotIndex = convertSeriesIndex(plt, n) - globalIndex = plt.n + # globalIndex = plt.n + globalIndex = d[:series_plotindex] # # add defaults? # for k in keys(_series_defaults) diff --git a/src/subplots.jl b/src/subplots.jl index 6b81bd19..7ec307d6 100644 --- a/src/subplots.jl +++ b/src/subplots.jl @@ -33,4 +33,14 @@ get_subplot(series::Series) = series.d[:subplot] get_subplot_index(plt::Plot, idx::Integer) = idx get_subplot_index(plt::Plot, sp::Subplot) = findfirst(_ -> _ === sp, plt.subplots) +series_list(sp::Subplot) = filter(series -> series.d[:subplot] === sp, sp.plt.series_list) + +function should_add_to_legend(series::Series) + !(series.d[:label] == "" || series.d[:seriestype] in ( + :hexbin,:hist2d,:hline,:vline, + :contour,:contour3d,:surface,:wireframe, + :heatmap,:path3d,:scatter3d, :pie, :image + )) +end + # ----------------------------------------------------------------------