diff --git a/src/args.jl b/src/args.jl index d146d966..ad4cae15 100644 --- a/src/args.jl +++ b/src/args.jl @@ -57,6 +57,9 @@ is3d(seriestype::Symbol) = seriestype in _3dTypes is3d(series::Series) = is3d(series.d) is3d(d::KW) = trueOrAllTrue(is3d, d[:seriestype]) +is3d(sp::Subplot) = string(sp.attr[:projection]) == "3d" +ispolar(sp::Subplot) = string(sp.attr[:projection]) == "polar" + const _allStyles = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] @compat const _styleAliases = KW( :a => :auto, @@ -171,7 +174,7 @@ const _plot_defaults = KW( :foreground_color => :auto, # default for all foregrounds, and title color, :size => (600,400), :pos => (0,0), - :windowtitle => "Plots.jl", + :window_title => "Plots.jl", :show => false, :layout => 1, # :num_subplots => -1, @@ -231,6 +234,7 @@ const _suppress_warnings = KW( :x_discrete_indices => nothing, :y_discrete_indices => nothing, :z_discrete_indices => nothing, + :subplot => nothing, ) # add defaults for the letter versions @@ -381,7 +385,7 @@ add_aliases(:colorbar, :cb, :cbar, :colorkey) add_aliases(:smooth, :regression, :reg) add_aliases(:levels, :nlevels, :nlev, :levs) add_aliases(:size, :windowsize, :wsize) -add_aliases(:windowtitle, :wtitle) +add_aliases(:window_title, :windowtitle, :wtitle) add_aliases(:show, :gui, :display) add_aliases(:color_palette, :palette) add_aliases(:linkx, :xlink) @@ -627,7 +631,7 @@ function preprocessArgs!(d::KW) end # delete!(d, asym) - # # NOTE: this logic was moved to _add_plotargs... + # # NOTE: this logic was moved to _add_attr... # # turn :labels into :ticks_and_labels # tsym = symbol(letter * "ticks") # if haskey(d, tsym) && ticksType(d[tsym]) == :labels @@ -913,9 +917,9 @@ function color_or_match!(d::KW, k::Symbol, match_color) end -# update plotargs from an input dictionary +# update attr from an input dictionary function _update_plot_args(plt::Plot, d_in::KW) - pargs = plt.plotargs + pargs = plt.attr for (k,v) in _plot_defaults slice_arg!(d_in, pargs, k, v) end @@ -934,7 +938,7 @@ end # update a subplots args and axes function _update_subplot_args(plt::Plot, sp::Subplot, d_in::KW, subplot_index::Integer) - pargs = plt.plotargs + pargs = plt.attr spargs = sp.attr # @show subplot_index, sp for (k,v) in _subplot_defaults @@ -1040,7 +1044,7 @@ function has_black_border_for_default(st::Symbol) end # # # build the argument dictionary for a series -# function getSeriesArgs(pkg::AbstractBackend, plotargs::KW, kw, commandIndex::Int, plotIndex::Int, globalIndex::Int) # TODO, pass in plotargs, not plt +# function getSeriesArgs(pkg::AbstractBackend, attr::KW, kw, commandIndex::Int, plotIndex::Int, globalIndex::Int) # TODO, pass in attr, not plt # kwdict = KW(kw) # d = KW() # @@ -1065,21 +1069,21 @@ end # aliasesAndAutopick(d, :markershape, _markerAliases, supportedMarkers(pkg), plotIndex) # # # update color -# d[:seriescolor] = getSeriesRGBColor(d[:seriescolor], plotargs, plotIndex) +# d[:seriescolor] = getSeriesRGBColor(d[:seriescolor], attr, plotIndex) # # # # update linecolor # # c = d[:linecolor] -# # c = (c == :match ? d[:seriescolor] : getSeriesRGBColor(c, plotargs, plotIndex)) +# # c = (c == :match ? d[:seriescolor] : getSeriesRGBColor(c, attr, plotIndex)) # # d[:linecolor] = c # # # # update markercolor # # c = d[:markercolor] -# # c = (c == :match ? d[:seriescolor] : getSeriesRGBColor(c, plotargs, plotIndex)) +# # c = (c == :match ? d[:seriescolor] : getSeriesRGBColor(c, attr, plotIndex)) # # d[:markercolor] = c # # # # update fillcolor # # c = d[:fillcolor] -# # c = (c == :match ? d[:seriescolor] : getSeriesRGBColor(c, plotargs, plotIndex)) +# # c = (c == :match ? d[:seriescolor] : getSeriesRGBColor(c, attr, plotIndex)) # # d[:fillcolor] = c # # # update colors @@ -1091,13 +1095,13 @@ end # d[:seriescolor] # end # else -# getSeriesRGBColor(d[csym], plotargs, plotIndex) +# getSeriesRGBColor(d[csym], attr, plotIndex) # end # end # # # update markerstrokecolor # c = d[:markerstrokecolor] -# c = (c == :match ? plotargs[:foreground_color] : getSeriesRGBColor(c, plotargs, plotIndex)) +# c = (c == :match ? attr[:foreground_color] : getSeriesRGBColor(c, attr, plotIndex)) # d[:markerstrokecolor] = c # # # update alphas diff --git a/src/backends.jl b/src/backends.jl index e8ceec80..5b78aab6 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -48,15 +48,16 @@ include("backends/web.jl") plot(pkg::AbstractBackend; kw...) = error("plot($pkg; kw...) is not implemented") plot!(pkg::AbstractBackend, plt::Plot; kw...) = error("plot!($pkg, plt; kw...) is not implemented") _update_plot(pkg::AbstractBackend, plt::Plot, d::KW) = error("_update_plot($pkg, plt, d) is not implemented") -# subplot(pkg::AbstractBackend; kw...) = error("subplot($pkg; kw...) is not implemented") -# subplot!(pkg::AbstractBackend, subplt::Subplot; kw...) = error("subplot!($pkg, subplt; kw...) is not implemented") # don't do anything as a default _create_backend_figure(plt::Plot) = nothing +_initialize_subplot(plt::Plot, sp::Subplot) = nothing +_update_min_padding!(sp::Subplot) = nothing +_update_position!(sp::Subplot) = nothing _before_update(plt::Plot) = nothing -_series_added(plt::Plot) = nothing -# _add_annotations{X,Y,V}(plt::Plot, anns::AVec{Tuple{X,Y,V}}) = nothing -# _update_plot_pos_size(plt::AbstractPlot, d::KW) = nothing +_series_added(plt::Plot, series::Series) = nothing +_update_plot(plt::Plot, d::KW) = nothing +_series_updated(plt::Plot, series::Series) = nothing # --------------------------------------------------------- diff --git a/src/backends/bokeh.jl b/src/backends/bokeh.jl index 9ff99ad6..5d3c46db 100644 --- a/src/backends/bokeh.jl +++ b/src/backends/bokeh.jl @@ -37,7 +37,7 @@ supportedArgs(::BokehBackend) = [ # :show, :size, :title, - # :windowtitle, + # :window_title, :x, # :xguide, # :xlims, @@ -134,11 +134,11 @@ function _create_backend_figure(plt::Plot{BokehBackend}) datacolumns = Bokeh.BokehDataSet[] tools = Bokeh.tools() filename = tempname() * ".html" - title = plt.plotargs[:title] - w, h = plt.plotargs[:size] - xaxis_type = plt.plotargs[:xscale] == :log10 ? :log : :auto - yaxis_type = plt.plotargs[:yscale] == :log10 ? :log : :auto - # legend = plt.plotargs[:legend] ? xxxx : nothing + title = plt.attr[:title] + w, h = plt.attr[:size] + xaxis_type = plt.attr[:xscale] == :log10 ? :log : :auto + yaxis_type = plt.attr[:yscale] == :log10 ? :log : :auto + # legend = plt.attr[:legend] ? xxxx : nothing legend = nothing extra_args = KW() # TODO: we'll put extra settings (xlim, etc) here Bokeh.Plot(datacolumns, tools, filename, title, w, h, xaxis_type, yaxis_type, legend) #, extra_args) diff --git a/src/backends/gadfly.jl b/src/backends/gadfly.jl index 4c1790ed..359a724c 100644 --- a/src/backends/gadfly.jl +++ b/src/backends/gadfly.jl @@ -12,7 +12,7 @@ supportedArgs(::GadflyBackend) = [ :markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :fillrange, :fillcolor, :fillalpha, :bins, :n, :nc, :nr, :layout, :smooth, - :title, :windowtitle, :show, :size, + :title, :window_title, :show, :size, :x, :xguide, :xlims, :xticks, :xscale, :xflip, :y, :yguide, :ylims, :yticks, :yscale, :yflip, # :z, :zguide, :zlims, :zticks, :zscale, :zflip, @@ -190,7 +190,7 @@ function getMarkerGeom(d::KW) end end -function getGadflyMarkerTheme(d::KW, plotargs::KW) +function getGadflyMarkerTheme(d::KW, attr::KW) c = getColor(d[:markercolor]) α = d[:markeralpha] if α != nothing @@ -216,15 +216,15 @@ function getGadflyMarkerTheme(d::KW, plotargs::KW) end function addGadflyContColorScale(plt::Plot{GadflyBackend}, c) - plt.plotargs[:colorbar] == :none && return + plt.attr[:colorbar] == :none && return if !isa(c, ColorGradient) c = default_gradient() end push!(getGadflyContext(plt).scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(c, p)))) end -function addGadflyMarker!(plt::Plot, numlayers::Int, d::KW, plotargs::KW, geoms...) - gfargs = vcat(geoms..., getGadflyMarkerTheme(d, plotargs), getMarkerGeom(d)) +function addGadflyMarker!(plt::Plot, numlayers::Int, d::KW, attr::KW, geoms...) + gfargs = vcat(geoms..., getGadflyMarkerTheme(d, attr), getMarkerGeom(d)) kwargs = KW() # handle continuous color scales for the markers @@ -241,7 +241,7 @@ end # --------------------------------------------------------------------------- function addToGadflyLegend(plt::Plot, d::KW) - if plt.plotargs[:legend] != :none && d[:label] != "" + if plt.attr[:legend] != :none && d[:label] != "" gplt = getGadflyContext(plt) # add the legend if needed @@ -308,7 +308,7 @@ function addGadflySeries!(plt::Plot, d::KW) # markers if d[:markershape] != :none || st == :shape - prepend!(layers, addGadflyMarker!(plt, length(gplt.layers), d, plt.plotargs, smooth...)) + prepend!(layers, addGadflyMarker!(plt, length(gplt.layers), d, plt.attr, smooth...)) end st in (:hist2d, :hexbin, :contour) || addToGadflyLegend(plt, d) @@ -575,7 +575,7 @@ end # Plot(gplt, pkg, 0, d, KW[]) # end function _create_backend_figure(plt::Plot{GadflyBackend}) - createGadflyPlotObject(plt.plotargs) + createGadflyPlotObject(plt.attr) end @@ -674,8 +674,8 @@ getGadflyContext(plt::Plot{GadflyBackend}) = plt.o # end setGadflyDisplaySize(w,h) = Compose.set_default_graphic_size(w * Compose.px, h * Compose.px) -setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.plotargs[:size]...) -# setGadflyDisplaySize(subplt::Subplot) = setGadflyDisplaySize(getplotargs(subplt, 1)[:size]...) +setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.attr[:size]...) +# setGadflyDisplaySize(subplt::Subplot) = setGadflyDisplaySize(getattr(subplt, 1)[:size]...) # ------------------------------------------------------------------------- @@ -703,13 +703,13 @@ end function Base.display(::PlotsDisplay, plt::Plot{GadflyBackend}) - setGadflyDisplaySize(plt.plotargs[:size]...) + setGadflyDisplaySize(plt.attr[:size]...) display(plt.o) end # function Base.display(::PlotsDisplay, subplt::Subplot{GadflyBackend}) -# setGadflyDisplaySize(getplotargs(subplt,1)[:size]...) +# setGadflyDisplaySize(getattr(subplt,1)[:size]...) # ctx = buildGadflySubplotContext(subplt) # # # taken from Gadfly since I couldn't figure out how to do it directly diff --git a/src/backends/glvisualize.jl b/src/backends/glvisualize.jl index e654e373..965201d0 100644 --- a/src/backends/glvisualize.jl +++ b/src/backends/glvisualize.jl @@ -37,7 +37,7 @@ supportedArgs(::GLVisualizeBackend) = [ # :show, # :size, # :title, - # :windowtitle, + # :window_title, # :x, # :xguide, # :xlims, diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 263cd76e..f42e4634 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -19,7 +19,7 @@ supportedArgs(::GRBackend) = [ :bins, :n, :nc, :nr, :layout, :smooth, - :title, :windowtitle, :show, :size, + :title, :window_title, :show, :size, :x, :xguide, :xlims, :xticks, :xscale, :xflip, :y, :yguide, :ylims, :yticks, :yscale, :yflip, # :axis, :yrightlabel, @@ -194,7 +194,7 @@ end function gr_display(plt::Plot{GRBackend}, clear=true, update=true, subplot=[0, 1, 0, 1]) - d = plt.plotargs + d = plt.attr clear && GR.clearws() @@ -879,10 +879,10 @@ end # end function _add_annotations{X,Y,V}(plt::Plot{GRBackend}, anns::AVec{@compat(Tuple{X,Y,V})}) - if haskey(plt.plotargs, :anns) - append!(plt.plotargs[:anns], anns) + if haskey(plt.attr, :anns) + append!(plt.attr[:anns], anns) else - plt.plotargs[:anns] = anns + plt.attr[:anns] = anns end end @@ -893,7 +893,7 @@ end function _update_plot(plt::Plot{GRBackend}, d::KW) for k in (:title, :xguide, :yguide) - haskey(d, k) && (plt.plotargs[k] = d[k]) + haskey(d, k) && (plt.attr[k] = d[k]) end end diff --git a/src/backends/immerse.jl b/src/backends/immerse.jl index a1bab77b..42576158 100644 --- a/src/backends/immerse.jl +++ b/src/backends/immerse.jl @@ -21,7 +21,7 @@ end function createImmerseFigure(d::KW) w,h = d[:size] - figidx = Immerse.figure(; name = d[:windowtitle], width = w, height = h) + figidx = Immerse.figure(; name = d[:window_title], width = w, height = h) Immerse.Figure(figidx) end @@ -37,7 +37,7 @@ end # Plot((nothing,gplt), pkg, 0, d, KW[]) # end function _create_backend_figure(plt::Plot{ImmerseBackend}) - (nothing, createGadflyPlotObject(plt.plotargs)) + (nothing, createGadflyPlotObject(plt.attr)) end @@ -95,10 +95,10 @@ end # # function showSubplotObject(subplt::Subplot{ImmerseBackend}) # # create the Gtk window with vertical box vsep -# d = getplotargs(subplt,1) +# d = getattr(subplt,1) # w,h = d[:size] # vsep = Gtk.GtkBoxLeaf(:v) -# win = Gtk.GtkWindowLeaf(vsep, d[:windowtitle], w, h) +# win = Gtk.GtkWindowLeaf(vsep, d[:window_title], w, h) # # figindices = [] # row = Gtk.GtkBoxLeaf(:h) @@ -158,7 +158,7 @@ function Base.display(::PlotsDisplay, plt::Plot{ImmerseBackend}) fig, gplt = plt.o if fig == nothing - fig = createImmerseFigure(plt.plotargs) + fig = createImmerseFigure(plt.attr) Gtk.on_signal_destroy((x...) -> (Immerse.dropfig(Immerse._display, fig.figno); plt.o = (nothing,gplt)), fig.canvas) plt.o = (fig, gplt) end diff --git a/src/backends/pgfplots.jl b/src/backends/pgfplots.jl index 96a25299..fb351306 100644 --- a/src/backends/pgfplots.jl +++ b/src/backends/pgfplots.jl @@ -36,7 +36,7 @@ supportedArgs(::PGFPlotsBackend) = [ # :show, :size, :title, - # :windowtitle, + # :window_title, :x, :xguide, :xlims, @@ -246,10 +246,10 @@ end function _add_annotations{X,Y,V}(plt::Plot{PGFPlotsBackend}, anns::AVec{@compat(Tuple{X,Y,V})}) # set or add to the annotation_list - if haskey(plt.plotargs, :annotation_list) - append!(plt.plotargs[:annotation_list], anns) + if haskey(plt.attr, :annotation_list) + append!(plt.attr[:annotation_list], anns) else - plt.plotargs[:annotation_list] = anns + plt.attr[:annotation_list] = anns end end @@ -362,11 +362,11 @@ function _make_pgf_plot(plt::Plot{PGFPlotsBackend}) os = Any[] # We need to send the :legend KW to the axis for plt_series in plt.seriesargs - plt_series[:legend] = plt.plotargs[:legend] + plt_series[:legend] = plt.attr[:legend] push!(os, _pgfplots_axis(plt_series)) end - axisargs =_pgfplots_get_axis_kwargs(plt.plotargs) - w, h = map(px2mm, plt.plotargs[:size]) + axisargs =_pgfplots_get_axis_kwargs(plt.attr) + w, h = map(px2mm, plt.attr[:size]) plt.o = PGFPlots.Axis([os...]; width = "$w mm", height = "$h mm", axisargs...) end diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index 19cecc45..9c6e0a42 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -18,7 +18,7 @@ supportedArgs(::PlotlyBackend) = [ :bins, :n, :nc, :nr, :layout, # :smooth, - :title, :windowtitle, :show, :size, + :title, :window_title, :show, :size, :x, :xguide, :xlims, :xticks, :xscale, :xflip, :xrotation, :y, :yguide, :ylims, :yticks, :yscale, :yflip, :yrotation, :z, :zguide, :zlims, :zticks, :zscale, :zflip, :zrotation, @@ -97,26 +97,26 @@ end # plt # end -function _add_annotations{X,Y,V}(plt::Plot{PlotlyBackend}, anns::AVec{@compat(Tuple{X,Y,V})}) - # set or add to the annotation_list - if haskey(plt.plotargs, :annotation_list) - append!(plt.plotargs[:annotation_list], anns) - else - plt.plotargs[:annotation_list] = anns - end -end +# function _add_annotations{X,Y,V}(plt::Plot{PlotlyBackend}, anns::AVec{@compat(Tuple{X,Y,V})}) +# # set or add to the annotation_list +# if haskey(plt.attr, :annotation_list) +# append!(plt.attr[:annotation_list], anns) +# else +# plt.attr[:annotation_list] = anns +# end +# end # ---------------------------------------------------------------- -function _before_update_plot(plt::Plot{PlotlyBackend}) -end +# function _before_update_plot(plt::Plot{PlotlyBackend}) +# end +# +# # TODO: override this to update plot items (title, xlabel, etc) after creation +# function _update_plot(plt::Plot{PlotlyBackend}, d::KW) +# end -# TODO: override this to update plot items (title, xlabel, etc) after creation -function _update_plot(plt::Plot{PlotlyBackend}, d::KW) -end - -function _update_plot_pos_size(plt::AbstractPlot{PlotlyBackend}, d::KW) -end +# function _update_plot_pos_size(plt::AbstractPlot{PlotlyBackend}, d::KW) +# end # ---------------------------------------------------------------- @@ -140,41 +140,41 @@ end # true # end -function _expand_limits(lims, plt::Plot{PlotlyBackend}, isx::Bool) - # TODO: call expand limits for each plot data -end - -function _remove_axis(plt::Plot{PlotlyBackend}, isx::Bool) - # TODO: if plot is inner subplot, might need to remove ticks or axis labels -end +# function _expand_limits(lims, plt::Plot{PlotlyBackend}, isx::Bool) +# # TODO: call expand limits for each plot data +# end +# +# function _remove_axis(plt::Plot{PlotlyBackend}, isx::Bool) +# # TODO: if plot is inner subplot, might need to remove ticks or axis labels +# end # ---------------------------------------------------------------- function plotlyfont(font::Font, color = font.color) - KW( - :family => font.family, - :size => round(Int, font.pointsize*1.4), - :color => webcolor(color), + KW( + :family => font.family, + :size => round(Int, font.pointsize*1.4), + :color => webcolor(color), ) end function get_annotation_dict(x, y, val::Union{AbstractString,Symbol}) - KW( - :text => val, - :xref => "x", - :x => x, - :yref => "y", - :y => y, - :showarrow => false, + KW( + :text => val, + :xref => "x", + :x => x, + :yref => "y", + :y => y, + :showarrow => false, ) end function get_annotation_dict(x, y, ptxt::PlotText) - merge(get_annotation_dict(x, y, ptxt.str), KW( - :font => plotlyfont(ptxt.font), - :xanchor => ptxt.font.halign == :hcenter ? :center : ptxt.font.halign, - :yanchor => ptxt.font.valign == :vcenter ? :middle : ptxt.font.valign, - :rotation => ptxt.font.rotation, + merge(get_annotation_dict(x, y, ptxt.str), KW( + :font => plotlyfont(ptxt.font), + :xanchor => ptxt.font.halign == :hcenter ? :center : ptxt.font.halign, + :yanchor => ptxt.font.valign == :vcenter ? :middle : ptxt.font.valign, + :rotation => ptxt.font.rotation, )) end @@ -202,118 +202,133 @@ end # end function plotlyscale(scale::Symbol) - if scale == :log10 - "log" - else - "-" - end + if scale == :log10 + "log" + else + "-" + end end use_axis_field(ticks) = !(ticks in (nothing, :none)) -tickssym(letter) = symbol(letter * "ticks") -limssym(letter) = symbol(letter * "lims") -flipsym(letter) = symbol(letter * "flip") -scalesym(letter) = symbol(letter * "scale") -labelsym(letter) = symbol(letter * "label") -rotationsym(letter) = symbol(letter * "rotation") +# tickssym(letter) = symbol(letter * "ticks") +# limssym(letter) = symbol(letter * "lims") +# flipsym(letter) = symbol(letter * "flip") +# scalesym(letter) = symbol(letter * "scale") +# labelsym(letter) = symbol(letter * "label") +# rotationsym(letter) = symbol(letter * "rotation") -function plotlyaxis(d::KW, letter) - ax = KW( - :title => d[labelsym(letter)], - :showgrid => d[:grid], - :zeroline => false, +function plotlyaxis(axis::Axis, sp::Subplot{PlotlyBackend}) + letter = axis[:letter] + d = axis.d + ax = KW( + :title => d[:guide], + :showgrid => sp.attr[:grid], + :zeroline => false, ) - fgcolor = webcolor(d[:foreground_color]) - tsym = tickssym(letter) + # fgcolor = webcolor(d[:foreground_color]) + # tsym = tickssym(letter) - rot = d[rotationsym(letter)] - if rot != 0 - ax[:tickangle] = rot - end - - if use_axis_field(d[tsym]) - ax[:titlefont] = plotlyfont(d[:guidefont], fgcolor) - ax[:type] = plotlyscale(d[scalesym(letter)]) - ax[:tickfont] = plotlyfont(d[:tickfont], fgcolor) - ax[:tickcolor] = fgcolor - ax[:linecolor] = fgcolor - - # xlims - lims = d[limssym(letter)] - if lims != :auto && limsType(lims) == :limits - ax[:range] = lims + rot = d[:rotation] + if rot != 0 + ax[:tickangle] = rot end - # xflip - if d[flipsym(letter)] - ax[:autorange] = "reversed" - end + if use_axis_field(d[:ticks]) + ax[:titlefont] = plotlyfont(d[:guidefont], webcolor(d[:foreground_color_guide])) + ax[:type] = plotlyscale(d[:scale]) + ax[:tickfont] = plotlyfont(d[:tickfont], webcolor(d[:foreground_color_text])) + ax[:tickcolor] = webcolor(d[:foreground_color_border]) + ax[:linecolor] = webcolor(d[:foreground_color_border]) - # xticks - ticks = d[tsym] - if ticks != :auto - ttype = ticksType(ticks) - if ttype == :ticks - ax[:tickmode] = "array" - ax[:tickvals] = ticks - elseif ttype == :ticks_and_labels - ax[:tickmode] = "array" - ax[:tickvals], ax[:ticktext] = ticks - end + # lims + lims = d[:lims] + if lims != :auto && limsType(lims) == :limits + ax[:range] = lims + end + + # flip + if d[:flip] + ax[:autorange] = "reversed" + end + + # ticks + ticks = d[:ticks] + if ticks != :auto + ttype = ticksType(ticks) + if ttype == :ticks + ax[:tickmode] = "array" + ax[:tickvals] = ticks + elseif ttype == :ticks_and_labels + ax[:tickmode] = "array" + ax[:tickvals], ax[:ticktext] = ticks + end + end + else + ax[:showticklabels] = false + ax[:showgrid] = false end ax - else - ax[:showticklabels] = false - ax[:showgrid] = false - end - - ax end # function get_plot_json(plt::Plot{PlotlyBackend}) -# d = plt.plotargs -function plotly_layout(d::KW, seriesargs::AVec{KW}) +# d = plt.attr +# function plotly_layout(d::KW, seriesargs::AVec{KW}) +function plotly_layout(plt::Plot{PlotlyBackend}) d_out = KW() - d_out[:width], d_out[:height] = d[:size] + # for now, we only support 1 subplot + if length(plt.subplots) > 1 + warn("Subplots not supported yet") + end + sp = plt.subplots[1] - bgcolor = webcolor(d[:background_color]) - fgcolor = webcolor(d[:foreground_color]) + d_out[:width], d_out[:height] = plt.attr[:size] # set the fields for the plot - d_out[:title] = d[:title] - d_out[:titlefont] = plotlyfont(d[:guidefont], fgcolor) + d_out[:title] = sp.attr[:title] + d_out[:titlefont] = plotlyfont(sp.attr[:titlefont], webcolor(sp.attr[:foreground_color_title])) + + # TODO: use subplot positioning logic d_out[:margin] = KW(:l=>35, :b=>30, :r=>8, :t=>20) - d_out[:plot_bgcolor] = bgcolor - d_out[:paper_bgcolor] = bgcolor + + d_out[:plot_bgcolor] = webcolor(sp.attr[:background_color_inside]) + d_out[:paper_bgcolor] = webcolor(plt.attr[:background_color_outside]) # TODO: x/y axis tick values/labels - if any(is3d, seriesargs) + + # if any(is3d, seriesargs) + if is3d(sp) d_out[:scene] = KW( - :xaxis => plotlyaxis(d, "x"), - :yaxis => plotlyaxis(d, "y"), - :xzxis => plotlyaxis(d, "z"), + :xaxis => plotlyaxis(sp.attr[:xaxis], sp), + :yaxis => plotlyaxis(sp.attr[:yaxis], sp), + :xzxis => plotlyaxis(sp.attr[:zaxis], sp), ) else - d_out[:xaxis] = plotlyaxis(d, "x") - d_out[:yaxis] = plotlyaxis(d, "y") + d_out[:xaxis] = plotlyaxis(sp.attr[:xaxis], sp) + d_out[:yaxis] = plotlyaxis(sp.attr[:yaxis], sp) end # legend - d_out[:showlegend] = d[:legend] != :none - if d[:legend] != :none + d_out[:showlegend] = sp.attr[:legend] != :none + if sp.attr[:legend] != :none d_out[:legend] = KW( - :bgcolor => bgcolor, - :bordercolor => fgcolor, - :font => plotlyfont(d[:legendfont]), + :bgcolor => webcolor(sp.attr[:background_color_legend]), + :bordercolor => webcolor(sp.attr[:foreground_color_legend]), + :font => plotlyfont(sp.attr[:legendfont]), ) end + # if haskey(plt.attr, :annotation_list) + # append!(plt.attr[:annotation_list], anns) + # else + # plt.attr[:annotation_list] = anns + # end + # annotations - anns = get(d, :annotation_list, []) + anns = get(sp.attr, :annotations, []) d_out[:annotations] = if isempty(anns) KW[] else @@ -332,7 +347,7 @@ function plotly_layout(d::KW, seriesargs::AVec{KW}) # dumpdict(d_out,"",true) # @show d_out[:annotations] - if get(d, :polar, false) + if ispolar(sp) d_out[:direction] = "counterclockwise" end @@ -340,12 +355,12 @@ function plotly_layout(d::KW, seriesargs::AVec{KW}) end function get_plot_json(plt::Plot{PlotlyBackend}) - JSON.json(plotly_layout(plt.plotargs, plt.seriesargs)) + JSON.json(plotly_layout(plt)) end function plotly_colorscale(grad::ColorGradient, alpha = nothing) - [[grad.values[i], webcolor(grad.colors[i], alpha)] for i in 1:length(grad.colors)] + [[grad.values[i], webcolor(grad.colors[i], alpha)] for i in 1:length(grad.colors)] end plotly_colorscale(c, alpha = nothing) = plotly_colorscale(default_gradient(), alpha) @@ -357,196 +372,178 @@ const _plotly_markers = KW( :star5 => "star-triangle-up", :vline => "line-ns", :hline => "line-ew", - ) +) # get a dictionary representing the series params (d is the Plots-dict, d_out is the Plotly-dict) -function plotly_series(d::KW, plotargs::KW; plot_index = nothing) - # dumpdict(d,"series",true) - d_out = KW() +function plotly_series(plt::Plot{PlotlyBackend}, series::Series) + d = series.d + d_out = KW() - x, y = collect(d[:x]), collect(d[:y]) - d_out[:name] = d[:label] + x, y = collect(d[:x]), collect(d[:y]) + d_out[:name] = d[:label] - st = d[:seriestype] - isscatter = st in (:scatter, :scatter3d) - hasmarker = isscatter || d[:markershape] != :none - hasline = !isscatter + st = d[:seriestype] + isscatter = st in (:scatter, :scatter3d) + hasmarker = isscatter || d[:markershape] != :none + hasline = !isscatter - # set the "type" - if st in (:line, :path, :scatter, :steppre, :steppost) - d_out[:type] = "scatter" - d_out[:mode] = if hasmarker - hasline ? "lines+markers" : "markers" - else - hasline ? "lines" : "none" - end - if d[:fillrange] == true || d[:fillrange] == 0 - d_out[:fill] = "tozeroy" - d_out[:fillcolor] = webcolor(d[:fillcolor], d[:fillalpha]) - elseif !(d[:fillrange] in (false, nothing)) - warn("fillrange ignored... plotly only supports filling to zero. fillrange: $(d[:fillrange])") - end - d_out[:x], d_out[:y] = x, y - - elseif st == :bar - d_out[:type] = "bar" - d_out[:x], d_out[:y] = x, y - - elseif st == :hist2d - d_out[:type] = "histogram2d" - d_out[:x], d_out[:y] = x, y - if isa(d[:bins], Tuple) - xbins, ybins = d[:bins] - else - xbins = ybins = d[:bins] - end - d_out[:nbinsx] = xbins - d_out[:nbinsy] = ybins - - elseif st in (:hist, :density) - d_out[:type] = "histogram" - isvert = isvertical(d) - d_out[isvert ? :x : :y] = y - d_out[isvert ? :nbinsx : :nbinsy] = d[:bins] - if st == :density - d_out[:histnorm] = "probability density" - end - - elseif st == :heatmap - d_out[:type] = "heatmap" - d_out[:x], d_out[:y] = x, y - d_out[:z] = d[:z].surf - d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha]) - - elseif st == :contour - d_out[:type] = "contour" - d_out[:x], d_out[:y] = x, y - d_out[:z] = d[:z].surf - # d_out[:showscale] = d[:colorbar] != :none - d_out[:ncontours] = d[:levels] - d_out[:contours] = KW(:coloring => d[:fillrange] != nothing ? "fill" : "lines") - d_out[:colorscale] = plotly_colorscale(d[:linecolor], d[:linealpha]) - - elseif st in (:surface, :wireframe) - d_out[:type] = "surface" - d_out[:x], d_out[:y] = x, y - d_out[:z] = d[:z].surf - d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha]) - - elseif st == :pie - d_out[:type] = "pie" - d_out[:labels] = x - d_out[:values] = y - d_out[:hoverinfo] = "label+percent+name" - - elseif st in (:path3d, :scatter3d) - d_out[:type] = "scatter3d" - d_out[:mode] = if hasmarker - hasline ? "lines+markers" : "markers" - else - hasline ? "lines" : "none" - end - d_out[:x], d_out[:y] = x, y - d_out[:z] = collect(d[:z]) - - else - warn("Plotly: seriestype $st isn't supported.") - return KW() - end - - # add "marker" - if hasmarker - d_out[:marker] = KW( - :symbol => get(_plotly_markers, d[:markershape], string(d[:markershape])), - :opacity => d[:markeralpha], - :size => 2 * d[:markersize], - :color => webcolor(d[:markercolor], d[:markeralpha]), - :line => KW( - :color => webcolor(d[:markerstrokecolor], d[:markerstrokealpha]), - :width => d[:markerstrokewidth], - ), - ) - - # gotta hack this (for now?) since plotly can't handle rgba values inside the gradient - if d[:marker_z] != nothing - # d_out[:marker][:color] = d[:marker_z] - # d_out[:marker][:colorscale] = plotly_colorscale(d[:markercolor], d[:markeralpha]) - # d_out[:showscale] = true - grad = ColorGradient(d[:markercolor], alpha=d[:markeralpha]) - zmin, zmax = extrema(d[:marker_z]) - d_out[:marker][:color] = [webcolor(getColorZ(grad, (zi - zmin) / (zmax - zmin))) for zi in d[:marker_z]] - end - - end - - # add "line" - if hasline - d_out[:line] = KW( - :color => webcolor(d[:linecolor], d[:linealpha]), - :width => d[:linewidth], - :shape => if st == :steppre - "vh" - elseif st == :steppost - "hv" + # set the "type" + if st in (:line, :path, :scatter, :steppre, :steppost) + d_out[:type] = "scatter" + d_out[:mode] = if hasmarker + hasline ? "lines+markers" : "markers" else - "linear" - end, - :dash => string(d[:linestyle]), - # :dash => "solid", - ) - end + hasline ? "lines" : "none" + end + if d[:fillrange] == true || d[:fillrange] == 0 + d_out[:fill] = "tozeroy" + d_out[:fillcolor] = webcolor(d[:fillcolor], d[:fillalpha]) + elseif !(d[:fillrange] in (false, nothing)) + warn("fillrange ignored... plotly only supports filling to zero. fillrange: $(d[:fillrange])") + end + d_out[:x], d_out[:y] = x, y - # convert polar plots x/y to theta/radius - if get(plotargs, :polar, false) - d_out[:t] = rad2deg(pop!(d_out, :x)) - d_out[:r] = pop!(d_out, :y) - end + elseif st == :bar + d_out[:type] = "bar" + d_out[:x], d_out[:y] = x, y - # # for subplots, we need to add the xaxis/yaxis fields - # if plot_index != nothing - # d_out[:xaxis] = "x$(plot_index)" - # d_out[:yaxis] = "y$(plot_index)" - # end + elseif st == :hist2d + d_out[:type] = "histogram2d" + d_out[:x], d_out[:y] = x, y + if isa(d[:bins], Tuple) + xbins, ybins = d[:bins] + else + xbins = ybins = d[:bins] + end + d_out[:nbinsx] = xbins + d_out[:nbinsy] = ybins - d_out + elseif st in (:hist, :density) + d_out[:type] = "histogram" + isvert = isvertical(d) + d_out[isvert ? :x : :y] = y + d_out[isvert ? :nbinsx : :nbinsy] = d[:bins] + if st == :density + d_out[:histnorm] = "probability density" + end + + elseif st == :heatmap + d_out[:type] = "heatmap" + d_out[:x], d_out[:y] = x, y + d_out[:z] = d[:z].surf + d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha]) + + elseif st == :contour + d_out[:type] = "contour" + d_out[:x], d_out[:y] = x, y + d_out[:z] = d[:z].surf + # d_out[:showscale] = d[:colorbar] != :none + d_out[:ncontours] = d[:levels] + d_out[:contours] = KW(:coloring => d[:fillrange] != nothing ? "fill" : "lines") + d_out[:colorscale] = plotly_colorscale(d[:linecolor], d[:linealpha]) + + elseif st in (:surface, :wireframe) + d_out[:type] = "surface" + d_out[:x], d_out[:y] = x, y + d_out[:z] = d[:z].surf + d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha]) + + elseif st == :pie + d_out[:type] = "pie" + d_out[:labels] = x + d_out[:values] = y + d_out[:hoverinfo] = "label+percent+name" + + elseif st in (:path3d, :scatter3d) + d_out[:type] = "scatter3d" + d_out[:mode] = if hasmarker + hasline ? "lines+markers" : "markers" + else + hasline ? "lines" : "none" + end + d_out[:x], d_out[:y] = x, y + d_out[:z] = collect(d[:z]) + + else + warn("Plotly: seriestype $st isn't supported.") + return KW() + end + + # add "marker" + if hasmarker + d_out[:marker] = KW( + :symbol => get(_plotly_markers, d[:markershape], string(d[:markershape])), + :opacity => d[:markeralpha], + :size => 2 * d[:markersize], + :color => webcolor(d[:markercolor], d[:markeralpha]), + :line => KW( + :color => webcolor(d[:markerstrokecolor], d[:markerstrokealpha]), + :width => d[:markerstrokewidth], + ), + ) + + # gotta hack this (for now?) since plotly can't handle rgba values inside the gradient + if d[:marker_z] != nothing + # d_out[:marker][:color] = d[:marker_z] + # d_out[:marker][:colorscale] = plotly_colorscale(d[:markercolor], d[:markeralpha]) + # d_out[:showscale] = true + grad = ColorGradient(d[:markercolor], alpha=d[:markeralpha]) + zmin, zmax = extrema(d[:marker_z]) + d_out[:marker][:color] = [webcolor(getColorZ(grad, (zi - zmin) / (zmax - zmin))) for zi in d[:marker_z]] + end + end + + # add "line" + if hasline + d_out[:line] = KW( + :color => webcolor(d[:linecolor], d[:linealpha]), + :width => d[:linewidth], + :shape => if st == :steppre + "vh" + elseif st == :steppost + "hv" + else + "linear" + end, + :dash => string(d[:linestyle]), + # :dash => "solid", + ) + end + + # convert polar plots x/y to theta/radius + if ispolar(d[:subplot]) + d_out[:t] = rad2deg(pop!(d_out, :x)) + d_out[:r] = pop!(d_out, :y) + end + + d_out end # get a list of dictionaries, each representing the series params function get_series_json(plt::Plot{PlotlyBackend}) - JSON.json(map(d -> plotly_series(d, plt.plotargs), plt.seriesargs)) + JSON.json(map(series -> plotly_series(plt, series), plt.series_list)) end -# function get_series_json(subplt::Subplot{PlotlyBackend}) -# ds = KW[] -# for (i,plt) in enumerate(subplt.plts) -# for d in plt.seriesargs -# push!(ds, plotly_series(d, plt.plotargs, plot_index = i)) -# end -# end -# JSON.json(ds) -# end - # ---------------------------------------------------------------- function html_head(plt::AbstractPlot{PlotlyBackend}) - "" + "" end function html_body(plt::Plot{PlotlyBackend}, style = nothing) - if style == nothing - w, h = plt.plotargs[:size] - style = "width:$(w)px;height:$(h)px;" - end - uuid = Base.Random.uuid4() - html = """ -
- - """ - # @show html - html + if style == nothing + w, h = plt.attr[:size] + style = "width:$(w)px;height:$(h)px;" + end + uuid = Base.Random.uuid4() + html = """ + + + """ + html end function js_body(plt::Plot{PlotlyBackend}, uuid) @@ -557,31 +554,6 @@ function js_body(plt::Plot{PlotlyBackend}, uuid) end -# function html_body(subplt::Subplot{PlotlyBackend}) -# w, h = subplt.plts[1].plotargs[:size] -# html = ["