Merge branch 'master' into julia0.7

This commit is contained in:
Daniel Schwabeneder 2018-07-01 23:30:40 +02:00 committed by GitHub
commit a575ab7c74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 350 additions and 275 deletions

31
NEWS.md
View File

@ -3,13 +3,42 @@
#### notes on release changes, ongoing development, and future planned work
- All new development should target 0.15!
- Minor version 0.17 is the last one to support Julia 0.6!!
- Minor version 0.11 is the last one to support Julia 0.5!!
- Critical bugfixes only
- `backports` branch is for Julia 0.5
---
## (current master)
- All new development should target Julia 0.7!
## 0.17.3
- Log-scale heatmap edge computation
- Fix size and dpi for GR and PyPlot
- Fix fillrange with line segments on PyPlot and Plotly
- fix flip for heatmap and image on GR
- New attributes for PGFPlots
- Widen axes for most series types and log scales
- Plotly: fix log scale with no ticks
- Fix axis flip on Plotly
- Fix hover and zcolor interaction in Plotly
- WebIO integration for PlotlyJS backend
## 0.17.2
- fix single subplot in plotly
- implement `(xyz)lims = :round`
- PyPlot: fix bg_legend = invisible()
- set fallback tick specification for axes with discrete values
- restructure of show methods
## 0.17.1
- Fix contour for PGFPlots
- 32Bit fix: Int64 -> Int
- Make series of shapes and segments toggle together in Plotly(JS)
- Fix marker arguments
- Fix processing order of series recipes
- Fix Plotly(JS) ribbon
- Contour plots with x,y in grid form on PyPlot
## 0.17.0
- Add GR dependency to make it the default backend

View File

@ -65,6 +65,7 @@ const _arg_desc = KW(
:html_output_format => "Symbol. When writing html output, what is the format? `:png` and `:svg` are currently supported.",
:inset_subplots => "nothing or vector of 2-tuple (parent,bbox). optionally pass a vector of (parent,bbox) tuples which are the parent layout and the relative bounding box of inset subplots",
:dpi => "Number. Dots Per Inch of output figures",
:thickness_scaling => "Number. Scale for the thickness of all line elements like lines, borders, axes, grid lines, ... defaults to 1.",
:display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.",
:extra_kwargs => "KW (Dict{Symbol,Any}). Pass a map of extra keyword args which may be specific to a backend.",
:fontfamily => "String or Symbol. Default font family for title, legend entries, tick labels and guides",
@ -110,7 +111,7 @@ const _arg_desc = KW(
# axis args
:guide => "String. Axis guide (label).",
:lims => "NTuple{2,Number}. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example).",
:lims => "NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example). `:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0]",
:ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
:scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`",
:rotation => "Number. Degrees rotation of tick labels.",
@ -139,5 +140,6 @@ const _arg_desc = KW(
:gridstyle => "Symbol. Style of the grid lines. Choose from $(_allStyles)",
:gridlinewidth => "Number. Width of the grid lines (in pixels)",
:tick_direction => "Symbol. Direction of the ticks. `:in` or `:out`",
:showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`"
:showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`",
:widen => "Bool. Widen the axis limits by a small factor to avoid cut-off markers and lines at the borders. Defaults to `true`.",
)

View File

@ -301,6 +301,7 @@ const _plot_defaults = KW(
:inset_subplots => nothing, # optionally pass a vector of (parent,bbox) tuples which are
# the parent layout and the relative bounding box of inset subplots
:dpi => DPI, # dots per inch for images, etc
:thickness_scaling => 1,
:display_type => :auto,
:extra_kwargs => KW(),
)
@ -381,6 +382,7 @@ const _axis_defaults = KW(
:gridlinewidth => 0.5,
:tick_direction => :in,
:showaxis => true,
:widen => true,
)
const _suppress_warnings = Set{Symbol}([
@ -1473,26 +1475,19 @@ function _replace_linewidth(d::KW)
end
function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
pkg = plt.backend
globalIndex = d[:series_plotindex]
# add default values to our dictionary, being careful not to delete what we just added!
for (k,v) in _series_defaults
slice_arg!(d, d, k, v, commandIndex, false)
end
# this is how many series belong to this subplot
# plotIndex = count(series -> series.d[:subplot] === sp && series.d[:primary], plt.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
return d
end
function _update_series_attributes!(d::KW, plt::Plot, sp::Subplot)
pkg = plt.backend
globalIndex = d[:series_plotindex]
plotIndex = _series_index(d, sp)
aliasesAndAutopick(d, :linestyle, _styleAliases, supported_styles(pkg), plotIndex)
aliasesAndAutopick(d, :markershape, _markerAliases, supported_markers(pkg), plotIndex)
@ -1528,11 +1523,11 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
# update markerstrokecolor
d[:markerstrokecolor] = if d[:markerstrokecolor] == :match
plot_color(sp[:foreground_color_subplot], d[:markerstrokealpha])
plot_color(sp[:foreground_color_subplot])
elseif d[:markerstrokecolor] == :auto
getSeriesRGBColor(plot_color(d[:markercolor], d[:markeralpha]), sp, plotIndex)
getSeriesRGBColor.(d[:markercolor], sp, plotIndex)
else
getSeriesRGBColor(plot_color(d[:markerstrokecolor], d[:markerstrokealpha]), sp, plotIndex)
getSeriesRGBColor.(d[:markerstrokecolor], sp, plotIndex)
end
# if marker_z, fill_z or line_z are set, ensure we have a gradient
@ -1562,3 +1557,19 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
_replace_linewidth(d)
d
end
function _series_index(d, sp)
idx = 0
for series in series_list(sp)
if series[:primary]
idx += 1
end
if series == d
return idx
end
end
if get(d, :primary, true)
idx += 1
end
return idx
end

View File

@ -246,19 +246,17 @@ function get_ticks(axis::Axis)
ticks = ticks == :native ? :auto : ticks
dvals = axis[:discrete_values]
cv, dv = if !isempty(dvals)
# discrete ticks...
n = length(dvals)
rng = if ticks == :auto
Int[round(Int,i) for i in linspace(1, n, 15)]
elseif ticks == :all
1:n
elseif typeof(ticks) <: Int
Int[round(Int,i) for i in linspace(1, n, ticks)]
end
axis[:continuous_values][rng], dvals[rng]
elseif typeof(ticks) <: Symbol
if ispolar(axis.sps[1]) && axis[:letter] == :x
cv, dv = if typeof(ticks) <: Symbol
if !isempty(dvals)
# discrete ticks...
n = length(dvals)
rng = if ticks == :auto
Int[round(Int,i) for i in linspace(1, n, 15)]
else # if ticks == :all
1:n
end
axis[:continuous_values][rng], dvals[rng]
elseif ispolar(axis.sps[1]) && axis[:letter] == :x
#force theta axis to be full circle
(collect(0:pi/4:7pi/4), string.(0:45:315))
else
@ -266,8 +264,13 @@ function get_ticks(axis::Axis)
optimal_ticks_and_labels(axis)
end
elseif typeof(ticks) <: Union{AVec, Int}
# override ticks, but get the labels
optimal_ticks_and_labels(axis, ticks)
if !isempty(dvals) && typeof(ticks) <: Int
rng = Int[round(Int,i) for i in linspace(1, length(dvals), ticks)]
axis[:continuous_values][rng], dvals[rng]
else
# override ticks, but get the labels
optimal_ticks_and_labels(axis, ticks)
end
elseif typeof(ticks) <: NTuple{2, Any}
# assuming we're passed (ticks, labels)
ticks
@ -415,21 +418,23 @@ end
# -------------------------------------------------------------------------
# push the limits out slightly
function widen(lmin, lmax)
span = lmax - lmin
function widen(lmin, lmax, scale = :identity)
f, invf = scalefunc(scale), invscalefunc(scale)
span = f(lmax) - f(lmin)
# eps = NaNMath.max(1e-16, min(1e-2span, 1e-10))
eps = NaNMath.max(1e-16, 0.03span)
lmin-eps, lmax+eps
invf(f(lmin)-eps), invf(f(lmax)+eps)
end
# figure out if widening is a good idea. if there's a scale set it's too tricky,
# so lazy out and don't widen
# figure out if widening is a good idea.
const _widen_seriestypes = (:line, :path, :steppre, :steppost, :sticks, :scatter, :barbins, :barhist, :histogram, :scatterbins, :scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :bar, :shape, :path3d, :scatter3d)
function default_should_widen(axis::Axis)
should_widen = false
if axis[:scale] == :identity && !is_2tuple(axis[:lims])
if !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
if series.d[:seriestype] in _widen_seriestypes
should_widen = true
end
end
@ -438,6 +443,13 @@ function default_should_widen(axis::Axis)
should_widen
end
function round_limits(amin,amax)
scale = 10^(1-round(log10(amax - amin)))
amin = floor(amin*scale)/scale
amax = ceil(amax*scale)/scale
amin, amax
end
# using the axis extrema and limit overrides, return the min/max value for this axis
function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis))
ex = axis[:extrema]
@ -466,8 +478,10 @@ function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis)
else
amin, amax
end
elseif should_widen
widen(amin, amax)
elseif should_widen && axis[:widen]
widen(amin, amax, axis[:scale])
elseif lims == :round
round_limits(amin,amax)
else
amin, amax
end

View File

@ -353,25 +353,18 @@ function gr_draw_markers(series::Series, x, y, msize, mz)
msi = _cycle(msize, i)
shape = _cycle(shapes, i)
cfunc = isa(shape, Shape) ? gr_set_fillcolor : gr_set_markercolor
cfuncind = isa(shape, Shape) ? GR.setfillcolorind : GR.setmarkercolorind
# draw a filled in shape, slightly bigger, to estimate a stroke
if series[:markerstrokewidth] > 0
cfunc(_cycle(series[:markerstrokecolor], i)) #, series[:markerstrokealpha])
cfunc(get_markerstrokecolor(series, i))
gr_set_transparency(get_markerstrokealpha(series, i))
gr_draw_marker(x[i], y[i], msi + series[:markerstrokewidth], shape)
end
# draw the shape
if mz == nothing
cfunc(_cycle(series[:markercolor], i)) #, series[:markeralpha])
else
# pick a color from the pre-loaded gradient
ci = round(Int, 1000 + _cycle(mz, i) * 255)
cfuncind(ci)
gr_set_transparency(_gr_gradient_alpha[ci-999])
end
# don't draw filled area if marker shape is 1D
# draw the shape - don't draw filled area if marker shape is 1D
if !(shape in (:hline, :vline, :+, :x))
cfunc(get_markercolor(series, i))
gr_set_transparency(get_markeralpha(series, i))
gr_draw_marker(x[i], y[i], msi, shape)
end
end
@ -390,7 +383,7 @@ end
function gr_set_line(lw, style, c) #, a)
GR.setlinetype(gr_linetype[style])
w, h = gr_plot_size
GR.setlinewidth(max(0, lw / ((w + h) * 0.001)))
GR.setlinewidth(_gr_thickness_scaling[1] * max(0, lw / ((w + h) * 0.001)))
gr_set_linecolor(c) #, a)
end
@ -403,6 +396,7 @@ end
# this stores the conversion from a font pointsize to "percentage of window height" (which is what GR uses)
const _gr_point_mult = 0.0018 * ones(1)
const _gr_thickness_scaling = ones(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,
@ -549,6 +543,9 @@ end
function gr_display(plt::Plot, fmt="")
GR.clearws()
_gr_thickness_scaling[1] = plt[:thickness_scaling]
dpi_factor = plt[:dpi] / Plots.DPI
# collect some monitor/display sizes in meters and pixels
display_width_meters, display_height_meters, display_width_px, display_height_px = GR.inqdspsize()
display_width_ratio = display_width_meters / display_width_px
@ -557,14 +554,6 @@ function gr_display(plt::Plot, fmt="")
# compute the viewport_canvas, normalized to the larger dimension
viewport_canvas = Float64[0,1,0,1]
w, h = plt[:size]
if !haskey(ENV, "PLOTS_TEST")
dpi_factor = plt[:dpi] / DPI
if fmt == "png"
dpi_factor *= 6
end
else
dpi_factor = 1
end
gr_plot_size[:] = [w, h]
if w > h
ratio = float(h) / w
@ -587,7 +576,7 @@ function gr_display(plt::Plot, fmt="")
# update point mult
px_per_pt = px / pt
_gr_point_mult[1] = 1.5 * px_per_pt / max(h,w)
_gr_point_mult[1] = 1.5 * _gr_thickness_scaling[1] * px_per_pt / max(h,w)
# subplots:
for sp in plt.subplots
@ -633,13 +622,14 @@ function gr_get_ticks_size(ticks, i)
end
function _update_min_padding!(sp::Subplot{GRBackend})
dpi = sp.plt[:thickness_scaling]
if !haskey(ENV, "GKSwstype")
if isijulia() || (isdefined(Main, :Juno) && Juno.isactive())
ENV["GKSwstype"] = "svg"
end
end
# Add margin given by the user
leftpad = 2mm + sp[:left_margin]
leftpad = 4mm + sp[:left_margin]
toppad = 2mm + sp[:top_margin]
rightpad = 4mm + sp[:right_margin]
bottompad = 2mm + sp[:bottom_margin]
@ -675,7 +665,7 @@ function _update_min_padding!(sp::Subplot{GRBackend})
if sp[:yaxis][:guide] != ""
leftpad += 4mm
end
sp.minpad = (leftpad, toppad, rightpad, bottompad)
sp.minpad = Tuple(dpi * [leftpad, toppad, rightpad, bottompad])
end
function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
@ -725,6 +715,12 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
end
if st == :heatmap
outside_ticks = true
for ax in (sp[:xaxis], sp[:yaxis])
v = series[ax[:letter]]
if diff(collect(extrema(diff(v))))[1] > 1e-6*std(v)
warn("GR: heatmap only supported with equally spaced data.")
end
end
x, y = heatmap_edges(series[:x], sp[:xaxis][:scale]), heatmap_edges(series[:y], sp[:yaxis][:scale])
xy_lims = x[1], x[end], y[1], y[end]
expand_extrema!(sp[:xaxis], x)
@ -776,7 +772,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# draw the axes
gr_set_font(tickfont(xaxis))
GR.setlinewidth(1)
GR.setlinewidth(sp.plt[:thickness_scaling])
if is3d(sp)
zmin, zmax = gr_lims(zaxis, true)
@ -1046,10 +1042,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
end
if series[:markershape] != :none
if series[:marker_z] != nothing
zmin, zmax = extrema(series[:marker_z])
GR.setspace(zmin, zmax, 0, 90)
end
gr_draw_markers(series, x, y, clims)
end
@ -1100,6 +1092,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
elseif st == :heatmap
xmin, xmax, ymin, ymax = xy_lims
zmin, zmax = clims
m, n = length(x), length(y)
xinds = sort(1:m, rev = xaxis[:flip])
yinds = sort(1:n, rev = yaxis[:flip])
z = reshape(reshape(z, m, n)[xinds, yinds], m*n)
GR.setspace(zmin, zmax, 0, 90)
grad = isa(series[:fillcolor], ColorGradient) ? series[:fillcolor] : cgrad()
colors = [plot_color(grad[clamp((zi-zmin) / (zmax-zmin), 0, 1)], series[:fillalpha]) for zi=z]
@ -1203,7 +1199,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
elseif st == :image
z = transpose_z(series, series[:z].surf, true)'
w, h = size(z)
w, h = length(x), length(y)
xinds = sort(1:w, rev = xaxis[:flip])
yinds = sort(1:h, rev = yaxis[:flip])
z = z[xinds, yinds]
xmin, xmax = ignorenan_extrema(series[:x]); ymin, ymax = ignorenan_extrema(series[:y])
if eltype(z) <: Colors.AbstractGray
grey = round.(UInt8, float(z) * 255)

View File

@ -240,10 +240,6 @@ end
# ----------------------------------------------------------------
_show(io::IO, mime::MIME"text/plain", plt::Plot{HDF5Backend}) = nothing #Don't show
# ----------------------------------------------------------------
# Display/show the plot (open a GUI window, or browser page, for example).
function _display(plt::Plot{HDF5Backend})
msg = "HDF5 interface does not support `display()` function."

View File

@ -523,7 +523,6 @@ for (mime, fmt) in _inspectdr_mimeformats_nodpi
_inspectdr_show(io, mime, _inspectdr_getmplot(plt.o), plt[:size]...)
end
end
_show(io::IO, mime::MIME"text/plain", plt::Plot{InspectDRBackend}) = nothing #Don't show
# ----------------------------------------------------------------

View File

@ -8,11 +8,12 @@ end
const _pgfplots_attr = merge_with_base_supported([
:annotations,
# :background_color_legend,
:background_color_legend,
:background_color_inside,
# :background_color_outside,
# :foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
# :foreground_color_text, :foreground_color_border,
# :foreground_color_legend,
:foreground_color_grid, :foreground_color_axis,
:foreground_color_text, :foreground_color_border,
:label,
:seriescolor, :seriesalpha,
:linecolor, :linestyle, :linewidth, :linealpha,
@ -149,6 +150,10 @@ function pgf_colormap(grad::ColorGradient)
end,", ")
end
pgf_thickness_scaling(plt::Plot) = plt[:thickness_scaling]
pgf_thickness_scaling(sp::Subplot) = pgf_thickness_scaling(sp.plt)
pgf_thickness_scaling(series) = pgf_thickness_scaling(series[:subplot])
function pgf_fillstyle(d, i = 1)
cstr,a = pgf_color(get_fillcolor(d, i))
fa = get_fillalpha(d, i)
@ -158,52 +163,56 @@ function pgf_fillstyle(d, i = 1)
"fill = $cstr, fill opacity=$a"
end
function pgf_linestyle(d, i = 1)
cstr,a = pgf_color(get_linecolor(d, i))
la = get_linealpha(d, i)
if la != nothing
a = la
end
function pgf_linestyle(linewidth::Real, color, α = 1, linestyle = "solid")
cstr, a = pgf_color(plot_color(color, α))
"""
color = $cstr,
draw opacity=$a,
line width=$(get_linewidth(d, i)),
$(get(_pgfplots_linestyles, get_linestyle(d, i), "solid"))"""
draw opacity = $a,
line width = $linewidth,
$(get(_pgfplots_linestyles, linestyle, "solid"))"""
end
function pgf_linestyle(d, i = 1)
lw = pgf_thickness_scaling(d) * get_linewidth(d, i)
lc = get_linecolor(d, i)
la = get_linealpha(d, i)
ls = get_linestyle(d, i)
return pgf_linestyle(lw, lc, la, ls)
end
function pgf_font(fontsize, thickness_scaling = 1, font = "\\selectfont")
fs = fontsize * thickness_scaling
return string("{\\fontsize{", fs, " pt}{", 1.3fs, " pt}", font, "}")
end
function pgf_marker(d, i = 1)
shape = _cycle(d[:markershape], i)
cstr, a = pgf_color(_cycle(d[:markercolor], i))
if d[:markeralpha] != nothing
a = _cycle(d[:markeralpha], i)
end
cstr_stroke, a_stroke = pgf_color(_cycle(d[:markerstrokecolor], i))
if d[:markerstrokealpha] != nothing
a_stroke = _cycle(d[:markerstrokealpha], i)
end
cstr, a = pgf_color(plot_color(get_markercolor(d, i), get_markeralpha(d, i)))
cstr_stroke, a_stroke = pgf_color(plot_color(get_markerstrokecolor(d, i), get_markerstrokealpha(d, i)))
"""
mark = $(get(_pgfplots_markers, shape, "*")),
mark size = $(0.5 * _cycle(d[:markersize], i)),
mark size = $(pgf_thickness_scaling(d) * 0.5 * _cycle(d[:markersize], i)),
mark options = {
color = $cstr_stroke, draw opacity = $a_stroke,
fill = $cstr, fill opacity = $a,
line width = $(_cycle(d[:markerstrokewidth], i)),
line width = $(pgf_thickness_scaling(d) * _cycle(d[:markerstrokewidth], i)),
rotate = $(shape == :dtriangle ? 180 : 0),
$(get(_pgfplots_linestyles, _cycle(d[:markerstrokestyle], i), "solid"))
}"""
end
function pgf_add_annotation!(o,x,y,val)
function pgf_add_annotation!(o, x, y, val, thickness_scaling = 1)
# Construct the style string.
# Currently supports color and orientation
cstr,a = pgf_color(val.font.color)
push!(o, PGFPlots.Plots.Node(val.str, # Annotation Text
x, y,
style="""
$(get(_pgf_annotation_halign,val.font.halign,"")),
color=$cstr, draw opacity=$(convert(Float16,a)),
rotate=$(val.font.rotation)
"""))
x, y,
style="""
$(get(_pgf_annotation_halign,val.font.halign,"")),
color=$cstr, draw opacity=$(convert(Float16,a)),
rotate=$(val.font.rotation),
font=$(pgf_font(val.font.pointsize, thickness_scaling))
"""))
end
# --------------------------------------------------------------------------------------
@ -222,10 +231,6 @@ function pgf_series(sp::Subplot, series::Series)
straightline_data(series)
elseif st == :shape
shape_data(series)
elseif d[:marker_z] != nothing
# If a marker_z is used pass it as third coordinate to a 2D plot.
# See "Scatter Plots" in PGFPlots documentation
d[:x], d[:y], d[:marker_z]
elseif ispolar(sp)
theta, r = filter_radial_data(d[:x], d[:y], axis_limits(sp[:yaxis]))
rad2deg.(theta), r
@ -380,8 +385,9 @@ function pgf_axis(sp::Subplot, letter)
# axis guide
kw[Symbol(letter,:label)] = axis[:guide]
# Add ticklabel rotations
push!(style, "$(letter)ticklabel style={rotate = $(axis[:rotation])}")
# Add label font
cstr, α = pgf_color(plot_color(axis[:guidefontcolor]))
push!(style, string(letter, "label style = {font = ", pgf_font(axis[:guidefontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", axis[:guidefontrotation], "}"))
# flip/reverse?
axis[:flip] && push!(style, "$letter dir=reverse")
@ -437,6 +443,9 @@ function pgf_axis(sp::Subplot, letter)
push!(style, string(letter, "ticklabels = {}"))
end
push!(style, string(letter, "tick align = ", (axis[:tick_direction] == :out ? "outside" : "inside")))
cstr, α = pgf_color(plot_color(axis[:tickfontcolor]))
push!(style, string(letter, "ticklabel style = {font = ", pgf_font(axis[:tickfontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", axis[:tickfontrotation], "}"))
push!(style, string(letter, " grid style = {", pgf_linestyle(pgf_thickness_scaling(sp) * axis[:gridlinewidth], axis[:foreground_color_grid], axis[:gridalpha], axis[:gridstyle]), "}"))
end
# framestyle
@ -449,7 +458,7 @@ function pgf_axis(sp::Subplot, letter)
if framestyle == :zerolines
push!(style, string("extra ", letter, " ticks = 0"))
push!(style, string("extra ", letter, " tick labels = "))
push!(style, string("extra ", letter, " tick style = {grid = major, major grid style = {color = black, draw opacity=1.0, line width=0.5), solid}}"))
push!(style, string("extra ", letter, " tick style = {grid = major, major grid style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_axis], 1.0), "}}"))
end
if !axis[:showaxis]
@ -457,6 +466,8 @@ function pgf_axis(sp::Subplot, letter)
end
if !axis[:showaxis] || framestyle in (:zerolines, :grid, :none)
push!(style, string(letter, " axis line style = {draw opacity = 0}"))
else
push!(style, string(letter, " axis line style = {", pgf_linestyle(pgf_thickness_scaling(sp), axis[:foreground_color_axis], 1.0), "}"))
end
# return the style list and KW args
@ -501,6 +512,8 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
if sp[:title] != ""
kw[:title] = "$(sp[:title])"
cstr, α = pgf_color(plot_color(sp[:titlefontcolor]))
push!(style, string("title style = {font = ", pgf_font(sp[:titlefontsize], pgf_thickness_scaling(sp)), ", color = ", cstr, ", draw opacity = ", α, ", rotate = ", sp[:titlefontrotation], "}"))
end
if sp[:aspect_ratio] in (1, :equal)
@ -511,6 +524,8 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
if haskey(_pgfplots_legend_pos, legpos)
kw[:legendPos] = _pgfplots_legend_pos[legpos]
end
cstr, a = pgf_color(plot_color(sp[:background_color_legend]))
push!(style, string("legend style = {", pgf_linestyle(pgf_thickness_scaling(sp), sp[:foreground_color_legend], 1.0, "solid"), ",", "fill = $cstr,", "font = ", pgf_font(sp[:legendfontsize], pgf_thickness_scaling(sp)), "}"))
if any(s[:seriestype] == :contour for s in series_list(sp))
kw[:view] = "{0}{90}"
@ -564,13 +579,13 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
# add series annotations
anns = series[:series_annotations]
for (xi,yi,str,fnt) in EachAnn(anns, series[:x], series[:y])
pgf_add_annotation!(o, xi, yi, PlotText(str, fnt))
pgf_add_annotation!(o, xi, yi, PlotText(str, fnt), pgf_thickness_scaling(series))
end
end
# add the annotations
for ann in sp[:annotations]
pgf_add_annotation!(o, locate_annotation(sp, ann...)...)
pgf_add_annotation!(o, locate_annotation(sp, ann...)..., pgf_thickness_scaling(sp))
end

View File

@ -263,6 +263,7 @@ function plotly_axis(plt::Plot, axis::Axis, sp::Subplot)
end
ax[:tickangle] = -axis[:rotation]
ax[:type] = plotly_scale(axis[:scale])
lims = axis_limits(axis)
if axis[:ticks] != :native || axis[:lims] != :auto
@ -271,14 +272,13 @@ function plotly_axis(plt::Plot, axis::Axis, sp::Subplot)
if !(axis[:ticks] in (nothing, :none, false))
ax[:titlefont] = plotly_font(guidefont(axis))
ax[:type] = plotly_scale(axis[:scale])
ax[:tickfont] = plotly_font(tickfont(axis))
ax[:tickcolor] = framestyle in (:zerolines, :grid) || !axis[:showaxis] ? rgba_string(invisible()) : rgb_string(axis[:foreground_color_axis])
ax[:linecolor] = rgba_string(axis[:foreground_color_axis])
# flip
if axis[:flip]
ax[:autorange] = "reversed"
ax[:range] = reverse(ax[:range])
end
# ticks
@ -328,9 +328,11 @@ function plotly_layout(plt::Plot)
d_out[:annotations] = KW[]
multiple_subplots = length(plt.subplots) > 1
for sp in plt.subplots
spidx = sp[:subplot_index]
x_idx, y_idx = plotly_link_indicies(plt, sp)
spidx = multiple_subplots ? sp[:subplot_index] : ""
x_idx, y_idx = multiple_subplots ? plotly_link_indicies(plt, 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] != ""
@ -388,6 +390,7 @@ function plotly_layout(plt::Plot)
:bgcolor => rgba_string(sp[:background_color_legend]),
:bordercolor => rgba_string(sp[:foreground_color_legend]),
:font => plotly_font(legendfont(sp)),
:tracegroupgap => 0,
:x => xpos,
:y => ypos
)
@ -584,6 +587,8 @@ function plotly_series(plt::Plot, series::Series)
return plotly_series_segments(series, d_out, x, y, z)
elseif st == :heatmap
x = heatmap_edges(x, sp[:xaxis][:scale])
y = heatmap_edges(y, sp[:yaxis][:scale])
d_out[:type] = "heatmap"
d_out[:x], d_out[:y], d_out[:z] = x, y, z
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
@ -632,31 +637,17 @@ function plotly_series(plt::Plot, series::Series)
# add "marker"
if hasmarker
inds = eachindex(x)
d_out[:marker] = KW(
:symbol => get(_plotly_markers, series[:markershape], string(series[:markershape])),
# :opacity => series[:markeralpha],
:size => 2 * series[:markersize],
# :color => rgba_string(series[:markercolor]),
:size => 2 * _cycle(series[:markersize], inds),
:color => rgba_string.(plot_color.(get_markercolor.(series, inds), get_markeralpha.(series, inds))),
:line => KW(
:color => _cycle(rgba_string.(series[:markerstrokecolor]),eachindex(series[:x])),
:width => series[:markerstrokewidth],
:color => rgba_string.(plot_color.(get_markerstrokecolor.(series, inds), get_markerstrokealpha.(series, inds))),
:width => _cycle(series[:markerstrokewidth], inds),
),
)
# gotta hack this (for now?) since plotly can't handle rgba values inside the gradient
if series[:marker_z] == nothing
d_out[:marker][:color] = _cycle(rgba_string.(series[:markercolor]),eachindex(series[:x]))
else
# grad = ColorGradient(series[:markercolor], alpha=series[:markeralpha])
# grad = as_gradient(series[:markercolor], series[:markeralpha])
cmin, cmax = get_clims(sp)
# zrange = zmax == zmin ? 1 : zmax - zmin # if all marker_z values are the same, plot all markers same color (avoids division by zero in next line)
d_out[:marker][:color] = [clamp(zi, cmin, cmax) for zi in series[:marker_z]]
d_out[:marker][:cmin] = cmin
d_out[:marker][:cmax] = cmax
d_out[:marker][:colorscale] = plotly_colorscale(series[:markercolor], series[:markeralpha])
d_out[:marker][:showscale] = hascolorbar(sp)
end
end
plotly_polar!(d_out, series)
@ -674,11 +665,12 @@ function plotly_series_shapes(plt::Plot, series::Series)
# these are the axes that the series should be mapped to
x_idx, y_idx = plotly_link_indicies(plt, series[:subplot])
base_d = KW()
base_d[:xaxis] = "x$(x_idx)"
base_d[:yaxis] = "y$(y_idx)"
base_d[:name] = series[:label]
# base_d[:legendgroup] = series[:label]
d_base = KW(
:xaxis => "x$(x_idx)",
:yaxis => "y$(y_idx)",
:name => series[:label],
:legendgroup => series[:label],
)
x, y = (plotly_data(series, letter, data)
for (letter, data) in zip((:x, :y), shape_data(series))
@ -688,7 +680,7 @@ function plotly_series_shapes(plt::Plot, series::Series)
length(rng) < 2 && continue
# to draw polygons, we actually draw lines with fill
d_out = merge(base_d, KW(
d_out = merge(d_base, KW(
:type => "scatter",
:mode => "lines",
:x => vcat(x[rng], x[rng[1]]),
@ -709,9 +701,11 @@ function plotly_series_shapes(plt::Plot, series::Series)
d_outs[i] = d_out
end
if series[:fill_z] != nothing
push!(d_outs, plotly_colorbar_hack(series, base_d, :fill))
push!(d_outs, plotly_colorbar_hack(series, d_base, :fill))
elseif series[:line_z] != nothing
push!(d_outs, plotly_colorbar_hack(series, base_d, :line))
push!(d_outs, plotly_colorbar_hack(series, d_base, :line))
elseif series[:marker_z] != nothing
push!(d_outs, plotly_colorbar_hack(series, d_base, :marker))
end
d_outs
end
@ -729,10 +723,11 @@ function plotly_series_segments(series::Series, d_base::KW, x, y, z)
d_outs = Vector{KW}((hasfillrange ? 2 : 1 ) * length(segments))
for (i,rng) in enumerate(segments)
length(rng) < 2 && continue
!isscatter && length(rng) < 2 && continue
d_out = deepcopy(d_base)
d_out[:showlegend] = i==1 ? should_add_to_legend(series) : false
d_out[:legendgroup] = series[:label]
# set the type
if st in (:path, :scatter, :scattergl, :straightline)
@ -766,30 +761,15 @@ function plotly_series_segments(series::Series, d_base::KW, x, y, z)
# add "marker"
if hasmarker
d_out[:marker] = KW(
:symbol => get(_plotly_markers, series[:markershape], string(series[:markershape])),
:symbol => get(_plotly_markers, _cycle(series[:markershape], i), string(_cycle(series[:markershape], i))),
# :opacity => series[:markeralpha],
:size => 2 * series[:markersize],
# :color => rgba_string(series[:markercolor]),
:size => 2 * _cycle(series[:markersize], i),
:color => rgba_string(plot_color(get_markercolor(series, i), get_markeralpha(series, i))),
:line => KW(
:color => _cycle(rgba_string.(series[:markerstrokecolor]), eachindex(rng)),
:width => series[:markerstrokewidth],
:color => rgba_string(plot_color(get_markerstrokecolor(series, i), get_markerstrokealpha(series, i))),
:width => _cycle(series[:markerstrokewidth], i),
),
)
# gotta hack this (for now?) since plotly can't handle rgba values inside the gradient
if series[:marker_z] == nothing
d_out[:marker][:color] = _cycle(rgba_string.(series[:markercolor]), eachindex(rng))
else
# grad = ColorGradient(series[:markercolor], alpha=series[:markeralpha])
# grad = as_gradient(series[:markercolor], series[:markeralpha])
cmin, cmax = get_clims(sp)
# zrange = zmax == zmin ? 1 : zmax - zmin # if all marker_z values are the same, plot all markers same color (avoids division by zero in next line)
d_out[:marker][:color] = [clamp(zi, cmin, cmax) for zi in _cycle(series[:marker_z], rng)]
d_out[:marker][:cmin] = cmin
d_out[:marker][:cmax] = cmax
d_out[:marker][:colorscale] = plotly_colorscale(series[:markercolor], series[:markeralpha])
d_out[:marker][:showscale] = hascolorbar(sp)
end
end
# add "line"
@ -809,7 +789,7 @@ function plotly_series_segments(series::Series, d_base::KW, x, y, z)
end
plotly_polar!(d_out, series)
plotly_hover!(d_out, series[:hover])
plotly_hover!(d_out, _cycle(series[:hover], rng))
if hasfillrange
# if hasfillrange is true, return two dictionaries (one for original
@ -825,14 +805,14 @@ function plotly_series_segments(series::Series, d_base::KW, x, y, z)
series[:fillrange] = (f1, f2)
end
if isa(series[:fillrange], AbstractVector)
d_out_fillrange[:y] = series[:fillrange]
d_out_fillrange[:y] = series[:fillrange][rng]
delete!(d_out_fillrange, :fill)
delete!(d_out_fillrange, :fillcolor)
else
# if fillrange is a tuple with upper and lower limit, d_out_fillrange
# is the series that will do the filling
d_out_fillrange[:x], d_out_fillrange[:y] =
concatenate_fillrange(x[rng], series[:fillrange][rng])
fillrng = Tuple(series[:fillrange][i][rng] for i in 1:2)
d_out_fillrange[:x], d_out_fillrange[:y] = concatenate_fillrange(x[rng], fillrng)
d_out_fillrange[:line][:width] = 0
delete!(d_out, :fill)
delete!(d_out, :fillcolor)
@ -848,6 +828,8 @@ function plotly_series_segments(series::Series, d_base::KW, x, y, z)
push!(d_outs, plotly_colorbar_hack(series, d_base, :line))
elseif series[:fill_z] != nothing
push!(d_outs, plotly_colorbar_hack(series, d_base, :fill))
elseif series[:marker_z] != nothing
push!(d_outs, plotly_colorbar_hack(series, d_base, :marker))
end
d_outs
@ -858,6 +840,7 @@ function plotly_colorbar_hack(series::Series, d_base::KW, sym::Symbol)
cmin, cmax = get_clims(series[:subplot])
d_out[:showlegend] = false
d_out[:type] = is3d(series) ? :scatter3d : :scatter
d_out[:hoverinfo] = :none
d_out[:mode] = :markers
d_out[:x], d_out[:y] = [series[:x][1]], [series[:y][1]]
if is3d(series)
@ -866,6 +849,7 @@ function plotly_colorbar_hack(series::Series, d_base::KW, sym::Symbol)
# zrange = zmax == zmin ? 1 : zmax - zmin # if all marker_z values are the same, plot all markers same color (avoids division by zero in next line)
d_out[:marker] = KW(
:size => 0,
:opacity => 0,
:color => [0.5],
:cmin => cmin,
:cmax => cmax,
@ -944,17 +928,7 @@ end
# ----------------------------------------------------------------
function _show(io::IO, ::MIME"image/png", plt::Plot{PlotlyBackend})
# 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})
error("svg output from the plotly backend is not supported. Please use plotlyjs instead.")
end
function Base.show(io::IO, ::MIME"text/html", plt::Plot{PlotlyBackend})
prepare_output(plt)
function _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyBackend})
write(io, html_head(plt) * html_body(plt))
end

View File

@ -88,8 +88,7 @@ end
# ----------------------------------------------------------------
function Base.show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend})
prepare_output(plt)
function _show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend})
if isijulia() && !_use_remote[]
write(io, PlotlyJS.html_body(PlotlyJS.JupyterPlot(plt.o)))
else
@ -121,6 +120,12 @@ function _display(plt::Plot{PlotlyJSBackend})
end
end
@require WebIO begin
function WebIO.render(plt::Plot{PlotlyJSBackend})
prepare_output(plt)
WebIO.render(plt.o)
end
end
function closeall(::PlotlyJSBackend)
if !isplotnull() && isa(current().o, PlotlyJS.SyncPlot)

View File

@ -395,14 +395,14 @@ function py_bbox_title(ax)
end
function py_dpi_scale(plt::Plot{PyPlotBackend}, ptsz)
ptsz * plt[:dpi] / DPI
ptsz
end
# ---------------------------------------------------------------------------
# Create the window/figure for this backend.
function _create_backend_figure(plt::Plot{PyPlotBackend})
w,h = map(px2inch, plt[:size])
w,h = map(px2inch, Tuple(s * plt[:dpi] / Plots.DPI for s in plt[:size]))
# # reuse the current figure?
fig = if plt[:overwrite_figure]
@ -570,12 +570,12 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
if series[:markershape] != :none && st in (:path, :scatter, :path3d,
:scatter3d, :steppre, :steppost,
:bar)
if series[:marker_z] == nothing
extrakw[:c] = series[:markershape] in (:+, :x, :hline, :vline) ? py_markerstrokecolor(series) : py_color_fix(py_markercolor(series), x)
markercolor = if any(typeof(series[arg]) <: AVec for arg in (:markercolor, :markeralpha)) || series[:marker_z] != nothing
py_color(plot_color.(get_markercolor.(series, eachindex(x)), get_markeralpha.(series, eachindex(x))))
else
extrakw[:c] = convert(Vector{Float64}, series[:marker_z])
extrakw[:cmap] = py_markercolormap(series)
py_color(plot_color(series[:markercolor], series[:markeralpha]))
end
extrakw[:c] = py_color_fix(markercolor, x)
xyargs = if st == :bar && !isvertical(series)
(y, x)
else
@ -591,11 +591,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
msc = py_markerstrokecolor(series)
lw = py_dpi_scale(plt, series[:markerstrokewidth])
for i=1:length(y)
extrakw[:c] = if series[:marker_z] == nothing
py_color_fix(py_color(_cycle(series[:markercolor],i)), x)
else
extrakw[:c]
end
extrakw[:c] = _cycle(markercolor, i)
push!(handle, ax[:scatter](_cycle(x,i), _cycle(y,i);
label = series[:label],
@ -638,6 +634,12 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
if st in (:contour, :contour3d)
z = transpose_z(series, z.surf)
if typeof(x)<:Plots.Surface
x = Plots.transpose_z(series, x.surf)
end
if typeof(y)<:Plots.Surface
y = Plots.transpose_z(series, y.surf)
end
if st == :contour3d
extrakw[:extend3d] = true
@ -835,9 +837,9 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
end
n = length(dim1)
args = if typeof(fillrange) <: Union{Real, AVec}
dim1, expand_data(fillrange, n), dim2
dim1, _cycle(fillrange, rng), dim2
elseif is_2tuple(fillrange)
dim1, expand_data(fillrange[1], n), expand_data(fillrange[2], n)
dim1, _cycle(fillrange[1], rng), _cycle(fillrange[2], rng)
end
handle = ax[f](args..., trues(n), false, py_fillstepstyle(st);
@ -953,10 +955,10 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
w, h = plt[:size]
fig = plt.o
fig[:clear]()
dpi = plt[:dpi]
fig[:set_size_inches](w/dpi, h/dpi, forward = true)
dpi = plt[:thickness_scaling] * plt[:dpi]
fig[:set_size_inches](w/DPI/plt[:thickness_scaling], h/DPI/plt[:thickness_scaling], forward = true)
fig[set_facecolor_sym](py_color(plt[:background_color_outside]))
fig[:set_dpi](dpi)
fig[:set_dpi](plt[:dpi])
# resize the window
PyPlot.plt[:get_current_fig_manager]()[:resize](w, h)
@ -1014,10 +1016,16 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
kw[:ticks] = locator
kw[:format] = formatter
kw[:boundaries] = vcat(0, kw[:values] + 0.5)
elseif any(colorbar_series[attr] != nothing for attr in (:line_z, :fill_z))
elseif any(colorbar_series[attr] != nothing for attr in (:line_z, :fill_z, :marker_z))
cmin, cmax = get_clims(sp)
norm = pycolors[:Normalize](vmin = cmin, vmax = cmax)
f = colorbar_series[:line_z] != nothing ? py_linecolormap : py_fillcolormap
f = if colorbar_series[:line_z] != nothing
py_linecolormap
elseif colorbar_series[:fill_z] != nothing
py_fillcolormap
else
py_markercolormap
end
cmap = pycmap[:ScalarMappable](norm = norm, cmap = f(colorbar_series))
cmap[:set_array]([])
handle = cmap
@ -1077,7 +1085,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
pyaxis[Symbol(:tick_, pos)]() # the tick labels
end
py_set_scale(ax, axis)
axis[:ticks] != :native || axis[:lims] != :auto ? py_set_lims(ax, axis) : nothing
axis[:ticks] != :native ? py_set_lims(ax, axis) : nothing
if ispolar(sp) && letter == :y
ax[:set_rlabel_position](90)
end
@ -1201,7 +1209,9 @@ function _update_min_padding!(sp::Subplot{PyPlotBackend})
rightpad += sp[:right_margin]
bottompad += sp[:bottom_margin]
sp.minpad = (leftpad, toppad, rightpad, bottompad)
dpi_factor = sp.plt[:thickness_scaling] * Plots.DPI / sp.plt[:dpi]
sp.minpad = Tuple(dpi_factor .* [leftpad, toppad, rightpad, bottompad])
end
@ -1262,8 +1272,8 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
linewidth = py_dpi_scale(plt, clamp(get_linewidth(series), 0, 5)),
linestyle = py_linestyle(:path, get_linestyle(series)),
marker = py_marker(series[:markershape]),
markeredgecolor = py_markerstrokecolor(series),
markerfacecolor = series[:marker_z] == nothing ? py_markercolor(series) : py_color(series[:markercolor][0.5])
markeredgecolor = py_color(get_markerstrokecolor(series), get_markerstrokealpha(series)),
markerfacecolor = series[:marker_z] == nothing ? py_color(get_markercolor(series), get_markeralpha(series)) : py_color(series[:markercolor][0.5])
)
else
series[:serieshandle][1]
@ -1278,23 +1288,17 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
labels,
loc = get(_pyplot_legend_pos, leg, "best"),
scatterpoints = 1,
fontsize = py_dpi_scale(plt, sp[:legendfontsize])
# family = sp[:legendfont].family
# framealpha = 0.6
fontsize = py_dpi_scale(plt, sp[:legendfontsize]),
facecolor = py_color(sp[:background_color_legend]),
edgecolor = py_color(sp[:foreground_color_legend]),
framealpha = alpha(plot_color(sp[:background_color_legend])),
)
leg[:set_zorder](1000)
sp[:legendtitle] != nothing && leg[:set_title](sp[:legendtitle])
fgcolor = py_color(sp[:foreground_color_legend])
lfcolor = py_color(sp[:legendfontcolor])
for txt in leg[:get_texts]()
PyPlot.plt[:setp](txt, color = lfcolor, family = sp[:legendfontfamily])
PyPlot.plt[:setp](txt, color = py_color(sp[:legendfontcolor]), family = sp[:legendfontfamily])
end
# set some legend properties
frame = leg[:get_frame]()
frame[set_facecolor_sym](py_color(sp[:background_color_legend]))
frame[:set_edgecolor](fgcolor)
end
end
end
@ -1356,7 +1360,7 @@ for (mime, fmt) in _pyplot_mimeformats
# figsize = map(px2inch, plt[:size]),
facecolor = fig[:get_facecolor](),
edgecolor = "none",
dpi = plt[:dpi]
dpi = plt[:dpi] * plt[:thickness_scaling]
)
end
end

View File

@ -212,7 +212,7 @@ end
function _show(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend})
unicodeplots_rebuild(plt)
map(show, plt.o)
foreach(x -> show(io, x), plt.o)
nothing
end

View File

@ -157,17 +157,6 @@ end
# ---------------------------------------------------------
const _mimeformats = Dict(
"application/eps" => "eps",
"image/eps" => "eps",
"application/pdf" => "pdf",
"image/png" => "png",
"application/postscript" => "ps",
"image/svg+xml" => "svg",
"text/plain" => "txt",
"application/x-tex" => "tex",
)
const _best_html_output_type = KW(
:pyplot => :png,
:unicodeplots => :txt,
@ -177,7 +166,7 @@ const _best_html_output_type = KW(
)
# a backup for html... passes to svg or png depending on the html_output_format arg
function Base.show(io::IO, ::MIME"text/html", plt::Plot)
function _show(io::IO, ::MIME"text/html", plt::Plot)
output_type = Symbol(plt.attr[:html_output_format])
if output_type == :auto
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
@ -191,26 +180,32 @@ function Base.show(io::IO, ::MIME"text/html", plt::Plot)
elseif output_type == :txt
show(io, MIME("text/plain"), plt)
else
error("only png or svg allowed. got: $output_type")
error("only png or svg allowed. got: $(repr(output_type))")
end
end
function _show(io::IO, m, plt::Plot{B}) where B
# Base.show_backtrace(STDOUT, backtrace())
warn("_show is not defined for this backend. m=", string(m))
# delegate mimewritable (showable on julia 0.7) to _show instead
function Base.mimewritable(m::M, plt::P) where {M<:MIME, P<:Plot}
return method_exists(_show, Tuple{IO, M, P})
end
function _display(plt::Plot)
warn("_display is not defined for this backend.")
end
# for writing to io streams... first prepare, then callback
for mime in keys(_mimeformats)
@eval function Base.show(io::IO, m::MIME{Symbol($mime)}, plt::Plot{B}) where B
for mime in ("text/plain", "text/html", "image/png", "image/eps", "image/svg+xml",
"application/eps", "application/pdf", "application/postscript",
"application/x-tex")
@eval function Base.show(io::IO, m::MIME{Symbol($mime)}, plt::Plot)
prepare_output(plt)
_show(io, m, plt)
end
end
# default text/plain for all backends
_show(io::IO, ::MIME{Symbol("text/plain")}, plt::Plot) = show(io, plt)
"Close all open gui windows of the current backend"
closeall() = closeall(backend())
@ -218,9 +213,10 @@ closeall() = closeall(backend())
# ---------------------------------------------------------
# A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert
const PDFBackends = Union{PGFPlotsBackend,PlotlyJSBackend,PyPlotBackend,InspectDRBackend,GRBackend}
if is_installed("FileIO")
@eval import FileIO
function _show(io::IO, ::MIME"image/png", plt::Plot)
function _show(io::IO, ::MIME"image/png", plt::Plot{<:PDFBackends})
fn = tempname()
# first save a pdf file
@ -288,7 +284,10 @@ end
output_type = get(_best_html_output_type, backend_name(plt.backend), :svg)
end
out = Dict()
if output_type == :png
if output_type == :txt
mime = "text/plain"
out[mime] = sprint(show, MIME(mime), plt)
elseif output_type == :png
mime = "image/png"
out[mime] = base64encode(show, MIME(mime), plt)
elseif output_type == :svg
@ -304,11 +303,6 @@ end
out
end
# default text/plain passes to html... handles Interact issues
function Base.show(io::IO, m::MIME"text/plain", plt::Plot)
show(io, MIME("text/html"), plt)
end
ENV["MPLBACKEND"] = "Agg"
end
end
@ -322,9 +316,6 @@ end
if Juno.isactive()
Media.media(Plot, Media.Plot)
_show(io::IO, m::MIME"text/plain", plt::Plot{B}) where {B} = print(io, "Plot{$B}()")
function Juno.render(e::Juno.Editor, plt::Plot)
Juno.render(e, nothing)
end
@ -333,13 +324,20 @@ end
function Juno.render(pane::Juno.PlotPane, plt::Plot)
# temporarily overwrite size to be Atom.plotsize
sz = plt[:size]
dpi = plt[:dpi]
thickness_scaling = plt[:thickness_scaling]
jsize = Juno.plotsize()
jsize[1] == 0 && (jsize[1] = 400)
jsize[2] == 0 && (jsize[2] = 500)
plt[:size] = jsize
scale = minimum(jsize[i] / sz[i] for i in 1:2)
plt[:size] = (s * scale for s in sz)
plt[:dpi] = Plots.DPI
plt[:thickness_scaling] *= scale
Juno.render(pane, HTML(stringmime(MIME("text/html"), plt)))
plt[:size] = sz
plt[:dpi] = dpi
plt[:thickness_scaling] = thickness_scaling
end
# special handling for PlotlyJS
function Juno.render(pane::Juno.PlotPane, plt::Plot{PlotlyJSBackend})

View File

@ -327,7 +327,7 @@ end
function _override_seriestype_check(d::KW, st::Symbol)
# do we want to override the series type?
if !is3d(st)
if !is3d(st) && !(st in (:contour,:contour3d))
z = d[:z]
if !isa(z, Void) && (size(d[:x]) == size(d[:y]) == size(z))
st = (st == :scatter ? :scatter3d : :path3d)
@ -398,6 +398,7 @@ function _process_seriesrecipe(plt::Plot, d::KW)
sp = _prepare_subplot(plt, d)
_prepare_annotations(sp, d)
_expand_subplot_extrema(sp, d, st)
_update_series_attributes!(d, plt, sp)
_add_the_series(plt, sp, d)
else

View File

@ -413,6 +413,7 @@ end
z := nothing
seriestype := :shape
label := ""
widen --> false
()
end
@deps plots_heatmap shape

View File

@ -627,7 +627,7 @@ group_as_matrix(t) = false
else
g = args[1]
if length(g.args) == 1
x = zeros(Int64, lengthGroup)
x = zeros(Int, lengthGroup)
for indexes in groupby.groupIds
x[indexes] = 1:length(indexes)
end

View File

@ -195,9 +195,13 @@ end
function iter_segments(series::Series)
x, y, z = series[:x], series[:y], series[:z]
if has_attribute_segments(series)
return [i:(i + 1) for i in 1:(length(y) - 1)]
if series[:seriestype] in (:scatter, :scatter3d)
return [[i] for i in 1:length(y)]
else
return [i:(i + 1) for i in 1:(length(y) - 1)]
end
else
segs = UnitRange{Int64}[]
segs = UnitRange{Int}[]
args = is3d(series) ? (x, y, z) : (x, y)
for seg in iter_segments(args...)
push!(segs, seg)
@ -354,19 +358,18 @@ const _scale_base = Dict{Symbol, Real}(
:ln => e,
)
"create an (n+1) list of the outsides of heatmap rectangles"
function heatmap_edges(v::AVec, scale::Symbol = :identity)
function _heatmap_edges(v::AVec)
vmin, vmax = ignorenan_extrema(v)
extra_min = extra_max = 0.5 * (vmax-vmin) / (length(v)-1)
if scale in _logScales
vmin > 0 || error("The axis values must be positive for a $scale scale")
while vmin - extra_min <= 0
extra_min /= _scale_base[scale]
end
end
extra_min = (v[2] - v[1]) / 2
extra_max = (v[end] - v[end - 1]) / 2
vcat(vmin-extra_min, 0.5 * (v[1:end-1] + v[2:end]), vmax+extra_max)
end
"create an (n+1) list of the outsides of heatmap rectangles"
function heatmap_edges(v::AVec, scale::Symbol = :identity)
f, invf = scalefunc(scale), invscalefunc(scale)
map(invf, _heatmap_edges(map(f,v)))
end
function calc_r_extrema(x, y)
xmin, xmax = ignorenan_extrema(x)
@ -620,7 +623,7 @@ function get_linecolor(series, i::Int = 1)
lc = series[:linecolor]
lz = series[:line_z]
if lz == nothing
isa(lc, ColorGradient) ? lc : _cycle(lc, i)
isa(lc, ColorGradient) ? lc : plot_color(_cycle(lc, i))
else
cmin, cmax = get_clims(series[:subplot])
grad = isa(lc, ColorGradient) ? lc : cgrad()
@ -644,7 +647,7 @@ function get_fillcolor(series, i::Int = 1)
fc = series[:fillcolor]
fz = series[:fill_z]
if fz == nothing
isa(fc, ColorGradient) ? fc : _cycle(fc, i)
isa(fc, ColorGradient) ? fc : plot_color(_cycle(fc, i))
else
cmin, cmax = get_clims(series[:subplot])
grad = isa(fc, ColorGradient) ? fc : cgrad()
@ -656,6 +659,31 @@ function get_fillalpha(series, i::Int = 1)
_cycle(series[:fillalpha], i)
end
function get_markercolor(series, i::Int = 1)
mc = series[:markercolor]
mz = series[:marker_z]
if mz == nothing
isa(mc, ColorGradient) ? mc : plot_color(_cycle(mc, i))
else
cmin, cmax = get_clims(series[:subplot])
grad = isa(mc, ColorGradient) ? mc : cgrad()
grad[clamp((_cycle(mz, i) - cmin) / (cmax - cmin), 0, 1)]
end
end
function get_markeralpha(series, i::Int = 1)
_cycle(series[:markeralpha], i)
end
function get_markerstrokecolor(series, i::Int = 1)
msc = series[:markerstrokecolor]
isa(msc, ColorGradient) ? msc : _cycle(msc, i)
end
function get_markerstrokealpha(series, i::Int = 1)
_cycle(series[:markerstrokealpha], i)
end
function has_attribute_segments(series::Series)
# we want to check if a series needs to be split into segments just because
# of its attributes
@ -666,7 +694,7 @@ function has_attribute_segments(series::Series)
end
series[:seriestype] == :shape && return false
# ... else we check relevant attributes if they have multiple inputs
return any((typeof(series[attr]) <: AbstractVector && length(series[attr]) > 1) for attr in [:seriescolor, :seriesalpha, :linecolor, :linealpha, :linewidth, :fillcolor, :fillalpha]) || any(typeof(series[attr]) <: AbstractArray{<:Real} for attr in (:line_z, :fill_z))
return any((typeof(series[attr]) <: AbstractVector && length(series[attr]) > 1) for attr in [:seriescolor, :seriesalpha, :linecolor, :linealpha, :linewidth, :fillcolor, :fillalpha, :markercolor, :markeralpha, :markerstrokecolor, :markerstrokealpha]) || any(typeof(series[attr]) <: AbstractArray{<:Real} for attr in (:line_z, :fill_z, :marker_z))
end
# ---------------------------------------------------------------

View File

@ -23,7 +23,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.17.0"
const _current_plots_version = v"0.17.3"
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)

View File

@ -9,8 +9,7 @@ Pkg.clone("https://github.com/JuliaPlots/PlotReferenceImages.jl.git")
# Pkg.clone("https://github.com/JuliaStats/KernelDensity.jl.git")
Pkg.clone("StatPlots")
Pkg.checkout("PlotUtils", "julia0.7")
Pkg.checkout("RecipesBase", "julia0.7")
# Pkg.checkout("PlotUtils")
# Pkg.clone("Blink")
# Pkg.build("Blink")