From ec87489dd4181a45dcba87da598e5906d4aa1c89 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Thu, 5 May 2016 00:13:45 -0400 Subject: [PATCH] working on image type; working on ijulia display_dict --- src/Plots.jl | 13 ++++--------- src/args.jl | 12 ++++++------ src/backends.jl | 2 ++ src/backends/gr.jl | 6 +++--- src/backends/pyplot.jl | 8 +++++--- src/output.jl | 35 ++++++++++++++++++++++++++++------- src/plot.jl | 2 +- src/series_args.jl | 28 ++++++++++++++++++++++++++-- src/utils.jl | 34 ++++++++++++++++++++++++++++++++++ 9 files changed, 109 insertions(+), 31 deletions(-) diff --git a/src/Plots.jl b/src/Plots.jl index 3cabbc8e..ff85c65f 100644 --- a/src/Plots.jl +++ b/src/Plots.jl @@ -276,16 +276,11 @@ yaxis!(plt::Plot, args...; kw...) = plot!(pl const CURRENT_BACKEND = CurrentBackend(:none) + function __init__() - - # override IJulia inline display - if isijulia() - @eval import IJulia - IJulia.display_dict(plt::AbstractPlot) = Dict{ASCIIString, ByteString}("text/html" => sprint(writemime, "text/html", plt)) - end - - setup_dataframes() - setup_atom() + setup_ijulia() + setup_dataframes() + setup_atom() end # --------------------------------------------------------- diff --git a/src/args.jl b/src/args.jl index cd3ba133..4fe276c1 100644 --- a/src/args.jl +++ b/src/args.jl @@ -11,7 +11,7 @@ const _3dTypes = [:path3d, :scatter3d, :surface, :wireframe, :contour3d] const _allTypes = vcat([ :none, :line, :path, :steppre, :steppost, :sticks, :scatter, :heatmap, :hexbin, :hist, :hist2d, :hist3d, :density, :bar, :hline, :vline, :ohlc, - :contour, :contour3d, :pie, :shape, :box, :violin, :quiver + :contour, :pie, :shape, :box, :violin, :quiver, :image ], _3dTypes) @compat const _typeAliases = KW( :n => :none, @@ -41,11 +41,14 @@ const _allTypes = vcat([ :boxplot => :box, :velocity => :quiver, :gradient => :quiver, + :img => :image, + :imshow => :image, + :imagesc => :image, ) like_histogram(linetype::Symbol) = linetype in (:hist, :density) like_line(linetype::Symbol) = linetype in (:line, :path, :steppre, :steppost) -like_surface(linetype::Symbol) = linetype in (:contour, :contour3d, :heatmap, :surface, :wireframe) +like_surface(linetype::Symbol) = linetype in (:contour, :contour3d, :heatmap, :surface, :wireframe, :image) const _allStyles = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] @@ -148,6 +151,7 @@ _seriesDefaults[:quiver] = nothing _seriesDefaults[:normalize] = false # do we want a normalized histogram? _seriesDefaults[:weights] = nothing # optional weights for histograms (1D and 2D) _seriesDefaults[:contours] = false # add contours to 3d surface and wireframe plots +_seriesDefaults[:match_dimensions] = false # do rows match x (true) or y (false) for heatmap/image/spy? see issue 196 const _plotDefaults = KW() @@ -571,10 +575,6 @@ function preprocessArgs!(d::KW) for arg in wraptuple(pop!(d, :line, ())) processLineArg(d, arg) end - # delete!(d, :line) - # if get(d, :linewidth, :auto) == :auto - # d[:linewidth] = (get(d, :linetype, :path) in (:surface,:heatmap) ? 0 : 1) - # end # handle marker args... default to ellipse if shape not set anymarker = false diff --git a/src/backends.jl b/src/backends.jl index 62d78164..70c4ce1b 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -148,6 +148,7 @@ supportedMarkers(::AbstractBackend) = [:none] supportedScales(::AbstractBackend) = [:identity] subplotSupported(::AbstractBackend) = false stringsSupported(::AbstractBackend) = false +nativeImagesSupported(::AbstractBackend) = false supportedAxes() = supportedAxes(backend()) supportedTypes() = supportedTypes(backend()) @@ -156,5 +157,6 @@ supportedMarkers() = supportedMarkers(backend()) supportedScales() = supportedScales(backend()) subplotSupported() = subplotSupported(backend()) stringsSupported() = stringsSupported(backend()) +nativeImagesSupported() = nativeImagesSupported(backend()) # --------------------------------------------------------- diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 947297aa..27a2512e 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -535,7 +535,7 @@ function gr_display(plt::Plot{GRBackend}, clear=true, update=true, GR.setcharheight(charheight) GR.colormap() elseif lt == :contour - x, y, z = p[:x], p[:y], p[:z].surf + x, y, z = p[:x], p[:y], transpose_z(p, p[:z].surf, false) zmin, zmax = minimum(z), maximum(z) if typeof(p[:levels]) <: Array h = p[:levels] @@ -556,7 +556,7 @@ function gr_display(plt::Plot{GRBackend}, clear=true, update=true, GR.setcharheight(charheight) GR.axes(0, ztick, xmax, zmin, 0, 1, 0.005) elseif lt in [:surface, :wireframe] - x, y, z = p[:x], p[:y], p[:z].surf + x, y, z = p[:x], p[:y], transpose_z(p, p[:z].surf, false) zmin, zmax = GR.adjustrange(minimum(z), maximum(z)) GR.setspace(zmin, zmax, 40, 70) xtick = GR.tick(xmin, xmax) / 2 @@ -588,7 +588,7 @@ function gr_display(plt::Plot{GRBackend}, clear=true, update=true, GR.colormap() end elseif lt == :heatmap - x, y, z = p[:x], p[:y], p[:z].surf + x, y, z = p[:x], p[:y], transpose_z(p, p[:z].surf, false) zmin, zmax = GR.adjustrange(minimum(z), maximum(z)) GR.setspace(zmin, zmax, 0, 90) GR.setcolormap(GR.COLORMAP_COOLWARM) diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index 9ebb608e..a039933c 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -531,7 +531,8 @@ function _add_series(pkg::PyPlotBackend, plt::Plot, d::KW) end if lt in (:contour, :contour3d) - z = z.surf' + # z = z.surf' + z = transpose_z(d, z.surf) needs_colorbar = true @@ -568,8 +569,9 @@ function _add_series(pkg::PyPlotBackend, plt::Plot, d::KW) if !ismatrix(x) || !ismatrix(y) x = repmat(x', length(y), 1) y = repmat(y, 1, length(d[:x])) - z = z' end + # z = z' + z = transpose_z(d, z) if lt == :surface if d[:marker_z] != nothing extrakw[:facecolors] = getPyPlotCustomShading(d[:fillcolor], d[:marker_z], d[:fillalpha]) @@ -626,7 +628,7 @@ function _add_series(pkg::PyPlotBackend, plt::Plot, d::KW) end if lt == :heatmap - x, y, z = heatmap_edges(x), heatmap_edges(y), z.surf' + x, y, z = heatmap_edges(x), heatmap_edges(y), transpose_z(d, z.surf) if !(eltype(z) <: Number) z, discrete_colorbar_values = indices_and_unique_values(z) end diff --git a/src/output.jl b/src/output.jl index 4182526a..e96ded60 100644 --- a/src/output.jl +++ b/src/output.jl @@ -99,12 +99,6 @@ end savefig(fn::@compat(AbstractString)) = savefig(current(), fn) -# savepng(args...; kw...) = savepng(current(), args...; kw...) -# savepng(plt::AbstractPlot, fn::@compat(AbstractString); kw...) = (io = open(fn, "w"); writemime(io, MIME("image/png"), plt); close(io)) - - - - # --------------------------------------------------------- gui(plt::AbstractPlot = current()) = display(PlotsDisplay(), plt) @@ -115,9 +109,36 @@ Base.display(::Base.REPL.REPLDisplay, ::MIME"text/plain", plt::AbstractPlot) = g # a backup for html... passes to svg function Base.writemime(io::IO, ::MIME"text/html", plt::AbstractPlot) - writemime(io, MIME("image/svg+xml"), plt) + writemime(io, MIME("image/svg+xml"), plt) end +# --------------------------------------------------------- +# IJulia +# --------------------------------------------------------- + +const _ijulia_output = ASCIIString["text/html"] + +function setup_ijulia() + # override IJulia inline display + if isijulia() + @eval begin + import IJulia + export set_ijulia_output + function set_ijulia_output(mimestr::ASCIIString) + info("Setting IJulia output format to $mimestr") + global _ijulia_output + _ijulia_output[1] = mimestr + end + function IJulia.display_dict(plt::AbstractPlot) + 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)) + set_ijulia_output("text/html") + end +end # --------------------------------------------------------- # Atom PlotPane diff --git a/src/plot.jl b/src/plot.jl index 62bfd14c..0e1b5af1 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -165,7 +165,7 @@ function _add_series(plt::Plot, d::KW, ::Void, args...; # get the list of dictionaries, one per series dumpdict(d, "before process_inputs") process_inputs(plt, d, args...) - dumpdict(d, "after process_inputs") + dumpdict(d, "after process_inputs", true) if idxfilter != nothing # add the group name as the label if there isn't one passed in diff --git a/src/series_args.jl b/src/series_args.jl index db633298..d5cc428a 100644 --- a/src/series_args.jl +++ b/src/series_args.jl @@ -192,8 +192,6 @@ function build_series_args(plt::AbstractPlot, kw::KW) #, idxfilter) append!(ret, apply_series_recipe(copy(d), Val{:quiver})) end - - # now that we've processed a given series... optionally split into # multiple dicts through a recipe (for example, a box plot is split into component # parts... polygons, lines, and scatters) @@ -248,6 +246,32 @@ function process_inputs{T<:Number}(plt::AbstractPlot, d::KW, mat::AMat{T}) end end +# images - grays +function process_inputs{T<:Gray}(plt::AbstractPlot, d::KW, mat::AMat{T}) + d[:linetype] = :image + d[:yflip] = true + n,m = size(mat) + d[:x], d[:y], d[:z] = 1:n, 1:m, mat + # handle images... when not supported natively, do a hack to use heatmap machinery + if !nativeImagesSupported() + d[:linetype] = :heatmap + d[:z] = convert(Matrix{Float64}, mat) + d[:fillcolor] = ColorGradient([:black, :white]) + end +end + +# images - colors +function process_inputs{T<:Colorant}(plt::AbstractPlot, d::KW, mat::AMat{T}) + d[:linetype] = :image + d[:yflip] = true + n,m = size(mat) + d[:x], d[:y], d[:z] = 1:n, 1:m, mat + # handle images... when not supported natively, do a hack to use heatmap machinery + if !nativeImagesSupported() + imageHack(d) + end +end + # plotting arbitrary shapes/polygons function process_inputs(plt::AbstractPlot, d::KW, shape::Shape) diff --git a/src/utils.jl b/src/utils.jl index 83f0edb2..9ff3c5d5 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -114,6 +114,27 @@ function regressionXY(x, y) regx, regy end +function replace_image_with_heatmap{T<:Colorant}(z::Array{T}) + @show T, size(z) + n, m = size(z) + # idx = 0 + colors = ColorGradient(vec(z)) + newz = reshape(linspace(0, 1, n*m), n, m) + newz, colors + # newz = zeros(n, m) + # for i=1:n, j=1:m + # push!(colors, T(z[i,j]...)) + # newz[i,j] = idx / (n*m-1) + # idx += 1 + # end + # newz, ColorGradient(colors) +end + +function imageHack(d::KW) + :heatmap in supportedTypes() || error("Neither :image or :heatmap are supported!") + d[:linetype] = :heatmap + d[:z], d[:fillcolor] = replace_image_with_heatmap(d[:z]) +end # --------------------------------------------------------------- # ------------------------------------------------------------------------------------ @@ -259,6 +280,19 @@ function indices_and_unique_values(z::AbstractArray) newz, vals end +# this is a helper function to determine whether we need to transpose a surface matrix. +# it depends on whether the backend matches rows to x (transpose_on_match == true) or vice versa +# for example: PyPlot sends rows to y, so transpose_on_match should be true +function transpose_z(d::KW, z, transpose_on_match::Bool = true) + if d[:match_dimensions] == transpose_on_match + z' + else + z + end +end + + + # --------------------------------------------------------------- wraptuple(x::@compat(Tuple)) = x