added bar_position; fixed orientation handling; pyplot cleanup

This commit is contained in:
Thomas Breloff 2016-04-18 15:12:13 -04:00
parent 236a7dadc6
commit a2ea9db90e
4 changed files with 333 additions and 383 deletions

View File

@ -147,6 +147,7 @@ _seriesDefaults[:zcolor] = nothing # value for color scale
# _seriesDefaults[:nlevels] = 15 # _seriesDefaults[:nlevels] = 15
_seriesDefaults[:levels] = 15 _seriesDefaults[:levels] = 15
_seriesDefaults[:orientation] = :vertical _seriesDefaults[:orientation] = :vertical
_seriesDefaults[:bar_position] = :overlay # for bar plots and histograms: could also be stack (stack up) or dodge (side by side)
_seriesDefaults[:xerror] = nothing _seriesDefaults[:xerror] = nothing
_seriesDefaults[:yerror] = nothing _seriesDefaults[:yerror] = nothing
_seriesDefaults[:ribbon] = nothing _seriesDefaults[:ribbon] = nothing

View File

@ -39,7 +39,9 @@ function getLineGeom(d::KW)
elseif lt == :hist2d elseif lt == :hist2d
Gadfly.Geom.histogram2d(xbincount = xbins, ybincount = ybins) Gadfly.Geom.histogram2d(xbincount = xbins, ybincount = ybins)
elseif lt == :hist elseif lt == :hist
Gadfly.Geom.histogram(bincount = xbins) Gadfly.Geom.histogram(bincount = xbins,
orientation = isvertical(d) ? :vertical : :horizontal,
position = d[:bar_position] == :stack ? :stack : :dodge)
elseif lt == :path elseif lt == :path
Gadfly.Geom.path Gadfly.Geom.path
elseif lt in (:bar, :sticks) elseif lt in (:bar, :sticks)

View File

@ -144,15 +144,15 @@ getfig(wrap::PyPlotAxisWrapper) = wrap.fig
# get a reference to the correct axis # get a reference to the correct axis
function getLeftAxis(wrap::PyPlotAxisWrapper) function getLeftAxis(wrap::PyPlotAxisWrapper)
if wrap.ax == nothing if wrap.ax == nothing
axes = wrap.fig.o[:axes] axes = wrap.fig.o[:axes]
if isempty(axes) if isempty(axes)
return wrap.fig.o[:add_subplot](111; wrap.kwargs...) return wrap.fig.o[:add_subplot](111; wrap.kwargs...)
end
axes[1]
else
wrap.ax
end end
axes[1]
else
wrap.ax
end
end end
function getRightAxis(wrap::PyPlotAxisWrapper) function getRightAxis(wrap::PyPlotAxisWrapper)
@ -168,32 +168,31 @@ getAxis(plt::Plot{PyPlotBackend}, axis::Symbol) = (axis == :right ? getRightAxis
# left axis is PyPlot.<func>, right axis is "f.axes[0].twinx().<func>" # left axis is PyPlot.<func>, right axis is "f.axes[0].twinx().<func>"
function getPyPlotFunction(plt::Plot, axis::Symbol, linetype::Symbol) function getPyPlotFunction(plt::Plot, axis::Symbol, linetype::Symbol)
# # need to access mplot3d functions differently
# if linetype == :surface
# return mplot3d.pymember("Axes3D")[:plot_surface]
# end
# # need to access mplot3d functions differently # in the 2-axis case we need to get: <rightaxis>[:<func>]
# if linetype == :surface ax = getAxis(plt, axis)
# return mplot3d.pymember("Axes3D")[:plot_surface] # ax[:set_ylabel](plt.plotargs[:yrightlabel])
# end fmap = KW(
:hist => :hist,
# in the 2-axis case we need to get: <rightaxis>[:<func>] :density => :hist,
ax = getAxis(plt, axis) :sticks => :bar,
# ax[:set_ylabel](plt.plotargs[:yrightlabel]) :bar => :bar,
fmap = KW( :hist2d => :hexbin,
:hist => :hist, :hexbin => :hexbin,
:density => :hist, :scatter => :scatter,
:sticks => :bar, :contour => :contour,
:bar => :bar, :scatter3d => :scatter,
:hist2d => :hexbin, :surface => :plot_surface,
:hexbin => :hexbin, :wireframe => :plot_wireframe,
:scatter => :scatter, :heatmap => :pcolor,
:contour => :contour, :shape => :add_patch,
:scatter3d => :scatter, # :surface => pycolors.pymember("LinearSegmentedColormap")[:from_list]
:surface => :plot_surface,
:wireframe => :plot_wireframe,
:heatmap => :pcolor,
:shape => :add_patch,
# :surface => pycolors.pymember("LinearSegmentedColormap")[:from_list]
) )
return ax[get(fmap, linetype, :plot)] return ax[get(fmap, linetype, :plot)]
end end
@ -286,233 +285,233 @@ end
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
function _add_series(pkg::PyPlotBackend, plt::Plot; kw...) function _add_series(pkg::PyPlotBackend, plt::Plot; kw...)
d = KW(kw) d = KW(kw)
# 3D plots have a different underlying Axes object in PyPlot # 3D plots have a different underlying Axes object in PyPlot
lt = d[:linetype] lt = d[:linetype]
if lt in _3dTypes && isempty(plt.o.kwargs) if lt in _3dTypes && isempty(plt.o.kwargs)
push!(plt.o.kwargs, (:projection, "3d")) push!(plt.o.kwargs, (:projection, "3d"))
end
# handle mismatched x/y sizes, as PyPlot doesn't like that
x, y = d[:x], d[:y]
if !isa(get(d, :z, nothing), Surface)
nx, ny = map(length, (x,y))
if nx < ny
d[:x] = Float64[x[mod1(i,nx)] for i=1:ny]
else
d[:y] = Float64[y[mod1(i,ny)] for i=1:nx]
end
end
ax = getAxis(plt, d[:axis])
if !(lt in supportedTypes(pkg))
error("linetype $(lt) is unsupported in PyPlot. Choose from: $(supportedTypes(pkg))")
end
color = getPyPlotColor(d[:linecolor], d[:linealpha])
if lt == :sticks
d,_ = sticksHack(;d...)
elseif lt in (:scatter, :scatter3d)
if d[:markershape] == :none
d[:markershape] = :ellipse
end end
elseif lt in (:hline,:vline) # handle mismatched x/y sizes, as PyPlot doesn't like that
linewidth = d[:linewidth] x, y = d[:x], d[:y]
linecolor = color nx, ny = length(x), length(y)
if !isa(get(d, :z, nothing), Surface) && nx != ny
if nx < ny
d[:x] = Float64[x[mod1(i,nx)] for i=1:ny]
else
d[:y] = Float64[y[mod1(i,ny)] for i=1:nx]
end
end
ax = getAxis(plt, d[:axis])
if !(lt in supportedTypes(pkg))
error("linetype $(lt) is unsupported in PyPlot. Choose from: $(supportedTypes(pkg))")
end
linecolor = getPyPlotColor(d[:linecolor], d[:linealpha])
markercolor = getPyPlotColor(d[:markercolor], d[:markeralpha])
fillcolor = getPyPlotColor(d[:fillcolor], d[:fillalpha])
strokecolor = getPyPlotColor(d[:markerstrokecolor], d[:markerstrokealpha])
linecmap = getPyPlotColorMap(d[:linecolor], d[:linealpha])
fillcmap = getPyPlotColorMap(d[:fillcolor], d[:fillalpha])
linestyle = getPyPlotLineStyle(lt, d[:linestyle]) linestyle = getPyPlotLineStyle(lt, d[:linestyle])
for yi in d[:y]
func = ax[lt == :hline ? :axhline : :axvline] if lt == :sticks
func(yi, linewidth=d[:linewidth], color=linecolor, linestyle=linestyle) d,_ = sticksHack(;d...)
elseif lt in (:scatter, :scatter3d)
if d[:markershape] == :none
d[:markershape] = :ellipse
end
elseif lt in (:hline,:vline)
for yi in d[:y]
func = ax[lt == :hline ? :axhline : :axvline]
func(yi, linewidth=d[:linewidth], color=linecolor, linestyle=linestyle)
end
end end
end extra_kwargs = KW()
plotfunc = getPyPlotFunction(plt, d[:axis], lt)
# lt = d[:linetype] # we have different args depending on plot type
extra_kwargs = KW() if lt in (:hist, :density, :sticks, :bar)
plotfunc = getPyPlotFunction(plt, d[:axis], lt) # NOTE: this is unsupported because it does the wrong thing... it shifts the whole axis
# extra_kwargs[:bottom] = d[:fill]
# we have different args depending on plot type if like_histogram(lt)
if lt in (:hist, :density, :sticks, :bar) extra_kwargs[:bins] = d[:nbins]
extra_kwargs[:normed] = lt == :density
extra_kwargs[:orientation] = isvertical(d) ? "vertical" : "horizontal"
extra_kwargs[:histtype] = d[:bar_position] == :stack ? "barstacked" : "bar"
else
extra_kwargs[:linewidth] = (lt == :sticks ? 0.1 : 0.9)
end
# NOTE: this is unsupported because it does the wrong thing... it shifts the whole axis elseif lt in (:hist2d, :hexbin)
# extra_kwargs[:bottom] = d[:fill] extra_kwargs[:gridsize] = d[:nbins]
extra_kwargs[:cmap] = linecmap
if like_histogram(lt) elseif lt == :contour
extra_kwargs[:bins] = d[:nbins] extra_kwargs[:cmap] = linecmap
extra_kwargs[:normed] = lt == :density extra_kwargs[:linewidths] = d[:linewidth]
else extra_kwargs[:linestyles] = linestyle
extra_kwargs[:linewidth] = (lt == :sticks ? 0.1 : 0.9) # TODO: will need to call contourf to fill in the contours
end
elseif lt in (:hist2d, :hexbin) elseif lt in (:surface, :wireframe)
extra_kwargs[:gridsize] = d[:nbins] if lt == :surface
extra_kwargs[:cmap] = getPyPlotColorMap(d[:linecolor]) extra_kwargs[:cmap] = fillcmap
end
extra_kwargs[:rstride] = 1
extra_kwargs[:cstride] = 1
extra_kwargs[:linewidth] = d[:linewidth]
extra_kwargs[:edgecolor] = linecolor
elseif lt == :contour elseif lt == :heatmap
extra_kwargs[:cmap] = getPyPlotColorMap(d[:linecolor]) extra_kwargs[:cmap] = fillcmap
extra_kwargs[:linewidths] = d[:linewidth]
extra_kwargs[:linestyles] = getPyPlotLineStyle(lt, d[:linestyle])
# TODO: will need to call contourf to fill in the contours
elseif lt in (:surface, :wireframe)
if lt == :surface
extra_kwargs[:cmap] = getPyPlotColorMap(d[:fillcolor], d[:fillalpha])
end
extra_kwargs[:rstride] = 1
extra_kwargs[:cstride] = 1
extra_kwargs[:linewidth] = d[:linewidth]
extra_kwargs[:edgecolor] = getPyPlotColor(d[:linecolor], d[:linealpha])
elseif lt == :heatmap
extra_kwargs[:cmap] = getPyPlotColorMap(d[:fillcolor], d[:fillalpha])
elseif lt == :shape elseif lt == :shape
extra_kwargs[:edgecolor] = getPyPlotColor(d[:markerstrokecolor], d[:markerstrokealpha]) extra_kwargs[:edgecolor] = strokecolor
extra_kwargs[:facecolor] = getPyPlotColor(d[:markercolor], d[:markeralpha]) extra_kwargs[:facecolor] = markercolor
extra_kwargs[:linewidth] = d[:markerstrokewidth] extra_kwargs[:linewidth] = d[:markerstrokewidth]
extra_kwargs[:fill] = true extra_kwargs[:fill] = true
else else
extra_kwargs[:linestyle] = getPyPlotLineStyle(lt, d[:linestyle]) extra_kwargs[:linestyle] = linestyle
extra_kwargs[:marker] = getPyPlotMarker(d[:markershape]) extra_kwargs[:marker] = getPyPlotMarker(d[:markershape])
if lt in (:scatter, :scatter3d) if lt in (:scatter, :scatter3d)
extra_kwargs[:s] = d[:markersize].^2 extra_kwargs[:s] = d[:markersize].^2
c = d[:markercolor] c = d[:markercolor]
if d[:zcolor] != nothing if d[:zcolor] != nothing
if !isa(c, ColorGradient) if !isa(c, ColorGradient)
c = default_gradient() c = default_gradient()
end
extra_kwargs[:c] = convert(Vector{Float64}, d[:zcolor])
extra_kwargs[:cmap] = getPyPlotColorMap(c, d[:markeralpha])
else
ppc = getPyPlotColor(c, d[:markeralpha])
# total hack due to PyPlot bug (see issue #145).
# hack: duplicate the color vector when the total rgba fields is the same as the series length
if (typeof(ppc) <: AbstractArray && length(ppc)*4 == length(x)) || (typeof(ppc) <: Tuple && length(x) == 4)
ppc = vcat(ppc, ppc)
end
extra_kwargs[:c] = ppc
end
extra_kwargs[:edgecolors] = strokecolor
extra_kwargs[:linewidths] = d[:markerstrokewidth]
else
extra_kwargs[:markersize] = d[:markersize]
extra_kwargs[:markerfacecolor] = markercolor
extra_kwargs[:markeredgecolor] = strokecolor
extra_kwargs[:markeredgewidth] = d[:markerstrokewidth]
extra_kwargs[:drawstyle] = getPyPlotStepStyle(lt)
end end
extra_kwargs[:c] = convert(Vector{Float64}, d[:zcolor]) end
extra_kwargs[:cmap] = getPyPlotColorMap(c, d[:markeralpha])
else
ppc = getPyPlotColor(c, d[:markeralpha])
# total hack due to PyPlot bug (see issue #145). # set these for all types
# hack: duplicate the color vector when the total rgba fields is the same as the series length if !(lt in (:contour,:surface,:wireframe,:heatmap))
if (typeof(ppc) <: AbstractArray && length(ppc)*4 == length(x)) || if !(lt in (:scatter, :scatter3d, :shape))
(typeof(ppc) <: Tuple && length(x) == 4) extra_kwargs[:color] = linecolor
ppc = vcat(ppc, ppc) extra_kwargs[:linewidth] = d[:linewidth]
end end
extra_kwargs[:c] = ppc extra_kwargs[:label] = d[:label]
extra_kwargs[:zorder] = plt.n
end
extra_kwargs[:edgecolors] = getPyPlotColor(d[:markerstrokecolor], d[:markerstrokealpha])
extra_kwargs[:linewidths] = d[:markerstrokewidth]
else
extra_kwargs[:markersize] = d[:markersize]
extra_kwargs[:markerfacecolor] = getPyPlotColor(d[:markercolor], d[:markeralpha])
extra_kwargs[:markeredgecolor] = getPyPlotColor(d[:markerstrokecolor], d[:markerstrokealpha])
extra_kwargs[:markeredgewidth] = d[:markerstrokewidth]
extra_kwargs[:drawstyle] = getPyPlotStepStyle(lt)
end end
end
# set these for all types # do the plot
if !(lt in (:contour,:surface,:wireframe,:heatmap)) d[:serieshandle] = if like_histogram(lt)
if !(lt in (:scatter, :scatter3d, :shape)) extra_kwargs[:color] = fillcolor
extra_kwargs[:color] = color extra_kwargs[:edgecolor] = linecolor
extra_kwargs[:linewidth] = d[:linewidth] plotfunc(d[:y]; extra_kwargs...)[1]
elseif lt == :contour
x, y = d[:x], d[:y]
surf = d[:z].surf'
levels = d[:levels]
if isscalar(levels)
extra_args = (levels)
elseif isvector(levels)
extra_args = ()
extra_kwargs[:levels] = levels
else
error("Only numbers and vectors are supported with levels keyword")
end
handle = plotfunc(x, y, surf, extra_args...; extra_kwargs...)
if d[:fillrange] != nothing
extra_kwargs[:cmap] = fillcmap
delete!(extra_kwargs, :linewidths)
handle = ax[:contourf](x, y, surf, extra_args...; extra_kwargs...)
end
handle
elseif lt in (:surface,:wireframe)
x, y, z = Array(d[:x]), Array(d[:y]), Array(d[:z])
if !ismatrix(x) || !ismatrix(y)
x = repmat(x', length(y), 1)
y = repmat(y, 1, length(d[:x]))
z = z'
end
plotfunc(x, y, z; extra_kwargs...)
elseif lt in _3dTypes
plotfunc(d[:x], d[:y], d[:z]; extra_kwargs...)[1]
elseif lt in (:scatter, :hist2d, :hexbin)
plotfunc(d[:x], d[:y]; extra_kwargs...)
elseif lt == :heatmap
x, y, z = d[:x], d[:y], d[:z].surf'
plotfunc(heatmap_edges(x), heatmap_edges(y), z; extra_kwargs...)
elseif lt == :shape
path = buildPyPlotPath(d[:x], d[:y])
patches = pypatches.pymember("PathPatch")(path; extra_kwargs...)
plotfunc(patches)
else # plot
plotfunc(d[:x], d[:y]; extra_kwargs...)[1]
end end
extra_kwargs[:label] = d[:label]
extra_kwargs[:zorder] = plt.n
end
# do the plot # smoothing
d[:serieshandle] = if like_histogram(lt) handleSmooth(plt, ax, d, d[:smooth])
plotfunc(d[:y]; extra_kwargs...)[1]
elseif lt == :contour # add the colorbar legend
x, y = d[:x], d[:y] if plt.plotargs[:colorbar] != :none && haskey(extra_kwargs, :cmap)
surf = d[:z].surf' PyPlot.colorbar(d[:serieshandle], ax=ax)
levels = d[:levels]
if isscalar(levels)
extra_args = (levels)
elseif isvector(levels)
extra_args = ()
extra_kwargs[:levels] = levels
else
error("Only numbers and vectors are supported with levels keyword")
end end
handle = plotfunc(x, y, surf, extra_args...; extra_kwargs...)
if d[:fillrange] != nothing # this sets the bg color inside the grid
extra_kwargs[:cmap] = getPyPlotColorMap(d[:fillcolor], d[:fillalpha]) ax[:set_axis_bgcolor](getPyPlotColor(plt.plotargs[:background_color]))
delete!(extra_kwargs, :linewidths)
handle = ax[:contourf](x, y, surf, extra_args...; extra_kwargs...) fillrange = d[:fillrange]
if fillrange != nothing && lt != :contour
if typeof(fillrange) <: @compat(Union{Real, AVec})
ax[:fill_between](d[:x], fillrange, d[:y], facecolor = fillcolor, zorder = plt.n)
else
ax[:fill_between](d[:x], fillrange..., facecolor = fillcolor, zorder = plt.n)
end
end end
handle
elseif lt in (:surface,:wireframe) push!(plt.seriesargs, d)
x, y, z = Array(d[:x]), Array(d[:y]), Array(d[:z]) plt
if !ismatrix(x) || !ismatrix(y)
x = repmat(x', length(y), 1)
y = repmat(y, 1, length(d[:x]))
z = z'
end
plotfunc(x, y, z; extra_kwargs...)
elseif lt in _3dTypes
plotfunc(d[:x], d[:y], d[:z]; extra_kwargs...)[1]
elseif lt in (:scatter, :hist2d, :hexbin)
plotfunc(d[:x], d[:y]; extra_kwargs...)
elseif lt == :heatmap
x, y, z = d[:x], d[:y], d[:z].surf'
plotfunc(heatmap_edges(x), heatmap_edges(y), z; extra_kwargs...)
elseif lt == :shape
path = buildPyPlotPath(d[:x], d[:y])
patches = pypatches.pymember("PathPatch")(path; extra_kwargs...)
plotfunc(patches)
else # plot
plotfunc(d[:x], d[:y]; extra_kwargs...)[1]
end
# smoothing
handleSmooth(plt, ax, d, d[:smooth])
# add the colorbar legend
if plt.plotargs[:colorbar] != :none && haskey(extra_kwargs, :cmap)
PyPlot.colorbar(d[:serieshandle], ax=ax)
end
# @show extra_kwargs
# this sets the bg color inside the grid
ax[:set_axis_bgcolor](getPyPlotColor(plt.plotargs[:background_color]))
fillrange = d[:fillrange]
if fillrange != nothing && lt != :contour
fillcolor = getPyPlotColor(d[:fillcolor], d[:fillalpha])
if typeof(fillrange) <: @compat(Union{Real, AVec})
ax[:fill_between](d[:x], fillrange, d[:y], facecolor = fillcolor, zorder = plt.n)
else
ax[:fill_between](d[:x], fillrange..., facecolor = fillcolor, zorder = plt.n)
end
end
push!(plt.seriesargs, d)
plt
end end
# ----------------------------------------------------------------- # -----------------------------------------------------------------
# given a dimension (:x, :y, or :z), loop over the seriesargs KWs to find the min/max of the underlying data
function minmaxseries(ds, vec, axis) function minmaxseries(ds, dimension, axis)
lo, hi = Inf, -Inf lo, hi = Inf, -Inf
for d in ds for d in ds
d[:axis] == axis || continue d[:axis] == axis || continue
v = d[vec] v = d[dimension]
if length(v) > 0 if length(v) > 0
vlo, vhi = extrema(v) vlo, vhi = extrema(v)
lo = min(lo, vlo) lo = min(lo, vlo)
@ -545,16 +544,6 @@ end
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
# function getxy(plt::Plot{PyPlotBackend}, i::Integer)
# series = plt.seriesargs[i][:serieshandle]
# try
# return series[:get_data]()
# catch
# xy = series[:get_offsets]()
# return vec(xy[:,1]), vec(xy[:,2])
# end
# end
function setxy!{X,Y}(plt::Plot{PyPlotBackend}, xy::Tuple{X,Y}, i::Integer) function setxy!{X,Y}(plt::Plot{PyPlotBackend}, xy::Tuple{X,Y}, i::Integer)
d = plt.seriesargs[i] d = plt.seriesargs[i]
d[:x], d[:y] = xy d[:x], d[:y] = xy
@ -571,18 +560,11 @@ end
function setxyz!{X,Y,Z}(plt::Plot{PyPlotBackend}, xyz::Tuple{X,Y,Z}, i::Integer) function setxyz!{X,Y,Z}(plt::Plot{PyPlotBackend}, xyz::Tuple{X,Y,Z}, i::Integer)
d = plt.seriesargs[i] d = plt.seriesargs[i]
# @show typeof(d), typeof(xyz)
d[:x], d[:y], d[:z] = xyz d[:x], d[:y], d[:z] = xyz
series = d[:serieshandle] series = d[:serieshandle]
# @show keys(series) series[:set_data](d[:x], d[:y])
# try series[:set_3d_properties](d[:z])
series[:set_data](d[:x], d[:y])
series[:set_3d_properties](d[:z])
# catch
# series[:set_offsets](hcat(d[:x], d[:y], d[:z]))
# end
set_lims!(plt, d[:axis]) set_lims!(plt, d[:axis])
# dumpdict(d, "H",true)
plt plt
end end
@ -705,100 +687,92 @@ end
# ----------------------------------------------------------------- # -----------------------------------------------------------------
function createPyPlotAnnotationObject(plt::Plot{PyPlotBackend}, x, y, val::@compat(AbstractString)) function createPyPlotAnnotationObject(plt::Plot{PyPlotBackend}, x, y, val::@compat(AbstractString))
ax = getLeftAxis(plt) ax = getLeftAxis(plt)
ax[:annotate](val, xy = (x,y)) ax[:annotate](val, xy = (x,y))
end end
function createPyPlotAnnotationObject(plt::Plot{PyPlotBackend}, x, y, val::PlotText) function createPyPlotAnnotationObject(plt::Plot{PyPlotBackend}, x, y, val::PlotText)
ax = getLeftAxis(plt) ax = getLeftAxis(plt)
ax[:annotate](val.str, ax[:annotate](val.str,
xy = (x,y), xy = (x,y),
family = val.font.family, family = val.font.family,
color = getPyPlotColor(val.font.color), color = getPyPlotColor(val.font.color),
horizontalalignment = val.font.halign == :hcenter ? "center" : string(val.font.halign), horizontalalignment = val.font.halign == :hcenter ? "center" : string(val.font.halign),
verticalalignment = val.font.valign == :vcenter ? "center" : string(val.font.valign), verticalalignment = val.font.valign == :vcenter ? "center" : string(val.font.valign),
rotation = val.font.rotation * 180 / π, rotation = val.font.rotation * 180 / π,
size = val.font.pointsize size = val.font.pointsize
) )
end end
function _add_annotations{X,Y,V}(plt::Plot{PyPlotBackend}, anns::AVec{@compat(Tuple{X,Y,V})}) function _add_annotations{X,Y,V}(plt::Plot{PyPlotBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
for ann in anns for ann in anns
createPyPlotAnnotationObject(plt, ann...) createPyPlotAnnotationObject(plt, ann...)
end end
end end
# ----------------------------------------------------------------- # -----------------------------------------------------------------
# NOTE: pyplot needs to build before
function _create_subplot(subplt::Subplot{PyPlotBackend}, isbefore::Bool) function _create_subplot(subplt::Subplot{PyPlotBackend}, isbefore::Bool)
l = subplt.layout l = subplt.layout
plotargs = getplotargs(subplt, 1)
fig = pyplot_figure(plotargs)
# w,h = map(px2inch, getplotargs(subplt,1)[:size]) nr = nrows(l)
# bgcolor = getPyPlotColor(getplotargs(subplt,1)[:background_color]) for (i,(r,c)) in enumerate(l)
# fig = PyPlot.figure(; figsize = (w,h), facecolor = bgcolor, dpi = DPI, tight_layout = true) # add the plot to the figure
plotargs = getplotargs(subplt, 1) nc = ncols(l, r)
fig = pyplot_figure(plotargs) fakeidx = (r-1) * nc + c
ax = fig[:add_subplot](nr, nc, fakeidx)
nr = nrows(l) subplt.plts[i].o = PyPlotAxisWrapper(ax, nothing, fig, [])
for (i,(r,c)) in enumerate(l) pyplot_3d_setup!(subplt.plts[i].o, plotargs)
end
# add the plot to the figure subplt.o = PyPlotAxisWrapper(nothing, nothing, fig, [])
nc = ncols(l, r) pyplot_3d_setup!(subplt.o, plotargs)
fakeidx = (r-1) * nc + c true
ax = fig[:add_subplot](nr, nc, fakeidx)
subplt.plts[i].o = PyPlotAxisWrapper(ax, nothing, fig, [])
pyplot_3d_setup!(subplt.plts[i].o, plotargs)
end
# subplt.o = PyPlotFigWrapper(fig, [])
subplt.o = PyPlotAxisWrapper(nothing, nothing, fig, [])
pyplot_3d_setup!(subplt.o, plotargs)
true
end end
# this will be called internally, when creating a subplot from existing plots # this will be called internally, when creating a subplot from existing plots
# NOTE: if I ever need to "Rebuild a "ubplot from individual Plot's"... this is what I should use! # NOTE: if I ever need to "Rebuild a "ubplot from individual Plot's"... this is what I should use!
function subplot(plts::AVec{Plot{PyPlotBackend}}, layout::SubplotLayout, d::KW) function subplot(plts::AVec{Plot{PyPlotBackend}}, layout::SubplotLayout, d::KW)
validateSubplotSupported() validateSubplotSupported()
p = length(layout) p = length(layout)
n = sum([plt.n for plt in plts]) n = sum([plt.n for plt in plts])
pkg = PyPlotBackend() pkg = PyPlotBackend()
newplts = Plot{PyPlotBackend}[_create_plot(pkg; subplot=true, plt.plotargs...) for plt in plts] newplts = Plot{PyPlotBackend}[_create_plot(pkg; subplot=true, plt.plotargs...) for plt in plts]
subplt = Subplot(nothing, newplts, PyPlotBackend(), p, n, layout, d, true, false, false, (r,c) -> (nothing,nothing)) subplt = Subplot(nothing, newplts, PyPlotBackend(), p, n, layout, d, true, false, false, (r,c) -> (nothing,nothing))
_preprocess_subplot(subplt, d) _preprocess_subplot(subplt, d)
_create_subplot(subplt, true) _create_subplot(subplt, true)
for (i,plt) in enumerate(plts) for (i,plt) in enumerate(plts)
for seriesargs in plt.seriesargs for seriesargs in plt.seriesargs
# _add_series_subplot(newplts[i]; seriesargs...) _add_series_subplot(newplts[i], seriesargs)
_add_series_subplot(newplts[i], seriesargs) end
end end
end
_postprocess_subplot(subplt, d) _postprocess_subplot(subplt, d)
subplt subplt
end end
function _remove_axis(plt::Plot{PyPlotBackend}, isx::Bool) function _remove_axis(plt::Plot{PyPlotBackend}, isx::Bool)
if isx if isx
plot!(plt, xticks=zeros(0), xlabel="") plot!(plt, xticks=zeros(0), xlabel="")
else else
plot!(plt, yticks=zeros(0), ylabel="") plot!(plt, yticks=zeros(0), ylabel="")
end end
end end
function _expand_limits(lims, plt::Plot{PyPlotBackend}, isx::Bool) function _expand_limits(lims, plt::Plot{PyPlotBackend}, isx::Bool)
pltlims = plt.o.ax[isx ? :get_xbound : :get_ybound]() pltlims = plt.o.ax[isx ? :get_xbound : :get_ybound]()
_expand_limits(lims, pltlims) _expand_limits(lims, pltlims)
end end
# ----------------------------------------------------------------- # -----------------------------------------------------------------
@ -812,88 +786,62 @@ const _pyplot_legend_pos = KW(
# function addPyPlotLegend(plt::Plot) # function addPyPlotLegend(plt::Plot)
function addPyPlotLegend(plt::Plot, ax) function addPyPlotLegend(plt::Plot, ax)
leg = plt.plotargs[:legend] leg = plt.plotargs[:legend]
if leg != :none if leg != :none
# gotta do this to ensure both axes are included # gotta do this to ensure both axes are included
args = filter(x -> !(x[:linetype] in (:hist,:density,:hexbin,:hist2d,:hline,:vline,:contour,:surface,:wireframe,:heatmap,:path3d,:scatter3d)), plt.seriesargs) args = filter(x -> !(x[:linetype] in (:hist,:density,:hexbin,:hist2d,:hline,:vline,:contour,:surface,:wireframe,:heatmap,:path3d,:scatter3d)), plt.seriesargs)
args = filter(x -> x[:label] != "", args) args = filter(x -> x[:label] != "", args)
if length(args) > 0 if length(args) > 0
leg = ax[:legend]([d[:serieshandle] for d in args], leg = ax[:legend]([d[:serieshandle] for d in args],
[d[:label] for d in args], [d[:label] for d in args],
loc = get(_pyplot_legend_pos, leg, "best"), loc = get(_pyplot_legend_pos, leg, "best"),
fontsize = plt.plotargs[:legendfont].pointsize fontsize = plt.plotargs[:legendfont].pointsize
# framealpha = 0.6 # framealpha = 0.6
) )
leg[:set_zorder](1000) leg[:set_zorder](1000)
end
end end
end
end end
# -----------------------------------------------------------------
function finalizePlot(plt::Plot{PyPlotBackend}) function finalizePlot(plt::Plot{PyPlotBackend})
ax = getLeftAxis(plt)
addPyPlotLegend(plt, ax)
updateAxisColors(ax, getPyPlotColor(plt.plotargs[:foreground_color]))
PyPlot.draw()
end
function finalizePlot(subplt::Subplot{PyPlotBackend})
fig = subplt.o.fig
for (i,plt) in enumerate(subplt.plts)
ax = getLeftAxis(plt) ax = getLeftAxis(plt)
addPyPlotLegend(plt, ax) addPyPlotLegend(plt, ax)
updateAxisColors(ax, getPyPlotColor(plt.plotargs[:foreground_color])) updateAxisColors(ax, getPyPlotColor(plt.plotargs[:foreground_color]))
end PyPlot.draw()
# fig[:tight_layout]()
PyPlot.draw()
end end
# # allow for writing any supported mime function finalizePlot(subplt::Subplot{PyPlotBackend})
# for mime in keys(PyPlot.aggformats) fig = subplt.o.fig
# @eval function Base.writemime(io::IO, m::MIME{symbol{$mime}}, plt::Plot{PyPlotBackend}) for (i,plt) in enumerate(subplt.plts)
# finalizePlot(plt) ax = getLeftAxis(plt)
# writemime(io, m, getfig(plt.o)) addPyPlotLegend(plt, ax)
# end updateAxisColors(ax, getPyPlotColor(plt.plotargs[:foreground_color]))
# end end
# fig[:tight_layout]()
PyPlot.draw()
end
# function Base.writemime(io::IO, m::@compat(Union{MIME"image/svg+xml", MIME"image/png"}, plt::Plot{PyPlotBackend})
# finalizePlot(plt)
# writemime(io, m, getfig(plt.o))
# end
# -----------------------------------------------------------------
# NOTE: to bring up a GUI window in IJulia, need some extra steps # NOTE: to bring up a GUI window in IJulia, need some extra steps
function Base.display(::PlotsDisplay, plt::AbstractPlot{PyPlotBackend}) function Base.display(::PlotsDisplay, plt::AbstractPlot{PyPlotBackend})
finalizePlot(plt) finalizePlot(plt)
if isa(Base.Multimedia.displays[end], Base.REPL.REPLDisplay) if isa(Base.Multimedia.displays[end], Base.REPL.REPLDisplay)
display(getfig(plt.o)) display(getfig(plt.o))
else else
# # PyPlot.ion() # # PyPlot.ion()
# PyPlot.figure(getfig(plt.o).o[:number]) # PyPlot.figure(getfig(plt.o).o[:number])
# PyPlot.draw_if_interactive() # PyPlot.draw_if_interactive()
# # PyPlot.ioff() # # PyPlot.ioff()
end end
# PyPlot.plt[:show](block=false) # PyPlot.plt[:show](block=false)
getfig(plt.o)[:show]() getfig(plt.o)[:show]()
end end
# function Base.display(::PlotsDisplay, subplt::Subplot{PyPlotBackend})
# finalizePlot(subplt)
# PyPlot.ion()
# PyPlot.figure(getfig(subplt.o).o[:number])
# PyPlot.draw_if_interactive()
# PyPlot.ioff()
# # display(getfig(subplt.o))
# end
# # allow for writing any supported mime
# for mime in (MIME"image/png", MIME"application/pdf", MIME"application/postscript")
# @eval function Base.writemime(io::IO, ::$mime, plt::AbstractPlot{PyPlotBackend})
# finalizePlot(plt)
# writemime(io, $mime(), getfig(plt.o))
# end
# end
const _pyplot_mimeformats = Dict( const _pyplot_mimeformats = Dict(
"application/eps" => "eps", "application/eps" => "eps",
"image/eps" => "eps", "image/eps" => "eps",
@ -901,26 +849,21 @@ const _pyplot_mimeformats = Dict(
"image/png" => "png", "image/png" => "png",
"application/postscript" => "ps", "application/postscript" => "ps",
"image/svg+xml" => "svg" "image/svg+xml" => "svg"
) )
for (mime, fmt) in _pyplot_mimeformats for (mime, fmt) in _pyplot_mimeformats
@eval function Base.writemime(io::IO, ::MIME{symbol($mime)}, plt::AbstractPlot{PyPlotBackend}) @eval function Base.writemime(io::IO, ::MIME{symbol($mime)}, plt::AbstractPlot{PyPlotBackend})
finalizePlot(plt) finalizePlot(plt)
fig = getfig(plt.o) fig = getfig(plt.o)
fig.o["canvas"][:print_figure](io, fig.o["canvas"][:print_figure](
format=$fmt, io,
# bbox_inches = "tight", format=$fmt,
# figsize = map(px2inch, plt.plotargs[:size]), # bbox_inches = "tight",
facecolor = fig.o["get_facecolor"](), # figsize = map(px2inch, plt.plotargs[:size]),
edgecolor = "none", facecolor = fig.o["get_facecolor"](),
dpi = DPI edgecolor = "none",
) dpi = DPI
end )
end
end end
# function Base.writemime(io::IO, m::MIME"image/png", subplt::Subplot{PyPlotBackend})
# finalizePlot(subplt)
# writemime(io, m, getfig(subplt.o))
# end

View File

@ -210,6 +210,10 @@ end
# 1 argument # 1 argument
# -------------------------------------------------------------------- # --------------------------------------------------------------------
function process_inputs(plt::AbstractPlot, d::KW, n::Integer)
d[:x], d[:y], d[:z] = zeros(0), zeros(0), zeros(0)
end
# no special handling... assume x and z are nothing # no special handling... assume x and z are nothing
function process_inputs(plt::AbstractPlot, d::KW, y) function process_inputs(plt::AbstractPlot, d::KW, y)
d[:y] = y d[:y] = y