diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index 83861bef..45b7530d 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -19,7 +19,8 @@ supported_args(::PlotlyBackend) = [ :fillrange, :fillcolor, :fillalpha, :bins, :layout, - :title, :window_title, :show, :size, + :title, :title_location, :titlefont, + :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, @@ -33,7 +34,8 @@ supported_args(::PlotlyBackend) = [ # :overwrite_figure, :polar, :normalize, :weights, - # :contours, :aspect_ratio + # :contours, :aspect_ratio, + :hover, ] supported_types(::PlotlyBackend) = [ @@ -97,19 +99,19 @@ function plotly_font(font::Font, color = font.color) ) end -function plotly_annotation_dict(x, y, val) +function plotly_annotation_dict(x, y, val; xref="paper", yref="paper") KW( :text => val, - :xref => "x", + :xref => xref, :x => x, - :yref => "y", + :yref => xref, :y => y, :showarrow => false, ) end -function plotly_annotation_dict(x, y, ptxt::PlotText) - merge(plotly_annotation_dict(x, y, ptxt.str), KW( +function plotly_annotation_dict(x, y, ptxt::PlotText; xref="paper", yref="paper") + merge(plotly_annotation_dict(x, y, ptxt.str; xref=xref, yref=yref), KW( :font => plotly_font(ptxt.font), :xanchor => ptxt.font.halign == :hcenter ? :center : ptxt.font.halign, :yanchor => ptxt.font.valign == :vcenter ? :middle : ptxt.font.valign, @@ -148,6 +150,7 @@ function plotly_scale(scale::Symbol) end 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] @@ -225,20 +228,31 @@ function plotly_layout(plt::Plot) # end # sp = plt.subplots[1] - d_out[:width], d_out[:height] = plt[:size] + w, h = plt[:size] + d_out[:width], d_out[:height] = w, h d_out[:paper_bgcolor] = webcolor(plt[:background_color_outside]) + d_out[:margin] = KW(:l=>0, :b=>0, :r=>0, :t=>20) + + d_out[:annotations] = KW[] for sp in plt.subplots - sp_out = KW() spidx = plotly_subplot_index(sp) - # set the fields for the plot - d_out[:title] = sp[:title] - d_out[:titlefont] = plotly_font(sp[:titlefont], sp[:foreground_color_title]) - - # # TODO: use subplot positioning logic - # d_out[:margin] = KW(:l=>35, :b=>30, :r=>8, :t=>20) - d_out[:margin] = KW(:l=>0, :b=>0, :r=>0, :t=>30) + # TODO: add an annotation for the title + if sp[:title] != "" + bb = bbox(sp) + tpos = sp[:title_location] + xmm = if tpos == :left + left(bb) + elseif tpos == :right + right(bb) + else + 0.5 * (left(bb) + right(bb)) + end + titlex, titley = xy_mm_to_pcts(xmm, top(bb), w*px, h*px) + titlefont = font(sp[:titlefont], :top, sp[:foreground_color_title]) + push!(d_out[:annotations], plotly_annotation_dict(titlex, titley, text(sp[:title], titlefont))) + end d_out[:plot_bgcolor] = webcolor(sp[:background_color_inside]) @@ -267,7 +281,7 @@ function plotly_layout(plt::Plot) end # annotations - d_out[:annotations] = KW[plotly_annotation_dict(ann...) for ann in sp[:annotations]] + append!(d_out[:annotations], KW[plotly_annotation_dict(ann...; xref = "x$spidx", yref = "y$spidx") for ann in sp[:annotations]]) # # arrows # for sargs in seriesargs @@ -327,6 +341,7 @@ function plotly_series(plt::Plot, series::Series) spidx = plotly_subplot_index(sp) d_out[:xaxis] = "x$spidx" d_out[:yaxis] = "y$spidx" + d_out[:showlegend] = should_add_to_legend(series) x, y = collect(d[:x]), collect(d[:y]) d_out[:name] = d[:label] @@ -463,6 +478,12 @@ function plotly_series(plt::Plot, series::Series) d_out[:r] = pop!(d_out, :y) end + # hover text + if get(d, :hover, nothing) != nothing + d_out[:hoverinfo] = "text" + d_out[:text] = d[:hover] + end + d_out end diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index 365857d4..7144b468 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -22,7 +22,6 @@ supported_args(::PyPlotBackend) = [ :title, :window_title, :show, :size, :x, :xguide, :xlims, :xticks, :xscale, :xflip, :xrotation, :y, :yguide, :ylims, :yticks, :yscale, :yflip, :yrotation, - # :axis, :yrightlabel, :z, :zguide, :zlims, :zticks, :zscale, :zflip, :zrotation, :z, :tickfont, :guidefont, :legendfont, @@ -916,11 +915,17 @@ function py_set_ticks(ax, ticks, letter) end function py_compute_axis_minval(axis::Axis) + # compute the smallest absolute value for the log scale's linear threshold minval = 1.0 sp = axis.sp for series in series_list(axis.sp) minval = min(minval, minimum(abs(series.d[axis[:letter]]))) end + + # now if the axis limits go to a smaller abs value, use that instead + vmin, vmax = axis_limits(axis) + minval = min(minval, abs(vmin), abs(vmax)) + minval end diff --git a/src/components.jl b/src/components.jl index f6d21a3a..7b1a08eb 100644 --- a/src/components.jl +++ b/src/components.jl @@ -218,7 +218,14 @@ function font(args...) for arg in args T = typeof(arg) - if arg == :center + if T == Font + family = arg.family + pointsize = arg.pointsize + halign = arg.halign + valign = arg.valign + rotation = arg.rotation + color = arg.color + elseif arg == :center halign = :hcenter valign = :vcenter elseif arg in (:hcenter, :left, :right) @@ -253,6 +260,7 @@ end PlotText(str) = PlotText(string(str), font()) text(t::PlotText) = t +text(str::AbstractString, f::Font) = PlotText(str, f) function text(str, args...) PlotText(string(str), font(args...)) end diff --git a/src/layouts.jl b/src/layouts.jl index bdcb5755..1944f8fc 100644 --- a/src/layouts.jl +++ b/src/layouts.jl @@ -5,6 +5,8 @@ const px = AbsoluteLength(0.254) const pct = Length{:pct, Float64}(1.0) +to_pixels(m::AbsoluteLength) = m / 0.254 + const _cbar_width = 5mm @compat Base.:.*(m::Measure, n::Number) = m * n @@ -70,6 +72,16 @@ function crop(parent::BoundingBox, child::BoundingBox) BoundingBox(l, t, w, h) end +# convert x,y coordinates from absolute coords to percentages... +# returns x_pct, y_pct +function xy_mm_to_pcts(x::AbsoluteLength, y::AbsoluteLength, figw, figh, flipy = true) + xmm, ymm = x.value, y.value + if flipy + ymm = figh.value - ymm # flip y when origin in bottom-left + end + xmm / figw.value, ymm / figh.value +end + # convert a bounding box from absolute coords to percentages... # returns an array of percentages of figure size: [left, bottom, width, height] function bbox_to_pcts(bb::BoundingBox, figw, figh, flipy = true)