From c58de34e6371a04bc7442048638a0106c7dd6651 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Thu, 22 Sep 2016 17:36:08 -0400 Subject: [PATCH 01/50] layout error msg --- src/layouts.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layouts.jl b/src/layouts.jl index d39a7762..dba708ee 100644 --- a/src/layouts.jl +++ b/src/layouts.jl @@ -437,7 +437,7 @@ end function layout_args(d::KW, n_override::Integer) layout, n = layout_args(get(d, :layout, n_override)) if n != n_override - error("When doing layout, n != n_override. You're probably trying to force existing plots into a layout that doesn't fit them.") + error("When doing layout, n ($n) != n_override ($(n_override)). You're probably trying to force existing plots into a layout that doesn't fit them.") end layout, n end From 755a70bf775c856a311e57a46c13da8b0f1aeaa4 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Thu, 22 Sep 2016 19:36:25 -0400 Subject: [PATCH 02/50] added series_list to Subplot object to improve performance --- src/args.jl | 3 ++- src/backends/gr.jl | 5 +++-- src/pipeline.jl | 5 +++-- src/subplots.jl | 3 ++- src/types.jl | 18 ++++++++++-------- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/args.jl b/src/args.jl index 5dbbc35b..8f0b23ee 100644 --- a/src/args.jl +++ b/src/args.jl @@ -1143,7 +1143,8 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int) end # this is how many series belong to this subplot - plotIndex = count(series -> series.d[:subplot] === sp && series.d[:primary], plt.series_list) + # plotIndex = count(series -> series.d[:subplot] === sp && series.d[:primary], plt.series_list) + plotIndex = count(series -> series[:primary], sp.series_list) if get(d, :primary, true) plotIndex += 1 end diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 8c9f2d2d..e2632080 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -684,9 +684,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) end GR.restorestate() - # TODO: can we remove? gr_set_font(xaxis[:tickfont]) - # GR.setcolormap(1000 + GR.COLORMAP_COOLWARM) + + # this needs to be here to point the colormap to the right indices + GR.setcolormap(1000 + GR.COLORMAP_COOLWARM) for (idx, series) in enumerate(series_list(sp)) st = series[:seriestype] diff --git a/src/pipeline.jl b/src/pipeline.jl index 23b273b4..958594a0 100644 --- a/src/pipeline.jl +++ b/src/pipeline.jl @@ -355,11 +355,12 @@ function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol) end end -function _add_the_series(plt, d) +function _add_the_series(plt, sp, d) warnOnUnsupported_args(plt.backend, d) warnOnUnsupported(plt.backend, d) series = Series(d) push!(plt.series_list, series) + push!(sp.series_list, series) _series_added(plt, series) end @@ -382,7 +383,7 @@ function _process_seriesrecipe(plt::Plot, d::KW) sp = _prepare_subplot(plt, d) _prepare_annotations(sp, d) _expand_subplot_extrema(sp, d, st) - _add_the_series(plt, d) + _add_the_series(plt, sp, d) else # get a sub list of series for this seriestype diff --git a/src/subplots.jl b/src/subplots.jl index cd253a69..3400874c 100644 --- a/src/subplots.jl +++ b/src/subplots.jl @@ -3,6 +3,7 @@ function Subplot{T<:AbstractBackend}(::T; parent = RootLayout()) Subplot{T}( parent, + Series[], (20mm, 5mm, 2mm, 10mm), defaultbox, defaultbox, @@ -33,7 +34,7 @@ get_subplot(series::Series) = series.d[:subplot] get_subplot_index(plt::Plot, idx::Integer) = Int(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) +series_list(sp::Subplot) = sp.series_list # filter(series -> series.d[:subplot] === sp, sp.plt.series_list) function should_add_to_legend(series::Series) series.d[:primary] && series.d[:label] != "" && diff --git a/src/types.jl b/src/types.jl index 8fdb45e5..b9965eec 100644 --- a/src/types.jl +++ b/src/types.jl @@ -21,11 +21,21 @@ wrap{T}(obj::T) = InputWrapper{T}(obj) Base.isempty(wrapper::InputWrapper) = false +# ----------------------------------------------------------- + +type Series + d::KW +end + +attr(series::Series, k::Symbol) = series.d[k] +attr!(series::Series, v, k::Symbol) = (series.d[k] = v) + # ----------------------------------------------------------- # a single subplot type Subplot{T<:AbstractBackend} <: AbstractLayout parent::AbstractLayout + series_list::Vector{Series} # arguments for each series minpad::Tuple # leftpad, toppad, rightpad, bottompad bbox::BoundingBox # the canvas area which is available to this subplot plotarea::BoundingBox # the part where the data goes @@ -56,14 +66,6 @@ typealias SubplotMap Dict{Any, Subplot} # ----------------------------------------------------------- -type Series - d::KW -end - -attr(series::Series, k::Symbol) = series.d[k] -attr!(series::Series, v, k::Symbol) = (series.d[k] = v) - -# ----------------------------------------------------------- type Plot{T<:AbstractBackend} <: AbstractPlot{T} backend::T # the backend type From fe1b7597878645e644816ffacc77fc8d7b4373b3 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Fri, 23 Sep 2016 12:24:56 -0400 Subject: [PATCH 03/50] faster plotIndex count; withenv logic and cairox11/cairopng in gr --- src/args.jl | 8 +++++++- src/backends/gr.jl | 26 ++++++++++++++------------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/args.jl b/src/args.jl index 8f0b23ee..12d5ee15 100644 --- a/src/args.jl +++ b/src/args.jl @@ -1144,7 +1144,13 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int) # this is how many series belong to this subplot # plotIndex = count(series -> series.d[:subplot] === sp && series.d[:primary], plt.series_list) - plotIndex = count(series -> series[:primary], sp.series_list) + plotIndex = 0 + for series in sp.series_list + if series[:primary] + plotIndex += 1 + end + end + # plotIndex = count(series -> series[:primary], sp.series_list) if get(d, :primary, true) plotIndex += 1 end diff --git a/src/backends/gr.jl b/src/backends/gr.jl index e2632080..4c3ea2ad 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -1021,14 +1021,13 @@ const _gr_mimeformats = Dict( for (mime, fmt) in _gr_mimeformats @eval function _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{GRBackend}) GR.emergencyclosegks() - wstype = haskey(ENV, "GKS_WSTYPE") ? ENV["GKS_WSTYPE"] : "0" filepath = tempname() * "." * $fmt - ENV["GKS_WSTYPE"] = $fmt - ENV["GKS_FILEPATH"] = filepath - gr_display(plt) - GR.emergencyclosegks() + withenv("GKS_WSTYPE" => $fmt == "png" ? "cairopng" : $fmt, + "GKS_FILEPATH" => filepath) do + gr_display(plt) + GR.emergencyclosegks() + end write(io, readstring(filepath)) - ENV["GKS_WSTYPE"] = wstype rm(filepath) end end @@ -1037,15 +1036,18 @@ function _display(plt::Plot{GRBackend}) if plt[:display_type] == :inline GR.emergencyclosegks() filepath = tempname() * ".pdf" - ENV["GKS_WSTYPE"] = "pdf" - ENV["GKS_FILEPATH"] = filepath - gr_display(plt) - GR.emergencyclosegks() + withenv("GKS_WSTYPE" => "pdf", + "GKS_FILEPATH" => filepath) do + gr_display(plt) + GR.emergencyclosegks() + end content = string("\033]1337;File=inline=1;preserveAspectRatio=0:", base64encode(open(readbytes, filepath)), "\a") println(content) rm(filepath) else - ENV["GKS_DOUBLE_BUF"] = "true" - gr_display(plt) + withenv("GKS_WSTYPE" => get(ENV, "GKS_WSTYPE", "cairox11"), + "GKS_DOUBLE_BUF" => get(ENV ,"GKS_DOUBLE_BUF", "true")) do + gr_display(plt) + end end end From bed9beafdccccfdf885281e39c38710ae1bfdb62 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Sat, 24 Sep 2016 21:59:58 -0400 Subject: [PATCH 04/50] fix axis widen when lims is set --- src/axes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/axes.jl b/src/axes.jl index 7d46cbcd..b0f3f1ef 100644 --- a/src/axes.jl +++ b/src/axes.jl @@ -342,7 +342,7 @@ end # so lazy out and don't widen function default_should_widen(axis::Axis) should_widen = false - if axis[:scale] == :identity + if axis[:scale] == :identity && !is_2tuple(axis[:lims]) for sp in axis.sps for series in series_list(sp) if series.d[:seriestype] in (:scatter,) || series.d[:markershape] != :none From e23cf3377e86ee8de9a4a26bdd58d424b6dd1656 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Sat, 24 Sep 2016 23:16:35 -0400 Subject: [PATCH 05/50] gr wstype default; gr tighten tick pos --- src/backends/gr.jl | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 4c3ea2ad..9a4b3c7a 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -627,7 +627,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) # use xor ($) to get the right y coords xi, yi = GR.wctondc(cv, (flip $ mirror) ? ymax : ymin) # @show cv dv ymin xi yi flip mirror (flip $ mirror) - gr_text(xi, yi + (mirror ? 1 : -1) * 0.01, string(dv)) + gr_text(xi, yi + (mirror ? 1 : -1) * 2e-3, string(dv)) end end @@ -640,7 +640,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) # use xor ($) to get the right y coords xi, yi = GR.wctondc((flip $ mirror) ? xmax : xmin, cv) # @show cv dv xmin xi yi - gr_text(xi + (mirror ? 1 : -1) * 0.01, yi, string(dv)) + gr_text(xi + (mirror ? 1 : -1) * 2e-3, yi, string(dv)) end end @@ -1017,12 +1017,19 @@ const _gr_mimeformats = Dict( "image/svg+xml" => "svg", ) +const _gr_wstype_default = @static if is_linux() + "cairox11" +elseif is_apple() + "quartz" +else + "windows" +end for (mime, fmt) in _gr_mimeformats @eval function _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{GRBackend}) GR.emergencyclosegks() filepath = tempname() * "." * $fmt - withenv("GKS_WSTYPE" => $fmt == "png" ? "cairopng" : $fmt, + withenv("GKS_WSTYPE" => $fmt, # $fmt == "png" ? "cairopng" : $fmt, "GKS_FILEPATH" => filepath) do gr_display(plt) GR.emergencyclosegks() @@ -1045,7 +1052,7 @@ function _display(plt::Plot{GRBackend}) println(content) rm(filepath) else - withenv("GKS_WSTYPE" => get(ENV, "GKS_WSTYPE", "cairox11"), + withenv("GKS_WSTYPE" => get(ENV, "GKS_WSTYPE", _gr_wstype_default), "GKS_DOUBLE_BUF" => get(ENV ,"GKS_DOUBLE_BUF", "true")) do gr_display(plt) end From 7ce783705a64809f588aabbbbc38e02ba8c53fbc Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Mon, 26 Sep 2016 11:52:24 -0400 Subject: [PATCH 06/50] Atom match PlotPane size and support plotlyjs --- src/output.jl | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/output.jl b/src/output.jl index 40070b0b..b71dc7ed 100644 --- a/src/output.jl +++ b/src/output.jl @@ -268,7 +268,11 @@ function setup_atom() if get(ENV, "PLOTS_USE_ATOM_PLOTPANE", true) in (true, 1, "1", "true", "yes") # this is like "display"... sends an html div with the plot to the PlotPane function Media.render(pane::Atom.PlotPane, plt::Plot) - Media.render(pane, Atom.div(Atom.HTML(stringmime(MIME("text/html"), plt)))) + # temporarily overwrite size to be Atom.plotsize + sz = plt[:size] + plt[:size] = Juno.plotsize() + Media.render(pane, Atom.div(".fill", Atom.HTML(stringmime(MIME("text/html"), plt)))) + plt[:size] = sz end else # @@ -279,14 +283,17 @@ function setup_atom() end end - # Atom.displaysize(::Plot) = (535, 379) - # Atom.displaytitle(plt::Plot) = "Plots.jl (backend: $(backend(plt)))" - - # special handling for plotly/plotlyjs - function Media.render{B<:Union{PlotlyBackend,PlotlyJSBackend}}(pane::Atom.PlotPane, plt::Plot{B}) + # special handling for plotly... use PlotsDisplay + function Media.render(pane::Atom.PlotPane, plt::Plot{PlotlyBackend}) display(Plots.PlotsDisplay(), plt) s = "PlotPane turned off. The plotly and plotlyjs backends cannot render in the PlotPane due to javascript issues." Media.render(pane, Atom.div(Atom.HTML(s))) end + + # special handling for PlotlyJS to pass through to that render method + function Media.render(pane::Atom.PlotPane, plt::Plot{PlotlyJSBackend}) + Plots.prepare_output(plt) + Media.render(pane, plt.o) + end end end From 54923c082ccb0061ef04c43c152dfd52a7a58a91 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Tue, 27 Sep 2016 12:51:20 -0400 Subject: [PATCH 07/50] reset_extrema; setxyz for z matrix --- src/axes.jl | 15 +++++++++++++++ src/utils.jl | 16 +++++++++------- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/axes.jl b/src/axes.jl index b0f3f1ef..4a797561 100644 --- a/src/axes.jl +++ b/src/axes.jl @@ -224,6 +224,21 @@ end # ------------------------------------------------------------------------- + +function reset_extrema!(sp::Subplot) + # axis = sp[Symbol(asym,:axis)] + # axis[:extrema] = Extrema() + for asym in (:x,:y,:z) + sp[Symbol(asym,:axis)][:extrema] = Extrema() + end + for series in sp.series_list + @show series + # expand_extrema!(axis, series[asym]) + expand_extrema!(sp, series.d) + end +end + + function expand_extrema!(ex::Extrema, v::Number) ex.emin = min(v, ex.emin) ex.emax = max(v, ex.emax) diff --git a/src/utils.jl b/src/utils.jl index d5a7757d..379a89cc 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -660,26 +660,28 @@ function setxy!{X,Y}(plt::Plot, xy::Tuple{X,Y}, i::Integer) series = plt.series_list[i] series.d[:x], series.d[:y] = xy sp = series.d[:subplot] - expand_extrema!(sp.attr[:xaxis], xy[1]) - expand_extrema!(sp.attr[:yaxis], xy[2]) + reset_extrema!(sp) _series_updated(plt, series) end function setxyz!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) series = plt.series_list[i] series.d[:x], series.d[:y], series.d[:z] = xyz sp = series.d[:subplot] - expand_extrema!(sp.attr[:xaxis], xyz[1]) - expand_extrema!(sp.attr[:yaxis], xyz[2]) - expand_extrema!(sp.attr[:zaxis], xyz[3]) + reset_extrema!(sp) _series_updated(plt, series) end +function setxyz!{X,Y,Z<:AbstractMatrix}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) + setxyz!(plt, (xyz[1], xyz[2], Surface(xyz[3])), i) +end + + # ------------------------------------------------------- # indexing notation # Base.getindex(plt::Plot, i::Integer) = getxy(plt, i) -Base.setindex!{X,Y}(plt::Plot, xy::Tuple{X,Y}, i::Integer) = setxy!(plt, xy, i) -Base.setindex!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) = setxyz!(plt, xyz, i) +Base.setindex!{X,Y}(plt::Plot, xy::Tuple{X,Y}, i::Integer) = (setxy!(plt, xy, i); plt) +Base.setindex!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) = (setxyz!(plt, xyz, i); plt) # ------------------------------------------------------- From 980a92c625746f6fada9ebdf9c1ba81c236d3f54 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Tue, 27 Sep 2016 13:05:28 -0400 Subject: [PATCH 08/50] remove show; fix plotlyjs _series_updated, closes #505 --- src/axes.jl | 4 ---- src/backends/plotlyjs.jl | 7 ++++++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/axes.jl b/src/axes.jl index 4a797561..142ccedb 100644 --- a/src/axes.jl +++ b/src/axes.jl @@ -226,14 +226,10 @@ end function reset_extrema!(sp::Subplot) - # axis = sp[Symbol(asym,:axis)] - # axis[:extrema] = Extrema() for asym in (:x,:y,:z) sp[Symbol(asym,:axis)][:extrema] = Extrema() end for series in sp.series_list - @show series - # expand_extrema!(axis, series[asym]) expand_extrema!(sp, series.d) end end diff --git a/src/backends/plotlyjs.jl b/src/backends/plotlyjs.jl index cebd6488..e35f7bd5 100644 --- a/src/backends/plotlyjs.jl +++ b/src/backends/plotlyjs.jl @@ -56,10 +56,15 @@ end function _series_updated(plt::Plot{PlotlyJSBackend}, series::Series) xsym, ysym = (ispolar(series) ? (:t,:r) : (:x,:y)) + kw = KW(xsym => (series.d[:x],), ysym => (series.d[:y],)) + z = series[:z] + if z != nothing + kw[:z] = (transpose_z(series, series[:z].surf, false),) + end PlotlyJS.restyle!( plt.o, findfirst(plt.series_list, series), - KW(xsym => (series.d[:x],), ysym => (series.d[:y],)) + kw ) end From 2b1c4685d2f78434e3ecc6eb000aee568b77074d Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Tue, 27 Sep 2016 15:55:28 -0400 Subject: [PATCH 09/50] glvisualize MetaPkg --- src/backends/glvisualize.jl | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/backends/glvisualize.jl b/src/backends/glvisualize.jl index 0ca5b03e..75a28103 100644 --- a/src/backends/glvisualize.jl +++ b/src/backends/glvisualize.jl @@ -77,27 +77,14 @@ end function add_backend_string(b::GLVisualizeBackend) """ - if !Plots.is_installed("GLVisualize") - Pkg.add("GLVisualize") - end - if !Plots.is_installed("Contour") - Pkg.add("Contour") - end - if !Plots.is_installed("GLPlot") - Pkg.add("GLPlot") - end + For those incredibly brave souls who assume full responsibility for what happens next... + There's an easy way to get what you need for the GLVisualize backend to work: - # TODO: remove this section when the tagged versions catch up - for pkg in [ - "GLWindow", "GLAbstraction", - "GLVisualize", "GeometryTypes", "FixedSizeArrays", - "FreeType", "GLPlot" - ] - warn("Running Pkg.checkout(\"\$pkg\"). To revert, run Pkg.free(\"\$pkg\")") - Pkg.checkout(pkg) - end - warn("Running Pkg.checkout(\"Reactive\", \"sd/betterstop\"). To revert, run Pkg.free(\"Reactive\")") - Pkg.checkout("Reactive", "sd/betterstop") + Pkg.clone("https://github.com/tbreloff/MetaPkg.jl") + import MetaPkg + MetaPkg.checkout("MetaGL") + + See the MetaPkg readme for details... """ end From 24a4c31f0d66981e2cf7d58aa4dd21d3fa926a18 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Thu, 29 Sep 2016 16:14:46 -0400 Subject: [PATCH 10/50] widen bar plots; improve ggplot2 theme --- src/recipes.jl | 4 ++++ src/themes.jl | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/recipes.jl b/src/recipes.jl index 73ae7a8d..4c985025 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -405,11 +405,15 @@ end push!(yseg, yi, fi, fi, yi, yi) end + # widen limits out a bit + expand_extrema!(axis, widen(extrema(xseg.pts)...)) + # switch back if !isvertical(d) xseg, yseg = yseg, xseg end + # reset orientation orientation := default(:orientation) diff --git a/src/themes.jl b/src/themes.jl index e84e2063..0de2bbdf 100644 --- a/src/themes.jl +++ b/src/themes.jl @@ -52,12 +52,12 @@ function add_theme(sym::Symbol; end add_theme(:ggplot2, - bglegend = _invisible, + bglegend = :lightgray, bginside = :lightgray, - fg = :white, - fglegend = _invisible, - fgtext = :gray, - fgguide = :black + fg = :black, + fggrid = :white, + fgborder = _invisible, + fgaxis = _invisible ) function set_theme(sym::Symbol) From f4329a9483832bfec53b83e0600668b1f89ef208 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Fri, 30 Sep 2016 10:40:26 -0400 Subject: [PATCH 11/50] support color for plotly bar; closes #513 --- src/backends/plotly.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index d70ee16e..d06864af 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -386,6 +386,7 @@ function plotly_series(plt::Plot, series::Series) d_out[:type] = "bar" d_out[:x], d_out[:y] = x, y d_out[:orientation] = isvertical(series) ? "v" : "h" + d_out[:marker] = KW(:color => rgba_string(series[:fillcolor])) elseif st == :heatmap d_out[:type] = "heatmap" From 5ed913ba5e9e4e8b018a0cb79654e78c9b53d1b7 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Fri, 30 Sep 2016 11:25:29 -0400 Subject: [PATCH 12/50] plotly: plotly_surface_data and wireframes; closes #479 --- src/backends/plotly.jl | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index d06864af..de30acd3 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -33,7 +33,7 @@ const _plotly_attr = merge_with_base_supported([ const _plotly_seriestype = [ :path, :scatter, :bar, :pie, :heatmap, - :contour, :surface, :path3d, :scatter3d, :shape, :scattergl, + :contour, :surface, :wireframe, :path3d, :scatter3d, :shape, :scattergl, ] const _plotly_style = [:auto, :solid, :dash, :dot, :dashdot] const _plotly_marker = [ @@ -343,6 +343,10 @@ plotly_data(v) = collect(v) plotly_data(surf::Surface) = surf.surf plotly_data{R<:Rational}(v::AbstractArray{R}) = float(v) +plotly_surface_data(series::Series, a::AbstractVector) = a +plotly_surface_data(series::Series, a::AbstractMatrix) = transpose_z(series, a, false) +plotly_surface_data(series::Series, a::Surface) = plotly_surface_data(series, a.surf) + # get a dictionary representing the series params (d is the Plots-dict, d_out is the Plotly-dict) function plotly_series(plt::Plot, series::Series) st = series[:seriestype] @@ -366,6 +370,13 @@ function plotly_series(plt::Plot, series::Series) hasmarker = isscatter || series[:markershape] != :none hasline = st in (:path, :path3d) + # for surface types, set the data + if st in (:heatmap, :contour, :surface, :wireframe) + for letter in [:x,:y,:z] + d_out[letter] = plotly_surface_data(series, series[letter]) + end + end + # set the "type" if st in (:path, :scatter, :scattergl) d_out[:type] = st==:scattergl ? "scattergl" : "scatter" @@ -390,12 +401,12 @@ function plotly_series(plt::Plot, series::Series) elseif st == :heatmap d_out[:type] = "heatmap" - d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false) + # d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false) d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha]) elseif st == :contour d_out[:type] = "contour" - d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false) + # d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false) # d_out[:showscale] = series[:colorbar] != :none d_out[:ncontours] = series[:levels] d_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines") @@ -403,8 +414,18 @@ function plotly_series(plt::Plot, series::Series) elseif st in (:surface, :wireframe) d_out[:type] = "surface" - d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false) - d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha]) + # d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false) + if st == :wireframe + d_out[:hidesurface] = true + wirelines = KW( + :show => true, + :color => rgba_string(series[:linecolor]), + :highlightwidth => series[:linewidth], + ) + d_out[:contours] = KW(:x => wirelines, :y => wirelines, :z => wirelines) + else + d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha]) + end elseif st == :pie d_out[:type] = "pie" From 4416fc919ecf223df8f12fd8b6519e56401156a0 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Fri, 30 Sep 2016 12:46:38 -0400 Subject: [PATCH 13/50] improve tick_padding and fix rotation for plotly/gr --- src/axes.jl | 8 ++++---- src/backends.jl | 17 +++++++++++++---- src/backends/gr.jl | 15 +++++++++++---- src/backends/plotly.jl | 5 +++-- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/axes.jl b/src/axes.jl index 142ccedb..0cd8ac4c 100644 --- a/src/axes.jl +++ b/src/axes.jl @@ -473,11 +473,11 @@ function axis_drawing_info(sp::Subplot) t2 = invf(f(ymax) - 0.015*(f(ymax)-f(ymin))) push!(spine_segs, (xmin,ymin), (xmax,ymin)) # bottom spine - push!(spine_segs, (xmin,ymax), (xmax,ymax)) # top spine + # push!(spine_segs, (xmin,ymax), (xmax,ymax)) # top spine for xtick in xticks[1] push!(spine_segs, (xtick, ymin), (xtick, t1)) # bottom tick push!(grid_segs, (xtick, t1), (xtick, t2)) # vertical grid - push!(spine_segs, (xtick, ymax), (xtick, t2)) # top tick + # push!(spine_segs, (xtick, ymax), (xtick, t2)) # top tick end end @@ -488,11 +488,11 @@ function axis_drawing_info(sp::Subplot) t2 = invf(f(xmax) - 0.015*(f(xmax)-f(xmin))) push!(spine_segs, (xmin,ymin), (xmin,ymax)) # left spine - push!(spine_segs, (xmax,ymin), (xmax,ymax)) # right spine + # push!(spine_segs, (xmax,ymin), (xmax,ymax)) # right spine for ytick in yticks[1] push!(spine_segs, (xmin, ytick), (t1, ytick)) # left tick push!(grid_segs, (t1, ytick), (t2, ytick)) # horizontal grid - push!(spine_segs, (xmax, ytick), (t2, ytick)) # right tick + # push!(spine_segs, (xmax, ytick), (t2, ytick)) # right tick end end diff --git a/src/backends.jl b/src/backends.jl index 699f1cc1..c2376a80 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -51,15 +51,24 @@ _before_layout_calcs(plt::Plot) = nothing title_padding(sp::Subplot) = sp[:title] == "" ? 0mm : sp[:titlefont].pointsize * pt guide_padding(axis::Axis) = axis[:guide] == "" ? 0mm : axis[:guidefont].pointsize * pt -# TODO: this should account for both tick font and the size/length/rotation of tick labels +# account for the size/length/rotation of tick labels function tick_padding(axis::Axis) + vals, labs = get_ticks(axis) ptsz = axis[:tickfont].pointsize * pt if axis[:ticks] in (nothing,false) 0mm - elseif axis[:letter] == :x - 2mm + ptsz else - 8mm + # we need to compute the size of the ticks generically + # this means computing the bounding box and then getting the width/height + longest_label = maximum(length(lab) for lab in labs) + labelwidth = 0.8longest_label * ptsz + + # generalize by "rotating" y labels + rot = axis[:rotation] + (axis[:letter] == :y ? 90 : 0) + + # now compute the generalized "height" after rotation as the "opposite+adjacent" of 2 triangles + hgt = abs(sind(rot)) * labelwidth + abs(cosd(rot)) * ptsz + 1mm + hgt end end diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 9a4b3c7a..090aa499 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -337,10 +337,11 @@ end const _gr_point_mult = zeros(1) # set the font attributes... assumes _gr_point_mult has been populated already -function gr_set_font(f::Font; halign = f.halign, valign = f.valign, color = f.color) +function gr_set_font(f::Font; halign = f.halign, valign = f.valign, + color = f.color, rotation = f.rotation) family = lowercase(f.family) GR.setcharheight(_gr_point_mult[1] * f.pointsize) - GR.setcharup(sin(f.rotation), cos(f.rotation)) + GR.setcharup(sind(-rotation), cosd(-rotation)) if haskey(gr_font_family, family) GR.settextfontprec(100 + gr_font_family[family], GR.TEXT_PRECISION_STRING) end @@ -622,7 +623,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) # x labels flip = sp[:yaxis][:flip] mirror = sp[:xaxis][:mirror] - gr_set_font(sp[:xaxis][:tickfont], valign = (mirror ? :bottom : :top), color = sp[:xaxis][:foreground_color_axis]) + gr_set_font(sp[:xaxis][:tickfont], + valign = (mirror ? :bottom : :top), + color = sp[:xaxis][:foreground_color_axis], + rotation = sp[:xaxis][:rotation]) for (cv, dv) in zip(xticks...) # use xor ($) to get the right y coords xi, yi = GR.wctondc(cv, (flip $ mirror) ? ymax : ymin) @@ -635,7 +639,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) # y labels flip = sp[:xaxis][:flip] mirror = sp[:yaxis][:mirror] - gr_set_font(sp[:yaxis][:tickfont], halign = (mirror ? :left : :right), color = sp[:yaxis][:foreground_color_axis]) + gr_set_font(sp[:yaxis][:tickfont], + halign = (mirror ? :left : :right), + color = sp[:yaxis][:foreground_color_axis], + rotation = sp[:yaxis][:rotation]) for (cv, dv) in zip(yticks...) # use xor ($) to get the right y coords xi, yi = GR.wctondc((flip $ mirror) ? xmax : xmin, cv) diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index de30acd3..dca86b14 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -115,7 +115,7 @@ function plotly_annotation_dict(x, y, ptxt::PlotText; xref="paper", yref="paper" :font => plotly_font(ptxt.font), :xanchor => ptxt.font.halign == :hcenter ? :center : ptxt.font.halign, :yanchor => ptxt.font.valign == :vcenter ? :middle : ptxt.font.valign, - :rotation => ptxt.font.rotation, + :rotation => -ptxt.font.rotation, )) end @@ -166,6 +166,7 @@ function plotly_axis(axis::Axis, sp::Subplot) :title => axis[:guide], :showgrid => sp[:grid], :zeroline => false, + :ticks => "inside", ) if letter in (:x,:y) @@ -175,7 +176,7 @@ function plotly_axis(axis::Axis, sp::Subplot) rot = axis[:rotation] if rot != 0 - ax[:tickangle] = rot + ax[:tickangle] = -rot end if !(axis[:ticks] in (nothing, :none)) From f41a09b68e44797f9c054c8d35ddb46540231ad3 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Fri, 30 Sep 2016 13:44:37 -0400 Subject: [PATCH 14/50] plotly: support aspect_ratio --- src/backends/plotly.jl | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index dca86b14..a60cf771 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -26,7 +26,8 @@ const _plotly_attr = merge_with_base_supported([ # :overwrite_figure, :polar, :normalize, :weights, - # :contours, :aspect_ratio, + # :contours, + :aspect_ratio, :hover, :inset_subplots, ]) @@ -150,11 +151,38 @@ function plotly_scale(scale::Symbol) end end +function shrink_by(lo, sz, ratio) + amt = 0.5 * (1.0 - ratio) * sz + lo + amt, sz - 2amt +end + +function plotly_apply_aspect_ratio(sp::Subplot, plotarea, pcts) + aspect_ratio = sp[:aspect_ratio] + if aspect_ratio != :none + if aspect_ratio == :equal + aspect_ratio = 1.0 + end + parea_ratio = width(plotarea) / height(plotarea) + if aspect_ratio > parea_ratio + # need to shrink y + ratio = parea_ratio / aspect_ratio + pcts[2], pcts[4] = shrink_by(pcts[2], pcts[4], ratio) + elseif aspect_ratio < parea_ratio + # need to shrink x + ratio = aspect_ratio / parea_ratio + pcts[1], pcts[3] = shrink_by(pcts[1], pcts[3], ratio) + end + pcts + end + pcts +end + # this method gets the start/end in percentage of the canvas for this axis direction function plotly_domain(sp::Subplot, letter) figw, figh = sp.plt[:size] pcts = bbox_to_pcts(sp.plotarea, figw*px, figh*px) + pcts = plotly_apply_aspect_ratio(sp, sp.plotarea, pcts) i1,i2 = (letter == :x ? (1,3) : (2,4)) [pcts[i1], pcts[i1]+pcts[i2]] end @@ -230,6 +258,7 @@ function plotly_layout(plt::Plot) for sp in plt.subplots spidx = plotly_subplot_index(sp) + # add an annotation for the title... positioned horizontally relative to plotarea, # but vertically just below the top of the subplot bounding box if sp[:title] != "" @@ -249,8 +278,6 @@ function plotly_layout(plt::Plot) d_out[:plot_bgcolor] = rgba_string(sp[:background_color_inside]) - # TODO: x/y axis tick values/labels - # if any(is3d, seriesargs) if is3d(sp) d_out[:scene] = KW( From c39f5e1483882415e140a0d1c0b00590ad6b5e0b Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Fri, 30 Sep 2016 13:48:27 -0400 Subject: [PATCH 15/50] plotly: always set tickangle --- src/backends/plotly.jl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index a60cf771..956cddb9 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -202,10 +202,7 @@ function plotly_axis(axis::Axis, sp::Subplot) ax[:anchor] = "$(letter==:x ? :y : :x)$(plotly_subplot_index(sp))" end - rot = axis[:rotation] - if rot != 0 - ax[:tickangle] = -rot - end + ax[:tickangle] = -axis[:rotation] if !(axis[:ticks] in (nothing, :none)) ax[:titlefont] = plotly_font(axis[:guidefont], axis[:foreground_color_guide]) From 9e8869acf1ffabef60c33191ccd38690cf5f530b Mon Sep 17 00:00:00 2001 From: Fedor Bezrukov Date: Mon, 3 Oct 2016 00:37:50 +0300 Subject: [PATCH 16/50] Fix for dpi in pyplot backend --- src/backends/pyplot.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index 7bdb5992..0ea2390d 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -356,7 +356,7 @@ function py_bbox_title(ax) end function py_dpi_scale(plt::Plot{PyPlotBackend}, ptsz) - ptsz * DPI / plt[:dpi] + ptsz * plt[:dpi] / DPI end # --------------------------------------------------------------------------- From bc276acb96177a274dc636d0a8c385b8a85b7de4 Mon Sep 17 00:00:00 2001 From: Denny Biasiolli Date: Thu, 6 Oct 2016 14:29:24 +0200 Subject: [PATCH 17/50] Fix typo in args.jl Fix #521 --- src/args.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/args.jl b/src/args.jl index 12d5ee15..606c5a37 100644 --- a/src/args.jl +++ b/src/args.jl @@ -352,7 +352,7 @@ end add_aliases(:seriescolor, :c, :color, :colour) add_aliases(:linecolor, :lc, :lcolor, :lcolour, :linecolour) add_aliases(:markercolor, :mc, :mcolor, :mcolour, :markercolour) -add_aliases(:markerstokecolor, :msc, :mscolor, :mscolour, :markerstokecolour) +add_aliases(:markerstrokecolor, :msc, :mscolor, :mscolour, :markerstrokecolour) add_aliases(:fillcolor, :fc, :fcolor, :fcolour, :fillcolour) add_aliases(:background_color, :bg, :bgcolor, :bg_color, :background, From 068282af55867ef012cec6ffe96add610e5c549b Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Thu, 6 Oct 2016 12:45:21 -0400 Subject: [PATCH 18/50] aliases for subplot colors; default(d,k); fg_color/fg_color_sp; fix tick_padding for nothing/false --- src/args.jl | 48 +++++++++++++++++++++++++++++++++++++++++------- src/backends.jl | 8 +++++--- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/args.jl b/src/args.jl index 606c5a37..133974b3 100644 --- a/src/args.jl +++ b/src/args.jl @@ -359,6 +359,8 @@ add_aliases(:background_color, :bg, :bgcolor, :bg_color, :background, :background_colour, :bgcolour, :bg_colour) add_aliases(:background_color_legend, :bg_legend, :bglegend, :bgcolor_legend, :bg_color_legend, :background_legend, :background_colour_legend, :bgcolour_legend, :bg_colour_legend) +add_aliases(:background_color_subplot, :bg_subplot, :bgsubplot, :bgcolor_subplot, :bg_color_subplot, :background_subplot, + :background_colour_subplot, :bgcolour_subplot, :bg_colour_subplot) add_aliases(:background_color_inside, :bg_inside, :bginside, :bgcolor_inside, :bg_color_inside, :background_inside, :background_colour_inside, :bgcolour_inside, :bg_colour_inside) add_aliases(:background_color_outside, :bg_outside, :bgoutside, :bgcolor_outside, :bg_color_outside, :background_outside, @@ -367,6 +369,8 @@ add_aliases(:foreground_color, :fg, :fgcolor, :fg_color, :foreground, :foreground_colour, :fgcolour, :fg_colour) add_aliases(:foreground_color_legend, :fg_legend, :fglegend, :fgcolor_legend, :fg_color_legend, :foreground_legend, :foreground_colour_legend, :fgcolour_legend, :fg_colour_legend) +add_aliases(:foreground_color_subplot, :fg_subplot, :fgsubplot, :fgcolor_subplot, :fg_color_subplot, :foreground_subplot, + :foreground_colour_subplot, :fgcolour_subplot, :fg_colour_subplot) add_aliases(:foreground_color_grid, :fg_grid, :fggrid, :fgcolor_grid, :fg_color_grid, :foreground_grid, :foreground_colour_grid, :fgcolour_grid, :fg_colour_grid, :gridcolor) add_aliases(:foreground_color_title, :fg_title, :fgtitle, :fgcolor_title, :fg_color_title, :foreground_title, @@ -456,6 +460,7 @@ end `default(key)` returns the current default value for that key `default(key, value)` sets the current default value for that key `default(; kw...)` will set the current default value for each key/value pair +`default(d, key)` returns the key from d if it exists, otherwise `default(key)` """ function default(k::Symbol) @@ -492,6 +497,11 @@ function default(; kw...) end end +function default(d::KW, k::Symbol) + get(d, k, default(k)) +end + + # ----------------------------------------------------------------------------- @@ -974,6 +984,27 @@ Base.get(series::Series, k::Symbol, v) = get(series.d, k, v) # ----------------------------------------------------------------------------- +function fg_color(d::KW) + fg = default(d, :foreground_color) + if fg == :auto + bg = plot_color(default(d, :background_color)) + fg = isdark(bg) ? colorant"white" : colorant"black" + else + plot_color(fg) + end +end + +function fg_color_sp(d::KW) + fgsp = default(d, :foreground_color_subplot) + if fg == :match + fg_color(d) + else + plot_color(fgsp) + end +end + + + # update attr from an input dictionary function _update_plot_args(plt::Plot, d_in::KW) for (k,v) in _plot_defaults @@ -981,13 +1012,16 @@ function _update_plot_args(plt::Plot, d_in::KW) end # handle colors - bg = plot_color(plt.attr[:background_color]) - fg = plt.attr[:foreground_color] - if fg == :auto - fg = isdark(bg) ? colorant"white" : colorant"black" - end - plt.attr[:background_color] = bg - plt.attr[:foreground_color] = plot_color(fg) + d = plt.attr + plt[:background_color] = plot_color(d[:background_color]) + plt[:foreground_color] = fg_color(d) + # bg = plot_color(plt.attr[:background_color]) + # fg = plt.attr[:foreground_color] + # if fg == :auto + # fg = isdark(bg) ? colorant"white" : colorant"black" + # end + # plt.attr[:background_color] = bg + # plt.attr[:foreground_color] = plot_color(fg) color_or_nothing!(plt.attr, :background_color_outside) end diff --git a/src/backends.jl b/src/backends.jl index c2376a80..7cd4e898 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -53,11 +53,13 @@ guide_padding(axis::Axis) = axis[:guide] == "" ? 0mm : axis[:guidefont].pointsiz # account for the size/length/rotation of tick labels function tick_padding(axis::Axis) - vals, labs = get_ticks(axis) - ptsz = axis[:tickfont].pointsize * pt - if axis[:ticks] in (nothing,false) + ticks = get_ticks(axis) + if ticks == nothing 0mm else + vals, labs = ticks + ptsz = axis[:tickfont].pointsize * pt + # we need to compute the size of the ticks generically # this means computing the bounding box and then getting the width/height longest_label = maximum(length(lab) for lab in labs) From a4c25321d879197b1dfdf456126ca145653c06db Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Fri, 7 Oct 2016 11:33:02 -0400 Subject: [PATCH 19/50] histogram2d puts NaN for 0 count; fix pyplot NaNs in heatmap; change default markersize to 4 --- src/args.jl | 2 +- src/backends/pyplot.jl | 21 ++++++++++++++------- src/recipes.jl | 5 +++++ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/args.jl b/src/args.jl index 133974b3..6a72a733 100644 --- a/src/args.jl +++ b/src/args.jl @@ -165,7 +165,7 @@ const _series_defaults = KW( :markershape => :none, :markercolor => :match, :markeralpha => nothing, - :markersize => 6, + :markersize => 4, :markerstrokestyle => :solid, :markerstrokewidth => 1, :markerstrokecolor => :match, diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index 0ea2390d..eb0ce0ad 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -64,7 +64,7 @@ function _initialize_backend(::PyPlotBackend) # problem: https://github.com/tbreloff/Plots.jl/issues/308 # solution: hack from @stevengj: https://github.com/stevengj/PyPlot.jl/pull/223#issuecomment-229747768 otherdisplays = splice!(Base.Multimedia.displays, 2:length(Base.Multimedia.displays)) - import PyPlot + import PyPlot, PyCall import LaTeXStrings: latexstring append!(Base.Multimedia.displays, otherdisplays) @@ -117,7 +117,9 @@ py_color(grad::ColorGradient) = py_color(grad.colors) function py_colormap(grad::ColorGradient) pyvals = [(z, py_color(grad[z])) for z in grad.values] - pycolors.LinearSegmentedColormap[:from_list]("tmp", pyvals) + cm = pycolors.LinearSegmentedColormap[:from_list]("tmp", pyvals) + cm[:set_bad](color=(0,0,0,0.0), alpha=0.0) + cm end py_colormap(c) = py_colormap(cgrad()) @@ -246,6 +248,12 @@ function labelfunc(scale::Symbol, backend::PyPlotBackend) end end +function py_mask_nans(z) + # PyPlot.pywrap(pynp.ma[:masked_invalid](PyPlot.pywrap(z))) + PyCall.pycall(pynp.ma[:masked_invalid], Any, z) + # pynp.ma[:masked_where](pynp.isnan(z),z) +end + # --------------------------------------------------------------------------- function fix_xy_lengths!(plt::Plot{PyPlotBackend}, series::Series) @@ -730,12 +738,11 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) end clims = sp[:clims] - if is_2tuple(clims) - isfinite(clims[1]) && (extrakw[:vmin] = clims[1]) - isfinite(clims[2]) && (extrakw[:vmax] = clims[2]) - end + zmin, zmax = extrema(z) + extrakw[:vmin] = (is_2tuple(clims) && isfinite(clims[1])) ? clims[1] : zmin + extrakw[:vmax] = (is_2tuple(clims) && isfinite(clims[2])) ? clims[2] : zmax - handle = ax[:pcolormesh](x, y, z; + handle = ax[:pcolormesh](x, y, py_mask_nans(z); label = series[:label], zorder = series[:series_plotindex], cmap = py_fillcolormap(series), diff --git a/src/recipes.jl b/src/recipes.jl index 4c985025..0bcc8e7e 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -511,6 +511,11 @@ centers(v::AVec) = 0.5 * (v[1:end-1] + v[2:end]) xedges, yedges, counts = my_hist_2d(x, y, d[:bins], normed = d[:normalize], weights = d[:weights]) + for (i,c) in enumerate(counts) + if c == 0 + counts[i] = NaN + end + end x := centers(xedges) y := centers(yedges) z := Surface(counts) From 04a435768477d6f6fd7063937299dc94d83ded0d Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Fri, 7 Oct 2016 12:14:06 -0400 Subject: [PATCH 20/50] fix plotly aspect_ratio and reword arg desc; closes #523 --- src/arg_desc.jl | 2 +- src/backends/plotly.jl | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/arg_desc.jl b/src/arg_desc.jl index 06f525bb..f6365571 100644 --- a/src/arg_desc.jl +++ b/src/arg_desc.jl @@ -85,7 +85,7 @@ const _arg_desc = KW( :grid => "Bool. Show the grid lines?", :annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String or PlotText (created with `text(args...)`) Add one-off text annotations at the x,y coordinates.", :projection => "Symbol or String. '3d' or 'polar'", -:aspect_ratio => "Symbol (:equal) or Number (width to height ratio of plot area).", +:aspect_ratio => "Symbol (:equal) or Number. Plot area is resized so that 1 y-unit is the same size as `apect_ratio` x-units.", :margin => "Measure (multiply by `mm`, `px`, etc). Base for individual margins... not directly used. Specifies the extra padding around subplots.", :left_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the left of the subplot.", :top_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the top of the subplot.", diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index 956cddb9..be88f4a9 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -162,14 +162,17 @@ function plotly_apply_aspect_ratio(sp::Subplot, plotarea, pcts) if aspect_ratio == :equal aspect_ratio = 1.0 end + xmin,xmax = axis_limits(sp[:xaxis]) + ymin,ymax = axis_limits(sp[:yaxis]) + want_ratio = ((xmax-xmin) / (ymax-ymin)) / aspect_ratio parea_ratio = width(plotarea) / height(plotarea) - if aspect_ratio > parea_ratio + if want_ratio > parea_ratio # need to shrink y - ratio = parea_ratio / aspect_ratio + ratio = parea_ratio / want_ratio pcts[2], pcts[4] = shrink_by(pcts[2], pcts[4], ratio) - elseif aspect_ratio < parea_ratio + elseif want_ratio < parea_ratio # need to shrink x - ratio = aspect_ratio / parea_ratio + ratio = want_ratio / parea_ratio pcts[1], pcts[3] = shrink_by(pcts[1], pcts[3], ratio) end pcts From f615a5d05ed3667063737851c1483c4486ec90d8 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Fri, 7 Oct 2016 12:53:18 -0400 Subject: [PATCH 21/50] experimenting with gr heatmap --- src/backends/gr.jl | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 090aa499..9a0af692 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -349,6 +349,14 @@ function gr_set_font(f::Font; halign = f.halign, valign = f.valign, GR.settextalign(gr_halign[halign], gr_valign[valign]) end +function gr_nans_to_infs!(z) + for (i,zi) in enumerate(z) + if zi == NaN + z[i] = Inf + end + end +end + # -------------------------------------------------------------------------------------- # viewport plot area @@ -817,7 +825,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) end GR.setspace(zmin, zmax, 0, 90) # GR.surface(x, y, z, GR.OPTION_COLORED_MESH) - GR.surface(x, y, z, GR.OPTION_HEATMAP) + # GR.surface(x, y, z, GR.OPTION_HEATMAP) + # gr_nans_to_infs!(z) + GR.surface(x, y, z, GR.OPTION_CELL_ARRAY) cmap && gr_colorbar(sp) elseif st in (:path3d, :scatter3d) From 14fd3c94b579fff531bd634c577001ccb0540d85 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Fri, 7 Oct 2016 13:49:00 -0400 Subject: [PATCH 22/50] fix plotly horizontal bars --- src/backends/plotly.jl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index be88f4a9..627adeb7 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -30,6 +30,7 @@ const _plotly_attr = merge_with_base_supported([ :aspect_ratio, :hover, :inset_subplots, + :bar_width, ]) const _plotly_seriestype = [ @@ -423,8 +424,11 @@ function plotly_series(plt::Plot, series::Series) elseif st == :bar d_out[:type] = "bar" - d_out[:x], d_out[:y] = x, y - d_out[:orientation] = isvertical(series) ? "v" : "h" + d_out[:x], d_out[:y], d_out[:orientation] = if isvertical(series) + x, y, "v" + else + y, x, "h" + end d_out[:marker] = KW(:color => rgba_string(series[:fillcolor])) elseif st == :heatmap From 2877cb71604ac0eec2e9815e12218e2dc639b2a6 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Fri, 7 Oct 2016 14:54:26 -0400 Subject: [PATCH 23/50] gr: replaced withenv calls with _gr_wstype and gr_set_output --- src/backends/gr.jl | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 9a0af692..8aafe9f9 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -1035,22 +1035,28 @@ const _gr_mimeformats = Dict( ) const _gr_wstype_default = @static if is_linux() - "cairox11" + "x11" + # "cairox11" elseif is_apple() "quartz" else "windows" end +const _gr_wstype = Ref(get(ENV, "GKS_WSTYPE", _gr_wstype_default)) +gr_set_output(wstype::String) = (_gr_wstype[] = wstype) + for (mime, fmt) in _gr_mimeformats @eval function _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{GRBackend}) GR.emergencyclosegks() filepath = tempname() * "." * $fmt - withenv("GKS_WSTYPE" => $fmt, # $fmt == "png" ? "cairopng" : $fmt, - "GKS_FILEPATH" => filepath) do + ENV["GKS_WSTYPE"] = $fmt + ENV["GKS_FILEPATH"] = filepath + # withenv("GKS_WSTYPE" => $fmt, # $fmt == "png" ? "cairopng" : $fmt, + # "GKS_FILEPATH" => filepath) do gr_display(plt) GR.emergencyclosegks() - end + # end write(io, readstring(filepath)) rm(filepath) end @@ -1060,18 +1066,22 @@ function _display(plt::Plot{GRBackend}) if plt[:display_type] == :inline GR.emergencyclosegks() filepath = tempname() * ".pdf" - withenv("GKS_WSTYPE" => "pdf", - "GKS_FILEPATH" => filepath) do + ENV["GKS_WSTYPE"] = "pdf" + ENV["GKS_FILEPATH"] = filepath + # withenv("GKS_WSTYPE" => "pdf", + # "GKS_FILEPATH" => filepath) do gr_display(plt) GR.emergencyclosegks() - end + # end content = string("\033]1337;File=inline=1;preserveAspectRatio=0:", base64encode(open(readbytes, filepath)), "\a") println(content) rm(filepath) else - withenv("GKS_WSTYPE" => get(ENV, "GKS_WSTYPE", _gr_wstype_default), - "GKS_DOUBLE_BUF" => get(ENV ,"GKS_DOUBLE_BUF", "true")) do + ENV["GKS_DOUBLE_BUF"] = true + ENV["GKS_WSTYPE"] = _gr_wstype[] + # withenv("GKS_WSTYPE" => get(ENV, "GKS_WSTYPE", _gr_wstype_default), + # "GKS_DOUBLE_BUF" => get(ENV ,"GKS_DOUBLE_BUF", "true")) do gr_display(plt) - end + # end end end From d290c6702a052176f235d52c6a2847f4036f41d8 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Sat, 8 Oct 2016 22:00:22 -0400 Subject: [PATCH 24/50] handle series_attr merge and add_defaults when combining subplots; closes #526 --- src/plot.jl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/plot.jl b/src/plot.jl index 87f06ea1..6d05ba66 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -89,8 +89,16 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...) plt.o = _create_backend_figure(plt) plt.init = true + series_attr = KW() + for (k,v) in d + if haskey(_series_defaults, k) + series_attr[k] = pop!(d,k) + end + end + # create the layout and initialize the subplots plt.layout, plt.subplots, plt.spmap = build_layout(layout, num_sp, copy(plts)) + cmdidx = 1 for (idx, sp) in enumerate(plt.subplots) _initialize_subplot(plt, sp) serieslist = series_list(sp) @@ -100,8 +108,11 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...) sp.plt = plt sp.attr[:subplot_index] = idx for series in serieslist + merge!(series.d, series_attr) + _add_defaults!(series.d, plt, sp, cmdidx) push!(plt.series_list, series) _series_added(plt, series) + cmdidx += 1 end end From 96821f63036ec53f7a78b87eb9296ff9d2fd0ce2 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Sat, 8 Oct 2016 22:39:49 -0400 Subject: [PATCH 25/50] remove spy; support spy seriestype in unicodeplots; recipes cleanup --- src/Plots.jl | 2 +- src/backends/unicodeplots.jl | 18 ++- src/recipes.jl | 235 ++--------------------------------- 3 files changed, 26 insertions(+), 229 deletions(-) diff --git a/src/Plots.jl b/src/Plots.jl index ff0c7bc9..9e2ca468 100644 --- a/src/Plots.jl +++ b/src/Plots.jl @@ -97,7 +97,7 @@ export @animate, @gif, - spy, + # spy, test_examples, iter_segments, diff --git a/src/backends/unicodeplots.jl b/src/backends/unicodeplots.jl index 710e3a4d..9e697f1b 100644 --- a/src/backends/unicodeplots.jl +++ b/src/backends/unicodeplots.jl @@ -16,7 +16,8 @@ const _unicodeplots_seriestype = [ :path, :scatter, # :bar, :shape, - :histogram2d + :histogram2d, + :spy ] const _unicodeplots_style = [:auto, :solid] const _unicodeplots_marker = [:none, :auto, :circle] @@ -67,6 +68,21 @@ function rebuildUnicodePlot!(plt::Plot, width, height) # create a plot window with xlim/ylim set, but the X/Y vectors are outside the bounds canvas_type = isijulia() ? UnicodePlots.AsciiCanvas : UnicodePlots.BrailleCanvas + # special handling for spy + if length(sp.series_list) == 1 + series = sp.series_list[1] + if series[:seriestype] == :spy + push!(plt.o, UnicodePlots.spy( + series[:z].surf, + width = width, + height = height, + title = sp[:title], + canvas = canvas_type + )) + continue + end + end + # # make it a bar canvas if plotting bar # if any(series -> series[:seriestype] == :bar, series_list(sp)) # canvas_type = UnicodePlots.BarplotGraphics diff --git a/src/recipes.jl b/src/recipes.jl index 0bcc8e7e..ffca23fc 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -93,57 +93,11 @@ end # ---------------------------------------------------------------------------------- - num_series(x::AMat) = size(x,2) num_series(x) = 1 - RecipesBase.apply_recipe{T}(d::KW, ::Type{T}, plt::Plot) = throw(MethodError("Unmatched plot recipe: $T")) - -# # TODO: remove when StatPlots is ready -# if is_installed("DataFrames") -# @eval begin -# import DataFrames - -# # if it's one symbol, set the guide and return the column -# function handle_dfs(df::DataFrames.AbstractDataFrame, d::KW, letter, sym::Symbol) -# get!(d, Symbol(letter * "guide"), string(sym)) -# collect(df[sym]) -# end - -# # if it's an array of symbols, set the labels and return a Vector{Any} of columns -# function handle_dfs(df::DataFrames.AbstractDataFrame, d::KW, letter, syms::AbstractArray{Symbol}) -# get!(d, :label, reshape(syms, 1, length(syms))) -# Any[collect(df[s]) for s in syms] -# end - -# # for anything else, no-op -# function handle_dfs(df::DataFrames.AbstractDataFrame, d::KW, letter, anything) -# anything -# end - -# # handle grouping by DataFrame column -# function extractGroupArgs(group::Symbol, df::DataFrames.AbstractDataFrame, args...) -# extractGroupArgs(collect(df[group])) -# end - -# # if a DataFrame is the first arg, lets swap symbols out for columns -# @recipe function f(df::DataFrames.AbstractDataFrame, args...) -# # if any of these attributes are symbols, swap out for the df column -# for k in (:fillrange, :line_z, :marker_z, :markersize, :ribbon, :weights, :xerror, :yerror) -# if haskey(d, k) && isa(d[k], Symbol) -# d[k] = collect(df[d[k]]) -# end -# end - -# # return a list of new arguments -# tuple(Any[handle_dfs(df, d, (i==1 ? "x" : i==2 ? "y" : "z"), arg) for (i,arg) in enumerate(args)]...) -# end -# end -# end - - # --------------------------------------------------------------------------- @@ -541,179 +495,6 @@ end # note: don't add dependencies because this really isn't a drop-in replacement -# # TODO: move boxplots and violin plots to StatPlots when it's ready - -# # --------------------------------------------------------------------------- -# # Box Plot - -# const _box_halfwidth = 0.4 - -# notch_width(q2, q4, N) = 1.58 * (q4-q2)/sqrt(N) - - -# @recipe function f(::Type{Val{:boxplot}}, x, y, z; notch=false, range=1.5) -# xsegs, ysegs = Segments(), Segments() -# glabels = sort(collect(unique(x))) -# warning = false -# outliers_x, outliers_y = zeros(0), zeros(0) -# for (i,glabel) in enumerate(glabels) -# # filter y -# values = y[filter(i -> cycle(x,i) == glabel, 1:length(y))] - -# # compute quantiles -# q1,q2,q3,q4,q5 = quantile(values, linspace(0,1,5)) - -# # notch -# n = notch_width(q2, q4, length(values)) - -# # warn on inverted notches? -# if notch && !warning && ( (q2>(q3-n)) || (q4<(q3+n)) ) -# warn("Boxplot's notch went outside hinges. Set notch to false.") -# warning = true # Show the warning only one time -# end - -# # make the shape -# center = discrete_value!(d[:subplot][:xaxis], glabel)[1] -# hw = d[:bar_width] == nothing ? _box_halfwidth : 0.5cycle(d[:bar_width], i) -# l, m, r = center - hw, center, center + hw - -# # internal nodes for notches -# L, R = center - 0.5 * hw, center + 0.5 * hw - -# # outliers -# if Float64(range) != 0.0 # if the range is 0.0, the whiskers will extend to the data -# limit = range*(q4-q2) -# inside = Float64[] -# for value in values -# if (value < (q2 - limit)) || (value > (q4 + limit)) -# push!(outliers_y, value) -# push!(outliers_x, center) -# else -# push!(inside, value) -# end -# end -# # change q1 and q5 to show outliers -# # using maximum and minimum values inside the limits -# q1, q5 = extrema(inside) -# end - -# # Box -# if notch -# push!(xsegs, m, l, r, m, m) # lower T -# push!(xsegs, l, l, L, R, r, r, l) # lower box -# push!(xsegs, l, l, L, R, r, r, l) # upper box -# push!(xsegs, m, l, r, m, m) # upper T - -# push!(ysegs, q1, q1, q1, q1, q2) # lower T -# push!(ysegs, q2, q3-n, q3, q3, q3-n, q2, q2) # lower box -# push!(ysegs, q4, q3+n, q3, q3, q3+n, q4, q4) # upper box -# push!(ysegs, q5, q5, q5, q5, q4) # upper T -# else -# push!(xsegs, m, l, r, m, m) # lower T -# push!(xsegs, l, l, r, r, l) # lower box -# push!(xsegs, l, l, r, r, l) # upper box -# push!(xsegs, m, l, r, m, m) # upper T - -# push!(ysegs, q1, q1, q1, q1, q2) # lower T -# push!(ysegs, q2, q3, q3, q2, q2) # lower box -# push!(ysegs, q4, q3, q3, q4, q4) # upper box -# push!(ysegs, q5, q5, q5, q5, q4) # upper T -# end -# end - -# # Outliers -# @series begin -# seriestype := :scatter -# markershape := :circle -# markercolor := d[:fillcolor] -# markeralpha := d[:fillalpha] -# markerstrokecolor := d[:linecolor] -# markerstrokealpha := d[:linealpha] -# x := outliers_x -# y := outliers_y -# primary := false -# () -# end - -# seriestype := :shape -# x := xsegs.pts -# y := ysegs.pts -# () -# end -# @deps boxplot shape scatter - -# # --------------------------------------------------------------------------- -# # Violin Plot - -# const _violin_warned = [false] - -# # if the user has KernelDensity installed, use this for violin plots. -# # otherwise, just use a histogram -# if is_installed("KernelDensity") -# @eval import KernelDensity -# @eval function violin_coords(y; trim::Bool=false) -# kd = KernelDensity.kde(y, npoints = 200) -# if trim -# xmin, xmax = extrema(y) -# inside = Bool[ xmin <= x <= xmax for x in kd.x] -# return(kd.density[inside], kd.x[inside]) -# end -# kd.density, kd.x -# end -# else -# @eval function violin_coords(y; trim::Bool=false) -# if !_violin_warned[1] -# warn("Install the KernelDensity package for best results.") -# _violin_warned[1] = true -# end -# edges, widths = my_hist(y, 10) -# centers = 0.5 * (edges[1:end-1] + edges[2:end]) -# ymin, ymax = extrema(y) -# vcat(0.0, widths, 0.0), vcat(ymin, centers, ymax) -# end -# end - - -# @recipe function f(::Type{Val{:violin}}, x, y, z; trim=true) -# xsegs, ysegs = Segments(), Segments() -# glabels = sort(collect(unique(x))) -# for glabel in glabels -# widths, centers = violin_coords(y[filter(i -> cycle(x,i) == glabel, 1:length(y))], trim=trim) -# isempty(widths) && continue - -# # normalize -# widths = _box_halfwidth * widths / maximum(widths) - -# # make the violin -# xcenter = discrete_value!(d[:subplot][:xaxis], glabel)[1] -# xcoords = vcat(widths, -reverse(widths)) + xcenter -# ycoords = vcat(centers, reverse(centers)) - -# push!(xsegs, xcoords) -# push!(ysegs, ycoords) -# end - -# seriestype := :shape -# x := xsegs.pts -# y := ysegs.pts -# () -# end -# @deps violin shape - -# # --------------------------------------------------------------------------- -# # density - -# @recipe function f(::Type{Val{:density}}, x, y, z; trim=false) -# newx, newy = violin_coords(y, trim=trim) -# if isvertical(d) -# newx, newy = newy, newx -# end -# x := newx -# y := newy -# seriestype := :path -# () -# end -# @deps density path # --------------------------------------------------------------------------- # contourf - filled contours @@ -952,14 +733,14 @@ end # series recipe or moved to PlotRecipes -"Sparsity plot... heatmap of non-zero values of a matrix" -function spy{T<:Real}(z::AMat{T}; kw...) - mat = map(zi->float(zi!=0), z)' - xn, yn = size(mat) - heatmap(mat; leg=false, yflip=true, aspect_ratio=:equal, - xlim=(0.5, xn+0.5), ylim=(0.5, yn+0.5), - kw...) -end +# "Sparsity plot... heatmap of non-zero values of a matrix" +# function spy{T<:Real}(z::AMat{T}; kw...) +# mat = map(zi->float(zi!=0), z)' +# xn, yn = size(mat) +# heatmap(mat; leg=false, yflip=true, aspect_ratio=:equal, +# xlim=(0.5, xn+0.5), ylim=(0.5, yn+0.5), +# kw...) +# end "Adds a+bx... straight line over the current plot" function abline!(plt::Plot, a, b; kw...) From f290748c720f0baf0288f396ca68315eb203606e Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Sat, 8 Oct 2016 23:03:07 -0400 Subject: [PATCH 26/50] gr: don't set GKS_WSTYPE for windows/use_default --- src/backends/gr.jl | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 8aafe9f9..0e60f0f5 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -1040,7 +1040,7 @@ const _gr_wstype_default = @static if is_linux() elseif is_apple() "quartz" else - "windows" + "use_default" end const _gr_wstype = Ref(get(ENV, "GKS_WSTYPE", _gr_wstype_default)) @@ -1052,11 +1052,8 @@ for (mime, fmt) in _gr_mimeformats filepath = tempname() * "." * $fmt ENV["GKS_WSTYPE"] = $fmt ENV["GKS_FILEPATH"] = filepath - # withenv("GKS_WSTYPE" => $fmt, # $fmt == "png" ? "cairopng" : $fmt, - # "GKS_FILEPATH" => filepath) do - gr_display(plt) - GR.emergencyclosegks() - # end + gr_display(plt) + GR.emergencyclosegks() write(io, readstring(filepath)) rm(filepath) end @@ -1068,20 +1065,16 @@ function _display(plt::Plot{GRBackend}) filepath = tempname() * ".pdf" ENV["GKS_WSTYPE"] = "pdf" ENV["GKS_FILEPATH"] = filepath - # withenv("GKS_WSTYPE" => "pdf", - # "GKS_FILEPATH" => filepath) do - gr_display(plt) - GR.emergencyclosegks() - # end + gr_display(plt) + GR.emergencyclosegks() content = string("\033]1337;File=inline=1;preserveAspectRatio=0:", base64encode(open(readbytes, filepath)), "\a") println(content) rm(filepath) else ENV["GKS_DOUBLE_BUF"] = true - ENV["GKS_WSTYPE"] = _gr_wstype[] - # withenv("GKS_WSTYPE" => get(ENV, "GKS_WSTYPE", _gr_wstype_default), - # "GKS_DOUBLE_BUF" => get(ENV ,"GKS_DOUBLE_BUF", "true")) do - gr_display(plt) - # end + if _gr_wstype[] != "use_default" + ENV["GKS_WSTYPE"] = _gr_wstype[] + end + gr_display(plt) end end From 9bbe0f9414aa08cfcdd60ef699993f412323512b Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Sat, 8 Oct 2016 23:19:26 -0400 Subject: [PATCH 27/50] gr: image transpose fix --- src/backends/gr.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 0e60f0f5..91b4855d 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -914,8 +914,8 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) elseif st == :image - img = series[:z].surf - h, w = size(img) + z = transpose_z(series, series[:z].surf, true) + h, w = size(z) if eltype(z) <: Colors.AbstractGray grey = round(UInt8, float(z) * 255) rgba = map(c -> UInt32( 0xff000000 + Int(c)<<16 + Int(c)<<8 + Int(c) ), grey) From 5e8c88d657f76e3609bca588706e0669c5a963d7 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Sun, 9 Oct 2016 00:52:53 -0400 Subject: [PATCH 28/50] spy recipes --- src/recipes.jl | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/recipes.jl b/src/recipes.jl index ffca23fc..78db2d7d 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -742,6 +742,43 @@ end # kw...) # end +# Only allow matrices through, and make it seriestype :spy so the backend can +# optionally handle it natively. + +@userplot Spy + +@recipe function f(g::Spy) + @assert length(g.args) == 1 && typeof(g.args[1]) <: AbstractMatrix + seriestype := :spy + mat = g.args[1] + n,m = size(mat) + Plots.SliceIt, 1:m, 1:n, Surface(mat) +end + +@recipe function f(::Type{Val{:spy}}, x,y,z) + yflip := true + aspect_ratio := 1 + rs, cs, zs = findnz(z.surf) + xlim := extrema(cs) + ylim := extrema(rs) + if d[:markershape] == :none + markershape := :circle + end + if d[:markersize] == default(:markersize) + markersize := 1 + end + markerstrokewidth := 0 + marker_z := zs + label := "" + x := cs + y := rs + z := nothing + seriestype := :scatter + () +end + +# ------------------------------------------------- + "Adds a+bx... straight line over the current plot" function abline!(plt::Plot, a, b; kw...) plot!(plt, [extrema(plt)...], x -> b + a*x; kw...) From ae608d4d78dfcbd91a75bc29c4d5f2c811bbef33 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Mon, 10 Oct 2016 01:08:29 -0400 Subject: [PATCH 29/50] staged date fix, still not working --- src/backends.jl | 2 +- src/recipes.jl | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/backends.jl b/src/backends.jl index 7cd4e898..46b23dcb 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -59,7 +59,7 @@ function tick_padding(axis::Axis) else vals, labs = ticks ptsz = axis[:tickfont].pointsize * pt - + # we need to compute the size of the ticks generically # this means computing the bounding box and then getting the width/height longest_label = maximum(length(lab) for lab in labs) diff --git a/src/recipes.jl b/src/recipes.jl index 78db2d7d..809c3477 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -792,12 +792,10 @@ abline!(args...; kw...) = abline!(current(), args...; kw...) @recipe function f{T<:AbstractArray{Date}}(::Type{T}, dts::T) date_formatter = dt -> string(convert(Date, dt)) - xformatter := date_formatter - map(dt->convert(Int,dt), dts) + Formatted(map(dt->convert(Int,dt), dts), date_formatter) end @recipe function f{T<:AbstractArray{DateTime}}(::Type{T}, dts::T) date_formatter = dt -> string(convert(DateTime, dt)) - xformatter := date_formatter - map(dt->convert(Int,dt), dts) + Formatted(map(dt->convert(Int,dt), dts), date_formatter) end From b9dea42be662b2716e8854b225a5804e02be147a Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Mon, 10 Oct 2016 07:02:10 -0400 Subject: [PATCH 30/50] fix Date recipe; closes #529 --- src/recipes.jl | 10 ++-------- src/series.jl | 4 ++-- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/recipes.jl b/src/recipes.jl index 809c3477..e9c29cee 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -790,12 +790,6 @@ abline!(args...; kw...) = abline!(current(), args...; kw...) # ------------------------------------------------- # Dates -@recipe function f{T<:AbstractArray{Date}}(::Type{T}, dts::T) - date_formatter = dt -> string(convert(Date, dt)) - Formatted(map(dt->convert(Int,dt), dts), date_formatter) -end - -@recipe function f{T<:AbstractArray{DateTime}}(::Type{T}, dts::T) - date_formatter = dt -> string(convert(DateTime, dt)) - Formatted(map(dt->convert(Int,dt), dts), date_formatter) +@recipe function f{T<:Union{Date,DateTime}}(::Type{T}, dt::T) + dt -> convert(Int,dt), dt -> string(convert(Date, dt)) end diff --git a/src/series.jl b/src/series.jl index 86be6954..8b836af4 100644 --- a/src/series.jl +++ b/src/series.jl @@ -42,8 +42,8 @@ convertToAnyVector(v::Volume, d::KW) = Any[v], nothing # # vector of OHLC # convertToAnyVector(v::AVec{OHLC}, d::KW) = Any[v], nothing -# dates -convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::KW) = Any[dts], nothing +# # dates +# convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::KW) = Any[dts], nothing # list of things (maybe other vectors, functions, or something else) function convertToAnyVector(v::AVec, d::KW) From 702ab3c5047643060ae1587f2c1f26365eb0629c Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Mon, 10 Oct 2016 07:34:51 -0400 Subject: [PATCH 31/50] remove plotly png output... point to plotlyjs --- src/backends/plotly.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index 627adeb7..d2548cf8 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -631,7 +631,8 @@ end function _show(io::IO, ::MIME"image/png", plt::Plot{PlotlyBackend}) - show_png_from_html(io, plt) + # show_png_from_html(io, plt) + error("png output from the plotly backend is not supported. Please use plotlyjs instead.") end function _show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyBackend}) From 93e7bc2a2e249a1328ef5e7d6346ff4a45130e67 Mon Sep 17 00:00:00 2001 From: Josef Heinen Date: Tue, 11 Oct 2016 15:03:31 +0200 Subject: [PATCH 32/50] gr: changed heatmap code --- src/backends/gr.jl | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 91b4855d..6f2706bd 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -816,18 +816,19 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) cmap && gr_colorbar(sp) elseif st == :heatmap - # z = vec(transpose_z(series, z.surf, false)) zmin, zmax = gr_lims(zaxis, true) + data = (float(z) - zmin) / (zmax - zmin) clims = sp[:clims] if is_2tuple(clims) isfinite(clims[1]) && (zmin = clims[1]) isfinite(clims[2]) && (zmax = clims[2]) end - GR.setspace(zmin, zmax, 0, 90) - # GR.surface(x, y, z, GR.OPTION_COLORED_MESH) - # GR.surface(x, y, z, GR.OPTION_HEATMAP) - # gr_nans_to_infs!(z) - GR.surface(x, y, z, GR.OPTION_CELL_ARRAY) + data = [if zmin<=d<=zmax 1000 + d * 255 else 0 end for d in data] + data = round(Int32, data) + xmin, xmax = gr_lims(xaxis, false) + ymin, ymax = gr_lims(yaxis, false) + width, height = length(x), length(y) + GR.cellarray(xmin, xmax, ymin, ymax, width, height, data) cmap && gr_colorbar(sp) elseif st in (:path3d, :scatter3d) From 77fbf3eb513ec4f04fe06bb41ca641ad0f507701 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Tue, 11 Oct 2016 10:32:51 -0400 Subject: [PATCH 33/50] use drawimage for heatmap --- src/backends/gr.jl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 6f2706bd..7a12bae7 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -817,18 +817,18 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) elseif st == :heatmap zmin, zmax = gr_lims(zaxis, true) - data = (float(z) - zmin) / (zmax - zmin) clims = sp[:clims] if is_2tuple(clims) isfinite(clims[1]) && (zmin = clims[1]) isfinite(clims[2]) && (zmax = clims[2]) end - data = [if zmin<=d<=zmax 1000 + d * 255 else 0 end for d in data] - data = round(Int32, data) - xmin, xmax = gr_lims(xaxis, false) - ymin, ymax = gr_lims(yaxis, false) - width, height = length(x), length(y) - GR.cellarray(xmin, xmax, ymin, ymax, width, height, data) + grad = isa(series[:fillcolor], ColorGradient) ? series[:fillcolor] : cgrad() + colors = [grad[clamp((zi-zmin) / (zmax-zmin), 0, 1)] for zi=z] + rgba = map(c -> UInt32( round(Int, alpha(c) * 255) << 24 + + round(Int, blue(c) * 255) << 16 + + round(Int, green(c) * 255) << 8 + + round(Int, red(c) * 255) ), colors) + GR.drawimage(xmin, xmax, ymin, ymax, length(x), length(y), rgba) cmap && gr_colorbar(sp) elseif st in (:path3d, :scatter3d) From 81302c1e9dad35ae1c713268f5fe39452819fa12 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Tue, 11 Oct 2016 12:43:38 -0400 Subject: [PATCH 34/50] NEWS; bump version --- NEWS.md | 25 +++++++++++++++++++++++++ test/imgcomp.jl | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index a832f440..640a192e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -12,6 +12,31 @@ ## 0.9 (current master/dev) +#### 0.9.4 + +- optimizations surrounding Subplot.series_list +- better Atom support, support plotlyjs +- gr: + - gks_wstype defaults and gr_set_output + - heatmap uses GR.drawimage +- histogram2d puts NaN for zeros +- improved support of NaN in heatmaps +- rebuilt spy recipes to output scatters with marker_z set +- deprecate png support in plotly... point to plotlyjs +- fixes: + - axis widen with lims set + - reset_extrema, setxyz + - bar plot widen + - better tick padding + - consistent tick rotation + - consistent aspect_ratio + - pyplot dpi + - plotly horizontal bars + - handle series attributes when combining subplots + - gr images transposed + - converted Date/DateTime to new type recipe approach for arrays +- issues closed include: #505 #513 #479 #523 #526 #529 + #### 0.9.3 - support pdf and eps in plotlyjs backend diff --git a/test/imgcomp.jl b/test/imgcomp.jl index 9eb79021..fe0493a1 100644 --- a/test/imgcomp.jl +++ b/test/imgcomp.jl @@ -24,7 +24,7 @@ default(size=(500,300)) # TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that # is referenced in a button press callback (the button clicked callback will call notify() on that condition) -const _current_plots_version = v"0.9.4" +const _current_plots_version = v"0.9.5" function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2) From b181788dc22405f3a24404c9144021b139998d5b Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Tue, 11 Oct 2016 15:36:56 -0400 Subject: [PATCH 35/50] add PlotThemes dep, change set_theme to theme --- REQUIRE | 2 +- src/Plots.jl | 17 +------ src/themes.jl | 133 +++++++++++++++++++++++++++----------------------- 3 files changed, 76 insertions(+), 76 deletions(-) diff --git a/REQUIRE b/REQUIRE index f0aaec83..4b52b996 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,4 +1,4 @@ -julia 0.5- +julia 0.5 RecipesBase PlotUtils diff --git a/src/Plots.jl b/src/Plots.jl index 9e2ca468..eebe49b8 100644 --- a/src/Plots.jl +++ b/src/Plots.jl @@ -3,14 +3,12 @@ __precompile__() module Plots -# using Compat using Reexport -# @reexport using Colors -# using Requires using FixedSizeArrays @reexport using RecipesBase using Base.Meta @reexport using PlotUtils +@reexport using PlotThemes import Showoff export @@ -29,8 +27,7 @@ export KW, wrap, - set_theme, - add_theme, + theme, plot, plot!, @@ -77,7 +74,6 @@ export backend_object, add_backend, aliases, - # dataframes, Shape, text, @@ -97,8 +93,6 @@ export @animate, @gif, - # spy, - test_examples, iter_segments, coords, @@ -247,11 +241,4 @@ end # --------------------------------------------------------- -# if VERSION >= v"0.4.0-dev+5512" -# include("precompile.jl") -# _precompile_() -# end - -# --------------------------------------------------------- - end # module diff --git a/src/themes.jl b/src/themes.jl index 0de2bbdf..16845ffb 100644 --- a/src/themes.jl +++ b/src/themes.jl @@ -1,65 +1,78 @@ -const _invisible = RGBA(0,0,0,0) +# const _invisible = RGBA(0,0,0,0) +# +# const _themes = KW( +# :default => KW( +# :bg => :white, +# :bglegend => :match, +# :bginside => :match, +# :bgoutside => :match, +# :fg => :auto, +# :fglegend => :match, +# :fggrid => :match, +# :fgaxis => :match, +# :fgtext => :match, +# :fgborder => :match, +# :fgguide => :match, +# ) +# ) -const _themes = KW( - :default => KW( - :bg => :white, - :bglegend => :match, - :bginside => :match, - :bgoutside => :match, - :fg => :auto, - :fglegend => :match, - :fggrid => :match, - :fgaxis => :match, - :fgtext => :match, - :fgborder => :match, - :fgguide => :match, +# function add_theme(sym::Symbol, theme::KW) +# _themes[sym] = theme +# end +# +# # add a new theme, using an existing theme as the base +# function add_theme(sym::Symbol; +# base = :default, # start with this theme +# bg = _themes[base][:bg], +# bglegend = _themes[base][:bglegend], +# bginside = _themes[base][:bginside], +# bgoutside = _themes[base][:bgoutside], +# fg = _themes[base][:fg], +# fglegend = _themes[base][:fglegend], +# fggrid = _themes[base][:fggrid], +# fgaxis = _themes[base][:fgaxis], +# fgtext = _themes[base][:fgtext], +# fgborder = _themes[base][:fgborder], +# fgguide = _themes[base][:fgguide], +# kw...) +# _themes[sym] = merge(KW( +# :bg => bg, +# :bglegend => bglegend, +# :bginside => bginside, +# :bgoutside => bgoutside, +# :fg => fg, +# :fglegend => fglegend, +# :fggrid => fggrid, +# :fgaxis => fgaxis, +# :fgtext => fgtext, +# :fgborder => fgborder, +# :fgguide => fgguide, +# ), KW(kw)) +# end +# +# add_theme(:ggplot2, +# bglegend = :lightgray, +# bginside = :lightgray, +# fg = :black, +# fggrid = :white, +# fgborder = _invisible, +# fgaxis = _invisible +# ) + +function theme(s::Symbol; kw...) + thm = PlotThemes._themes[s] + PlotUtils._default_gradient[] = s + default(; + bg = thm.bg_secondary, + bginside = thm.bg_primary, + fg = thm.lines, + fgtext = thm.text, + fgguide = thm.text, + fglegend = thm.text, + palette = thm.palette, + kw... ) -) - -function add_theme(sym::Symbol, theme::KW) - _themes[sym] = theme end -# add a new theme, using an existing theme as the base -function add_theme(sym::Symbol; - base = :default, # start with this theme - bg = _themes[base][:bg], - bglegend = _themes[base][:bglegend], - bginside = _themes[base][:bginside], - bgoutside = _themes[base][:bgoutside], - fg = _themes[base][:fg], - fglegend = _themes[base][:fglegend], - fggrid = _themes[base][:fggrid], - fgaxis = _themes[base][:fgaxis], - fgtext = _themes[base][:fgtext], - fgborder = _themes[base][:fgborder], - fgguide = _themes[base][:fgguide], - kw...) - _themes[sym] = merge(KW( - :bg => bg, - :bglegend => bglegend, - :bginside => bginside, - :bgoutside => bgoutside, - :fg => fg, - :fglegend => fglegend, - :fggrid => fggrid, - :fgaxis => fgaxis, - :fgtext => fgtext, - :fgborder => fgborder, - :fgguide => fgguide, - ), KW(kw)) -end - -add_theme(:ggplot2, - bglegend = :lightgray, - bginside = :lightgray, - fg = :black, - fggrid = :white, - fgborder = _invisible, - fgaxis = _invisible -) - -function set_theme(sym::Symbol) - default(; _themes[sym]...) -end +@deprecate set_theme(s) theme(s) From 7ff843ec1a6e8459e9beed77527fa490cbe41325 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Tue, 11 Oct 2016 16:50:58 -0400 Subject: [PATCH 36/50] msw alias --- src/args.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/args.jl b/src/args.jl index 6a72a733..ea07cbae 100644 --- a/src/args.jl +++ b/src/args.jl @@ -353,6 +353,7 @@ add_aliases(:seriescolor, :c, :color, :colour) add_aliases(:linecolor, :lc, :lcolor, :lcolour, :linecolour) add_aliases(:markercolor, :mc, :mcolor, :mcolour, :markercolour) add_aliases(:markerstrokecolor, :msc, :mscolor, :mscolour, :markerstrokecolour) +add_aliases(:markerstrokewidth, :msw, :mswidth) add_aliases(:fillcolor, :fc, :fcolor, :fcolour, :fillcolour) add_aliases(:background_color, :bg, :bgcolor, :bg_color, :background, From 9de3ed8cf05ffa5845db865c3b77628c6b742b0d Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Tue, 11 Oct 2016 19:20:07 -0400 Subject: [PATCH 37/50] remove Compat from REQUIRE --- REQUIRE | 1 - 1 file changed, 1 deletion(-) diff --git a/REQUIRE b/REQUIRE index 4b52b996..440fa7f5 100644 --- a/REQUIRE +++ b/REQUIRE @@ -3,7 +3,6 @@ julia 0.5 RecipesBase PlotUtils Reexport -Compat FixedSizeArrays Measures Showoff From f002f66890bf67a46bb8d70b77edc2c6a57a6d5f Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Wed, 12 Oct 2016 09:30:49 -0400 Subject: [PATCH 38/50] add PlotThemes to REQUIRE; add warning for DataFrames --- REQUIRE | 1 + src/plot.jl | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/REQUIRE b/REQUIRE index 440fa7f5..67e5f781 100644 --- a/REQUIRE +++ b/REQUIRE @@ -2,6 +2,7 @@ julia 0.5 RecipesBase PlotUtils +PlotThemes Reexport FixedSizeArrays Measures diff --git a/src/plot.jl b/src/plot.jl index 6d05ba66..498135f6 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -161,6 +161,11 @@ end function _plot!(plt::Plot, d::KW, args::Tuple) d[:plot_object] = plt + if !isempty(args) && !isdefined(Main, :StatPlots) && + first(split(string(typeof(args[1])), ".")) == "DataFrames" + warn("You're trying to plot a DataFrame, but this functionality is provided by StatPlots") + end + # -------------------------------- # "USER RECIPES" # -------------------------------- From 7fb995094e73d23cefcd4ddf081ae6f333361c54 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Wed, 12 Oct 2016 11:28:43 -0400 Subject: [PATCH 39/50] added closeall for gr/pyplot --- src/Plots.jl | 1 + src/backends/gr.jl | 2 ++ src/backends/pyplot.jl | 2 ++ src/output.jl | 2 ++ 4 files changed, 7 insertions(+) diff --git a/src/Plots.jl b/src/Plots.jl index eebe49b8..b5f09597 100644 --- a/src/Plots.jl +++ b/src/Plots.jl @@ -67,6 +67,7 @@ export savefig, png, gui, + closeall, backend, backends, diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 7a12bae7..c3573614 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -1079,3 +1079,5 @@ function _display(plt::Plot{GRBackend}) gr_display(plt) end end + +closeall(::GRBackend) = GR.emergencyclosegks() diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index eb0ce0ad..abac4017 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -1224,3 +1224,5 @@ for (mime, fmt) in _pyplot_mimeformats ) end end + +closeall(::PyPlotBackend) = PyPlot.plt[:close]("all") diff --git a/src/output.jl b/src/output.jl index b71dc7ed..d2b7da7c 100644 --- a/src/output.jl +++ b/src/output.jl @@ -172,6 +172,8 @@ for mime in keys(_mimeformats) end end +closeall() = closeall(backend()) + # --------------------------------------------------------- # A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert From d136977fc468d401345ff697cb513575f2233996 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Wed, 12 Oct 2016 13:25:19 -0400 Subject: [PATCH 40/50] fix date/datetime --- src/recipes.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/recipes.jl b/src/recipes.jl index e9c29cee..6a5cc4c7 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -790,6 +790,5 @@ abline!(args...; kw...) = abline!(current(), args...; kw...) # ------------------------------------------------- # Dates -@recipe function f{T<:Union{Date,DateTime}}(::Type{T}, dt::T) - dt -> convert(Int,dt), dt -> string(convert(Date, dt)) -end +@recipe f(::Type{Date}, dt::Date) = (dt -> convert(Int,dt), dt -> string(convert(Date,dt))) +@recipe f(::Type{DateTime}, dt::DateTime) = (dt -> convert(Int,dt), dt -> string(convert(DateTime,dt))) From 9d64914e628f0dc8340845e9e1497020e8a9b328 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Wed, 12 Oct 2016 13:34:07 -0400 Subject: [PATCH 41/50] reset theme with :none/:default --- src/themes.jl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/themes.jl b/src/themes.jl index 16845ffb..9e4a3173 100644 --- a/src/themes.jl +++ b/src/themes.jl @@ -61,6 +61,25 @@ # ) function theme(s::Symbol; kw...) + # reset? + if s == :none || s == :default + default(; + bg = :white, + bglegend = :match, + bginside = :match, + bgoutside = :match, + fg = :auto, + fglegend = :match, + fggrid = :match, + fgaxis = :match, + fgtext = :match, + fgborder = :match, + fgguide = :match, + palette = :auto + ) + return + end + thm = PlotThemes._themes[s] PlotUtils._default_gradient[] = s default(; From 6677e0e0a007852f4712005ee5cc0f8ee360d9ce Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Wed, 12 Oct 2016 14:52:30 -0400 Subject: [PATCH 42/50] fix link_axes for nested singleton subplot --- src/layouts.jl | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/layouts.jl b/src/layouts.jl index dba708ee..6c47949c 100644 --- a/src/layouts.jl +++ b/src/layouts.jl @@ -692,9 +692,22 @@ function link_axes!(axes::Axis...) end end +# figure out which subplots to link +function link_subplots(a::AbstractArray{AbstractLayout}, axissym::Symbol) + subplots = [] + for l in a + if isa(l, Subplot) + push!(subplots, l) + elseif isa(l, GridLayout) && size(l) == (1,1) + push!(subplots, l[1,1]) + end + end + subplots +end + # for some vector or matrix of layouts, filter only the Subplots and link those axes function link_axes!(a::AbstractArray{AbstractLayout}, axissym::Symbol) - subplots = filter(l -> isa(l, Subplot), a) + subplots = link_subplots(a, axissym) axes = [sp.attr[axissym] for sp in subplots] if length(axes) > 0 link_axes!(axes...) From aee13d295c1bf34315e7682336d6a3352d9a9753 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Wed, 12 Oct 2016 15:11:51 -0400 Subject: [PATCH 43/50] fix plotlyjs lims: apply scalefunc --- src/backends/plotly.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index d2548cf8..3ad993f3 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -218,7 +218,7 @@ function plotly_axis(axis::Axis, sp::Subplot) # lims lims = axis[:lims] if lims != :auto && limsType(lims) == :limits - ax[:range] = lims + ax[:range] = map(scalefunc(axis[:scale]), lims) end # flip From e2adcbb486000ca3e0b3fb8c0162ec41731196d4 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Thu, 13 Oct 2016 09:53:25 -0400 Subject: [PATCH 44/50] fix gradient in theme --- src/themes.jl | 67 ++++----------------------------------------------- 1 file changed, 5 insertions(+), 62 deletions(-) diff --git a/src/themes.jl b/src/themes.jl index 9e4a3173..5bdf6fe6 100644 --- a/src/themes.jl +++ b/src/themes.jl @@ -1,68 +1,8 @@ -# const _invisible = RGBA(0,0,0,0) -# -# const _themes = KW( -# :default => KW( -# :bg => :white, -# :bglegend => :match, -# :bginside => :match, -# :bgoutside => :match, -# :fg => :auto, -# :fglegend => :match, -# :fggrid => :match, -# :fgaxis => :match, -# :fgtext => :match, -# :fgborder => :match, -# :fgguide => :match, -# ) -# ) - -# function add_theme(sym::Symbol, theme::KW) -# _themes[sym] = theme -# end -# -# # add a new theme, using an existing theme as the base -# function add_theme(sym::Symbol; -# base = :default, # start with this theme -# bg = _themes[base][:bg], -# bglegend = _themes[base][:bglegend], -# bginside = _themes[base][:bginside], -# bgoutside = _themes[base][:bgoutside], -# fg = _themes[base][:fg], -# fglegend = _themes[base][:fglegend], -# fggrid = _themes[base][:fggrid], -# fgaxis = _themes[base][:fgaxis], -# fgtext = _themes[base][:fgtext], -# fgborder = _themes[base][:fgborder], -# fgguide = _themes[base][:fgguide], -# kw...) -# _themes[sym] = merge(KW( -# :bg => bg, -# :bglegend => bglegend, -# :bginside => bginside, -# :bgoutside => bgoutside, -# :fg => fg, -# :fglegend => fglegend, -# :fggrid => fggrid, -# :fgaxis => fgaxis, -# :fgtext => fgtext, -# :fgborder => fgborder, -# :fgguide => fgguide, -# ), KW(kw)) -# end -# -# add_theme(:ggplot2, -# bglegend = :lightgray, -# bginside = :lightgray, -# fg = :black, -# fggrid = :white, -# fgborder = _invisible, -# fgaxis = _invisible -# ) - function theme(s::Symbol; kw...) # reset? if s == :none || s == :default + PlotUtils._default_gradient[] = :inferno default(; bg = :white, bglegend = :match, @@ -80,8 +20,11 @@ function theme(s::Symbol; kw...) return end + # update the default gradient and other defaults thm = PlotThemes._themes[s] - PlotUtils._default_gradient[] = s + if thm.gradient != nothing + PlotUtils._default_gradient[] = s + end default(; bg = thm.bg_secondary, bginside = thm.bg_primary, From 0a8d88a4fe594272c13ab61dc7d700df0d6cba31 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Thu, 13 Oct 2016 09:56:27 -0400 Subject: [PATCH 45/50] NEWS; bump version --- NEWS.md | 12 ++++++++++++ test/imgcomp.jl | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 640a192e..c1c98498 100644 --- a/NEWS.md +++ b/NEWS.md @@ -12,6 +12,18 @@ ## 0.9 (current master/dev) +#### 0.9.5 + +- added dependency on PlotThemes +- set_theme --> theme +- remove Compat from REQUIRE +- warning for DataFrames without StatPlots +- closeall exported and implemented for gr/pyplot +- fix DateTime recipe +- reset theme with theme(:none) +- fix link_axes! for nested subplots +- fix plotly lims for log scale + #### 0.9.4 - optimizations surrounding Subplot.series_list diff --git a/test/imgcomp.jl b/test/imgcomp.jl index fe0493a1..71f94924 100644 --- a/test/imgcomp.jl +++ b/test/imgcomp.jl @@ -24,7 +24,7 @@ default(size=(500,300)) # TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that # is referenced in a button press callback (the button clicked callback will call notify() on that condition) -const _current_plots_version = v"0.9.5" +const _current_plots_version = v"0.9.6" function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2) From b1835a91af19ddfe1e16883abbac714bbeecdbed Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Thu, 13 Oct 2016 13:24:25 -0400 Subject: [PATCH 46/50] gr extrema fix; themes gradient_name fix --- src/backends/gr.jl | 8 ++++---- src/themes.jl | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/backends/gr.jl b/src/backends/gr.jl index c3573614..99782ea1 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -732,10 +732,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) # recompute data if typeof(z) <: Surface - if st == :heatmap - expand_extrema!(sp[:xaxis], (x[1]-0.5*(x[2]-x[1]), x[end]+0.5*(x[end]-x[end-1]))) - expand_extrema!(sp[:yaxis], (y[1]-0.5*(y[2]-y[1]), y[end]+0.5*(y[end]-y[end-1]))) - end + # if st == :heatmap + # expand_extrema!(sp[:xaxis], (x[1]-0.5*(x[2]-x[1]), x[end]+0.5*(x[end]-x[end-1]))) + # expand_extrema!(sp[:yaxis], (y[1]-0.5*(y[2]-y[1]), y[end]+0.5*(y[end]-y[end-1]))) + # end z = vec(transpose_z(series, z.surf, false)) elseif ispolar(sp) if frng != nothing diff --git a/src/themes.jl b/src/themes.jl index 5bdf6fe6..3429585a 100644 --- a/src/themes.jl +++ b/src/themes.jl @@ -23,7 +23,7 @@ function theme(s::Symbol; kw...) # update the default gradient and other defaults thm = PlotThemes._themes[s] if thm.gradient != nothing - PlotUtils._default_gradient[] = s + PlotUtils._default_gradient[] = PlotThemes.gradient_name(s) end default(; bg = thm.bg_secondary, From ebc591747ad4778c29ded8fd38db8c66ae1b54f5 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Fri, 14 Oct 2016 10:42:09 -0400 Subject: [PATCH 47/50] fix empty axes; closes #536 --- src/axes.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/axes.jl b/src/axes.jl index 0cd8ac4c..9938591d 100644 --- a/src/axes.jl +++ b/src/axes.jl @@ -381,6 +381,9 @@ function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis) if amax <= amin && isfinite(amin) amax = amin + 1.0 end + if !isfinite(amin) && !isfinite(amax) + amin, amax = 0.0, 1.0 + end if should_widen widen(amin, amax) else From d291582ad974dd9c8ee9c54884d88b8cd1123b7f Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Fri, 14 Oct 2016 13:49:47 -0400 Subject: [PATCH 48/50] fix gr flipped heatmap --- src/backends/gr.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 99782ea1..0ad65528 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -828,7 +828,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) round(Int, blue(c) * 255) << 16 + round(Int, green(c) * 255) << 8 + round(Int, red(c) * 255) ), colors) - GR.drawimage(xmin, xmax, ymin, ymax, length(x), length(y), rgba) + GR.drawimage(xmin, xmax, ymax, ymin, length(x), length(y), rgba) cmap && gr_colorbar(sp) elseif st in (:path3d, :scatter3d) From aa6814a6d310594693678e907538a16c23be8564 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Tue, 18 Oct 2016 20:45:56 -0400 Subject: [PATCH 49/50] rename update! to attr! --- src/Plots.jl | 2 +- src/args.jl | 2 +- src/axes.jl | 4 ++-- src/utils.jl | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Plots.jl b/src/Plots.jl index b5f09597..60a885cc 100644 --- a/src/Plots.jl +++ b/src/Plots.jl @@ -31,7 +31,7 @@ export plot, plot!, - update!, + attr!, current, default, diff --git a/src/args.jl b/src/args.jl index ea07cbae..490eaddc 100644 --- a/src/args.jl +++ b/src/args.jl @@ -1094,7 +1094,7 @@ function _update_axis(axis::Axis, d_in::KW, letter::Symbol, subplot_index::Int) end # update the axis - update!(axis, args...; kw...) + attr!(axis, args...; kw...) return end diff --git a/src/axes.jl b/src/axes.jl index 9938591d..b9840e7a 100644 --- a/src/axes.jl +++ b/src/axes.jl @@ -29,7 +29,7 @@ function Axis(sp::Subplot, letter::Symbol, args...; kw...) d[:discrete_values] = [] # update the defaults - update!(Axis([sp], d), args...; kw...) + attr!(Axis([sp], d), args...; kw...) end function get_axis(sp::Subplot, letter::Symbol) @@ -83,7 +83,7 @@ function process_axis_arg!(d::KW, arg, letter = "") end # update an Axis object with magic args and keywords -function update!(axis::Axis, args...; kw...) +function attr!(axis::Axis, args...; kw...) # first process args d = axis.d for arg in args diff --git a/src/utils.jl b/src/utils.jl index 379a89cc..7483d0a8 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -714,28 +714,28 @@ Base.push!(series::Series, xi, yi, zi) = (push_x!(series,xi); push_y!(series,yi) # ------------------------------------------------------- -function update!(series::Series; kw...) +function attr!(series::Series; kw...) d = KW(kw) preprocessArgs!(d) for (k,v) in d if haskey(_series_defaults, k) series[k] = v else - warn("unused key $k in series update") + warn("unused key $k in series attr") end end _series_updated(series[:subplot].plt, series) series end -function update!(sp::Subplot; kw...) +function attr!(sp::Subplot; kw...) d = KW(kw) preprocessArgs!(d) for (k,v) in d if haskey(_subplot_defaults, k) sp[k] = v else - warn("unused key $k in subplot update") + warn("unused key $k in subplot attr") end end sp From 3aac2b28955f549b750304e398c2633b4e0cf156 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Tue, 25 Oct 2016 22:33:53 -0400 Subject: [PATCH 50/50] check for empty labs --- src/backends.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backends.jl b/src/backends.jl index 46b23dcb..2118d732 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -58,6 +58,7 @@ function tick_padding(axis::Axis) 0mm else vals, labs = ticks + isempty(labs) && return 0mm ptsz = axis[:tickfont].pointsize * pt # we need to compute the size of the ticks generically