Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c4bdc5b856 | |||
| b5b4023056 | |||
| 0e598cc51d | |||
| 9fd09924eb | |||
| 10d218089f | |||
| 1ba0d198a7 | |||
| c44132d29d | |||
| a018a2c07a | |||
| 266d2efde5 | |||
| 3b33b054d3 | |||
| 1140b51e91 | |||
| 9d25c8fcd4 | |||
| e8ade18d47 | |||
| ed243f4e3e | |||
| e0af4b7925 | |||
| 80e53adbd8 | |||
| 36a29357a3 | |||
| 5bb9aceaac | |||
| 02d893b316 | |||
| b1850e58f4 | |||
| f1e566dddc | |||
| 2f60da33b7 | |||
| b0456d155a | |||
| 5f57a48996 | |||
| bc9d137001 | |||
| 483946787a | |||
| b165f233a8 | |||
| 3b325b2482 | |||
| 2dd480a3a6 | |||
| df33ed40d6 | |||
| cf4d78c87c | |||
| 8007d0dd6a | |||
| d7098f77c2 | |||
| 514284e784 | |||
| 2a3029edb4 | |||
| 45a1ed69d4 | |||
| 7248d8d7ce | |||
| fa84401866 | |||
| 910b94c5fd |
@@ -4,3 +4,4 @@
|
||||
.DS_Store
|
||||
examples/.ipynb_checkpoints/*
|
||||
examples/meetup/.ipynb_checkpoints/*
|
||||
deps/plotly-latest.min.js
|
||||
|
||||
@@ -9,6 +9,37 @@
|
||||
|
||||
## 0.7 (current master/dev)
|
||||
|
||||
#### 0.7.1
|
||||
|
||||
- inset (floating) subplots
|
||||
- change: when setting subplot/axis args from user recipes, they should apply only to their own subplot
|
||||
- trim for violin/boxplot
|
||||
- scatter3d recipe
|
||||
- removed plotly.js in favor of build.jl download
|
||||
- improvements/fixes to pgfplots backend
|
||||
- improvements/fixes to plotly/plotlyjs backends
|
||||
- titles are annotations and properly placed with title_position
|
||||
- hover attribute
|
||||
- shapes (almost)
|
||||
- scattergl
|
||||
- minimum perimeter logic in layout calc... fixed misaligned subplots
|
||||
- new clims attribute
|
||||
- more options for test_examples
|
||||
- GR refactor
|
||||
- added transparency
|
||||
- moved axis/grid logic out of series loop
|
||||
- generalized 3d and polar projections
|
||||
- renamed get_mod to Base.cycle
|
||||
- pyplot log scale fixes
|
||||
- PLOTS_DEFAULTS environment var processing
|
||||
- rename :ellipse to :circle, :ellipse is now an alias
|
||||
- supported args/types cleanup
|
||||
- seriestype dependency methods and `@deps` macro
|
||||
- bbox `h_anchor`/`v_anchor`
|
||||
- new axis arg: `:link` is a list of subplots to link axes with
|
||||
- cleanup/simplification of glvisualize backend
|
||||
|
||||
|
||||
#### 0.7.0
|
||||
|
||||
- Check out [the summary](http://plots.readthedocs.io/en/latest/plots_v0.7/)
|
||||
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
|
||||
#TODO: download https://cdn.plot.ly/plotly-latest.min.js to deps/ if it doesn't exist
|
||||
|
||||
local_fn = joinpath(dirname(@__FILE__), "plotly-latest.min.js")
|
||||
if !isfile(local_fn)
|
||||
info("Cannot find deps/plotly-latest.min.js... downloading latest version.")
|
||||
download("https://cdn.plot.ly/plotly-latest.min.js", local_fn)
|
||||
end
|
||||
Vendored
-41
File diff suppressed because one or more lines are too long
+17
-115
@@ -19,14 +19,12 @@ export
|
||||
GridLayout,
|
||||
grid,
|
||||
EmptyLayout,
|
||||
bbox,
|
||||
plotarea,
|
||||
@layout,
|
||||
# RowsLayout,
|
||||
# FlexLayout,
|
||||
AVec,
|
||||
AMat,
|
||||
KW,
|
||||
# attr,
|
||||
# attr!,
|
||||
|
||||
wrap,
|
||||
set_theme,
|
||||
@@ -34,8 +32,6 @@ export
|
||||
|
||||
plot,
|
||||
plot!,
|
||||
# subplot,
|
||||
# subplot!,
|
||||
|
||||
current,
|
||||
default,
|
||||
@@ -43,53 +39,11 @@ export
|
||||
|
||||
@userplot,
|
||||
@shorthands,
|
||||
# scatter,
|
||||
# scatter!,
|
||||
# bar,
|
||||
# bar!,
|
||||
# barh,
|
||||
# barh!,
|
||||
# histogram,
|
||||
# histogram!,
|
||||
# histogram2d,
|
||||
# histogram2d!,
|
||||
# density,
|
||||
# density!,
|
||||
# heatmap,
|
||||
# heatmap!,
|
||||
# hexbin,
|
||||
# hexbin!,
|
||||
# sticks,
|
||||
# sticks!,
|
||||
# hline,
|
||||
# hline!,
|
||||
# vline,
|
||||
# vline!,
|
||||
# ohlc,
|
||||
# ohlc!,
|
||||
|
||||
pie,
|
||||
pie!,
|
||||
# contour,
|
||||
# contour!,
|
||||
# contour3d,
|
||||
# contour3d!,
|
||||
# surface,
|
||||
# surface!,
|
||||
# wireframe,
|
||||
# wireframe!,
|
||||
# path3d,
|
||||
# path3d!,
|
||||
plot3d,
|
||||
plot3d!,
|
||||
# scatter3d,
|
||||
# scatter3d!,
|
||||
# abline!,
|
||||
# boxplot,
|
||||
# boxplot!,
|
||||
# violin,
|
||||
# violin!,
|
||||
# quiver,
|
||||
# quiver!,
|
||||
|
||||
title!,
|
||||
xlabel!,
|
||||
@@ -119,9 +73,6 @@ export
|
||||
text,
|
||||
font,
|
||||
Axis,
|
||||
# xaxis,
|
||||
# yaxis,
|
||||
# zaxis,
|
||||
stroke,
|
||||
brush,
|
||||
Surface,
|
||||
@@ -140,12 +91,11 @@ export
|
||||
|
||||
debugplots,
|
||||
|
||||
supportedArgs,
|
||||
supportedAxes,
|
||||
supportedTypes,
|
||||
supportedStyles,
|
||||
supportedMarkers,
|
||||
subplotSupported,
|
||||
supported_args,
|
||||
supported_types,
|
||||
supported_styles,
|
||||
supported_markers,
|
||||
is_subplot_supported,
|
||||
|
||||
Animation,
|
||||
frame,
|
||||
@@ -158,10 +108,6 @@ export
|
||||
arcdiagram,
|
||||
chorddiagram,
|
||||
|
||||
# @kw,
|
||||
# @recipe,
|
||||
# @plotrecipe,
|
||||
|
||||
test_examples,
|
||||
|
||||
translate,
|
||||
@@ -178,9 +124,9 @@ export
|
||||
# ---------------------------------------------------------
|
||||
|
||||
import Measures
|
||||
import Measures: Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height
|
||||
import Measures: Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height, w, h
|
||||
typealias BBox Measures.Absolute2DBox
|
||||
export BBox, BoundingBox, mm, cm, inch, pt, px, pct
|
||||
export BBox, BoundingBox, mm, cm, inch, pt, px, pct, w, h
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
@@ -209,14 +155,11 @@ include("arg_desc.jl")
|
||||
# define and export shorthand plotting method definitions
|
||||
macro shorthands(funcname::Symbol)
|
||||
funcname2 = Symbol(funcname, "!")
|
||||
ret = esc(quote
|
||||
esc(quote
|
||||
export $funcname, $funcname2
|
||||
$funcname(args...; kw...) = plot(args...; kw..., seriestype = $(quot(funcname)))
|
||||
$funcname2(args...; kw...) = plot!(args...; kw..., seriestype = $(quot(funcname)))
|
||||
end)
|
||||
# dump(ret,20)
|
||||
# @show ret
|
||||
ret
|
||||
end
|
||||
|
||||
@shorthands scatter
|
||||
@@ -231,7 +174,6 @@ end
|
||||
@shorthands hline
|
||||
@shorthands vline
|
||||
@shorthands ohlc
|
||||
# @shorthands pie
|
||||
@shorthands contour
|
||||
@shorthands contour3d
|
||||
@shorthands surface
|
||||
@@ -242,52 +184,10 @@ end
|
||||
@shorthands violin
|
||||
@shorthands quiver
|
||||
|
||||
# scatter(args...; kw...) = plot(args...; kw..., seriestype = :scatter)
|
||||
# scatter!(args...; kw...) = plot!(args...; kw..., seriestype = :scatter)
|
||||
# bar(args...; kw...) = plot(args...; kw..., seriestype = :bar)
|
||||
# bar!(args...; kw...) = plot!(args...; kw..., seriestype = :bar)
|
||||
# barh(args...; kw...) = plot(args...; kw..., seriestype = :barh, orientation = :h)
|
||||
# barh!(args...; kw...) = plot!(args...; kw..., seriestype = :barh, orientation = :h)
|
||||
# histogram(args...; kw...) = plot(args...; kw..., seriestype = :histogram)
|
||||
# histogram!(args...; kw...) = plot!(args...; kw..., seriestype = :histogram)
|
||||
# histogram2d(args...; kw...) = plot(args...; kw..., seriestype = :histogram2d)
|
||||
# histogram2d!(args...; kw...) = plot!(args...; kw..., seriestype = :histogram2d)
|
||||
# density(args...; kw...) = plot(args...; kw..., seriestype = :density)
|
||||
# density!(args...; kw...) = plot!(args...; kw..., seriestype = :density)
|
||||
# heatmap(args...; kw...) = plot(args...; kw..., seriestype = :heatmap)
|
||||
# heatmap!(args...; kw...) = plot!(args...; kw..., seriestype = :heatmap)
|
||||
# hexbin(args...; kw...) = plot(args...; kw..., seriestype = :hexbin)
|
||||
# hexbin!(args...; kw...) = plot!(args...; kw..., seriestype = :hexbin)
|
||||
# sticks(args...; kw...) = plot(args...; kw..., seriestype = :sticks, marker = :ellipse)
|
||||
# sticks!(args...; kw...) = plot!(args...; kw..., seriestype = :sticks, marker = :ellipse)
|
||||
# hline(args...; kw...) = plot(args...; kw..., seriestype = :hline)
|
||||
# hline!(args...; kw...) = plot!(args...; kw..., seriestype = :hline)
|
||||
# vline(args...; kw...) = plot(args...; kw..., seriestype = :vline)
|
||||
# vline!(args...; kw...) = plot!(args...; kw..., seriestype = :vline)
|
||||
# ohlc(args...; kw...) = plot(args...; kw..., seriestype = :ohlc)
|
||||
# ohlc!(args...; kw...) = plot!(args...; kw..., seriestype = :ohlc)
|
||||
pie(args...; kw...) = plot(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
|
||||
pie!(args...; kw...) = plot!(args...; kw..., seriestype = :pie, aspect_ratio = :equal, grid=false, xticks=nothing, yticks=nothing)
|
||||
# contour(args...; kw...) = plot(args...; kw..., seriestype = :contour)
|
||||
# contour!(args...; kw...) = plot!(args...; kw..., seriestype = :contour)
|
||||
# contour3d(args...; kw...) = plot(args...; kw..., seriestype = :contour3d)
|
||||
# contour3d!(args...; kw...) = plot!(args...; kw..., seriestype = :contour3d)
|
||||
# surface(args...; kw...) = plot(args...; kw..., seriestype = :surface)
|
||||
# surface!(args...; kw...) = plot!(args...; kw..., seriestype = :surface)
|
||||
# wireframe(args...; kw...) = plot(args...; kw..., seriestype = :wireframe)
|
||||
# wireframe!(args...; kw...) = plot!(args...; kw..., seriestype = :wireframe)
|
||||
# path3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
|
||||
# path3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
|
||||
plot3d(args...; kw...) = plot(args...; kw..., seriestype = :path3d)
|
||||
plot3d!(args...; kw...) = plot!(args...; kw..., seriestype = :path3d)
|
||||
# scatter3d(args...; kw...) = plot(args...; kw..., seriestype = :scatter3d)
|
||||
# scatter3d!(args...; kw...) = plot!(args...; kw..., seriestype = :scatter3d)
|
||||
# boxplot(args...; kw...) = plot(args...; kw..., seriestype = :boxplot)
|
||||
# boxplot!(args...; kw...) = plot!(args...; kw..., seriestype = :boxplot)
|
||||
# violin(args...; kw...) = plot(args...; kw..., seriestype = :violin)
|
||||
# violin!(args...; kw...) = plot!(args...; kw..., seriestype = :violin)
|
||||
# quiver(args...; kw...) = plot(args...; kw..., seriestype = :quiver)
|
||||
# quiver!(args...; kw...) = plot!(args...; kw..., seriestype = :quiver)
|
||||
|
||||
|
||||
title!(s::AbstractString; kw...) = plot!(; title = s, kw...)
|
||||
@@ -340,13 +240,15 @@ yaxis!(plt::Plot, args...; kw...) = plot!(pl
|
||||
|
||||
const CURRENT_BACKEND = CurrentBackend(:none)
|
||||
|
||||
# setup_dataframes()
|
||||
|
||||
function __init__()
|
||||
setup_ijulia()
|
||||
# setup_dataframes()
|
||||
setup_atom()
|
||||
# add_axis_letter_defaults()
|
||||
|
||||
if haskey(ENV, "PLOTS_DEFAULTS")
|
||||
for (k,v) in eval(parse(ENV["PLOTS_DEFAULTS"]))
|
||||
default(k, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ immutable AnimatedGif
|
||||
filename::Compat.ASCIIString
|
||||
end
|
||||
|
||||
function gif(anim::Animation, fn::Compat.ASCIIString = "tmp.gif"; fps::Integer = 20)
|
||||
function gif(anim::Animation, fn = "tmp.gif"; fps::Integer = 20)
|
||||
fn = abspath(fn)
|
||||
|
||||
try
|
||||
|
||||
@@ -45,6 +45,7 @@ const _arg_desc = KW(
|
||||
:subplot => "Integer (subplot index) or Subplot object. The subplot that this series belongs to.",
|
||||
:series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.",
|
||||
:primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.",
|
||||
:hover => "nothing or vector of strings. Text to display when hovering over each data point.",
|
||||
|
||||
# plot args
|
||||
:plot_title => "String. Title for the whole plot (not the subplots) (Note: Not currently implemented)",
|
||||
@@ -59,6 +60,7 @@ const _arg_desc = KW(
|
||||
:link => "Symbol. How/whether to link axis limits between subplots. Values: `:none`, `:x` (x axes are linked by columns), `:y` (y axes are linked by rows), `:both` (x and y are linked), `:all` (every subplot is linked together regardless of layout position).",
|
||||
:overwrite_figure => "Bool. Should we reuse the same GUI window/figure when plotting (true) or open a new one (false).",
|
||||
: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",
|
||||
|
||||
# subplot args
|
||||
:title => "String. Subplot title.",
|
||||
@@ -74,6 +76,7 @@ const _arg_desc = KW(
|
||||
:color_palette => "Vector of colors (cycle through) or color gradient (generate list from gradient) or `:auto` (generate a color list using `Colors.distiguishable_colors` and custom seed colors chosen to contrast with the background). The color palette is a color list from which series colors are automatically chosen.",
|
||||
:legend => "Bool (show the legend?) or Symbol (legend position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:inside`, `:legend`, `:topright`, `:topleft`, `:bottomleft`, `:bottomright` (note: only some may be supported in each backend)",
|
||||
:colorbar => "Bool (show the colorbar?) or Symbol (colorbar position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:legend` (matches legend value) (note: only some may be supported in each backend)",
|
||||
:clims => "`:auto` or NTuple{2,Number}. Fixes the limits of the colorbar.",
|
||||
:legendfont => "Font. Font of legend items.",
|
||||
: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.",
|
||||
|
||||
+83
-77
@@ -86,13 +86,14 @@ const _allStyles = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
:ddd => :dashdotdot,
|
||||
)
|
||||
|
||||
const _allMarkers = vcat(:none, :auto, sort(collect(keys(_shapes))))
|
||||
const _allMarkers = vcat(:none, :auto, _shape_keys) #sort(collect(keys(_shapes))))
|
||||
@compat const _markerAliases = KW(
|
||||
:n => :none,
|
||||
:no => :none,
|
||||
:a => :auto,
|
||||
:circle => :ellipse,
|
||||
:c => :ellipse,
|
||||
:ellipse => :circle,
|
||||
:c => :circle,
|
||||
:circ => :circle,
|
||||
:square => :rect,
|
||||
:sq => :rect,
|
||||
:r => :rect,
|
||||
@@ -181,6 +182,7 @@ const _series_defaults = KW(
|
||||
:series_annotations => [], # a list of annotations which apply to the coordinates of this series
|
||||
:primary => true, # when true, this "counts" as a series for color selection, etc. the main use is to allow
|
||||
# one logical series to be broken up (path and markers, for example)
|
||||
:hover => nothing, # text to display when hovering over the data points
|
||||
)
|
||||
|
||||
|
||||
@@ -197,6 +199,8 @@ const _plot_defaults = KW(
|
||||
:link => :none,
|
||||
:overwrite_figure => true,
|
||||
:html_output_format => :auto,
|
||||
:inset_subplots => nothing, # optionally pass a vector of (parent,bbox) tuples which are
|
||||
# the parent layout and the relative bounding box of inset subplots
|
||||
)
|
||||
|
||||
|
||||
@@ -214,6 +218,7 @@ const _subplot_defaults = KW(
|
||||
:color_palette => :auto,
|
||||
:legend => :best,
|
||||
:colorbar => :legend,
|
||||
:clims => :auto,
|
||||
:legendfont => font(8),
|
||||
:grid => true,
|
||||
:annotations => [], # annotation tuples... list of (x,y,annotation)
|
||||
@@ -234,6 +239,7 @@ const _axis_defaults = KW(
|
||||
:scale => :identity,
|
||||
:rotation => 0,
|
||||
:flip => false,
|
||||
:link => [],
|
||||
:tickfont => font(8),
|
||||
:guidefont => font(11),
|
||||
:foreground_color_axis => :match, # axis border/tick colors,
|
||||
@@ -254,6 +260,7 @@ const _suppress_warnings = Set{Symbol}([
|
||||
:plot_object,
|
||||
:primary,
|
||||
:smooth,
|
||||
:relative_bbox,
|
||||
])
|
||||
|
||||
# add defaults for the letter versions
|
||||
@@ -266,6 +273,7 @@ for letter in (:x,:y,:z)
|
||||
:scale,
|
||||
:rotation,
|
||||
:flip,
|
||||
:link,
|
||||
:tickfont,
|
||||
:guidefont,
|
||||
:foreground_color_axis,
|
||||
@@ -289,10 +297,10 @@ const _all_defaults = KW[
|
||||
]
|
||||
|
||||
const _all_args = sort(collect(union(map(keys, _all_defaults)...)))
|
||||
supportedArgs(::AbstractBackend) = error("supportedArgs not defined") #_all_args
|
||||
supportedArgs() = supportedArgs(backend())
|
||||
supported_args(::AbstractBackend) = error("supported_args not defined") #_all_args
|
||||
supported_args() = supported_args(backend())
|
||||
|
||||
RecipesBase.is_key_supported(k::Symbol) = (k in supportedArgs())
|
||||
RecipesBase.is_key_supported(k::Symbol) = (k in supported_args())
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
@@ -388,14 +396,13 @@ add_aliases(:zticks, :ztick)
|
||||
add_aliases(:zrotation, :zrot, :zr)
|
||||
add_aliases(:legend, :leg, :key)
|
||||
add_aliases(:colorbar, :cb, :cbar, :colorkey)
|
||||
add_aliases(:clims, :clim, :cbarlims, :cbar_lims, :climits, :color_limits)
|
||||
add_aliases(:smooth, :regression, :reg)
|
||||
add_aliases(:levels, :nlevels, :nlev, :levs)
|
||||
add_aliases(:size, :windowsize, :wsize)
|
||||
add_aliases(:window_title, :windowtitle, :wtitle)
|
||||
add_aliases(:show, :gui, :display)
|
||||
add_aliases(:color_palette, :palette)
|
||||
# add_aliases(:linkx, :xlink)
|
||||
# add_aliases(:linky, :ylink)
|
||||
add_aliases(:overwrite_figure, :clf, :clearfig, :overwrite, :reuse)
|
||||
add_aliases(:xerror, :xerr, :xerrorbar)
|
||||
add_aliases(:yerror, :yerr, :yerrorbar, :err, :errorbar)
|
||||
@@ -622,7 +629,7 @@ function preprocessArgs!(d::KW)
|
||||
if haskey(d, :markershape)
|
||||
d[:markershape] = _replace_markershape(d[:markershape])
|
||||
elseif anymarker
|
||||
d[:markershape_to_add] = :ellipse # add it after _apply_recipe
|
||||
d[:markershape_to_add] = :circle # add it after _apply_recipe
|
||||
end
|
||||
|
||||
# handle fill
|
||||
@@ -723,37 +730,46 @@ end
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
function warnOnUnsupportedArgs(pkg::AbstractBackend, d::KW)
|
||||
const _already_warned = Set()
|
||||
|
||||
function warnOnUnsupported_args(pkg::AbstractBackend, d::KW)
|
||||
for k in sortedkeys(d)
|
||||
k in supportedArgs(pkg) && continue
|
||||
k in supported_args(pkg) && continue
|
||||
k in _suppress_warnings && continue
|
||||
if d[k] != default(k)
|
||||
warn("Keyword argument $k not supported with $pkg. Choose from: $(supportedArgs(pkg))")
|
||||
if !((pkg, k) in _already_warned)
|
||||
push!(_already_warned, (pkg,k))
|
||||
warn("Keyword argument $k not supported with $pkg. Choose from: $(supported_args(pkg))")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
_markershape_supported(pkg::AbstractBackend, shape::Symbol) = shape in supportedMarkers(pkg)
|
||||
_markershape_supported(pkg::AbstractBackend, shape::Shape) = Shape in supportedMarkers(pkg)
|
||||
_markershape_supported(pkg::AbstractBackend, shape::Symbol) = shape in supported_markers(pkg)
|
||||
_markershape_supported(pkg::AbstractBackend, shape::Shape) = Shape in supported_markers(pkg)
|
||||
_markershape_supported(pkg::AbstractBackend, shapes::AVec) = all([_markershape_supported(pkg, shape) for shape in shapes])
|
||||
|
||||
function warnOnUnsupported(pkg::AbstractBackend, d::KW)
|
||||
(d[:seriestype] == :none
|
||||
|| d[:seriestype] in supportedTypes(pkg)
|
||||
|| warn("seriestype $(d[:seriestype]) is unsupported with $pkg. Choose from: $(supportedTypes(pkg))"))
|
||||
(d[:linestyle] in supportedStyles(pkg)
|
||||
|| warn("linestyle $(d[:linestyle]) is unsupported with $pkg. Choose from: $(supportedStyles(pkg))"))
|
||||
|| d[:seriestype] in supported_types(pkg)
|
||||
|| warn("seriestype $(d[:seriestype]) is unsupported with $pkg. Choose from: $(supported_types(pkg))"))
|
||||
(d[:linestyle] in supported_styles(pkg)
|
||||
|| warn("linestyle $(d[:linestyle]) is unsupported with $pkg. Choose from: $(supported_styles(pkg))"))
|
||||
(d[:markershape] == :none
|
||||
|| _markershape_supported(pkg, d[:markershape])
|
||||
|| warn("markershape $(d[:markershape]) is unsupported with $pkg. Choose from: $(supportedMarkers(pkg))"))
|
||||
|| warn("markershape $(d[:markershape]) is unsupported with $pkg. Choose from: $(supported_markers(pkg))"))
|
||||
end
|
||||
|
||||
function warnOnUnsupportedScales(pkg::AbstractBackend, d::KW)
|
||||
for k in (:xscale, :yscale)
|
||||
if haskey(d, k)
|
||||
d[k] in supportedScales(pkg) || warn("scale $(d[k]) is unsupported with $pkg. Choose from: $(supportedScales(pkg))")
|
||||
function warnOnUnsupported_scales(pkg::AbstractBackend, d::KW)
|
||||
for k in (:xscale, :yscale, :zscale)
|
||||
if haskey(d, k)
|
||||
v = d[k]
|
||||
v = get(_scaleAliases, v, v)
|
||||
if !(v in supported_scales(pkg))
|
||||
warn("scale $(d[k]) is unsupported with $pkg. Choose from: $(supported_scales(pkg))")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -771,6 +787,7 @@ function convertLegendValue(val::Symbol)
|
||||
end
|
||||
end
|
||||
convertLegendValue(val::Bool) = val ? :best : :none
|
||||
convertLegendValue(val::Void) = :none
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
@@ -896,87 +913,71 @@ end
|
||||
|
||||
# update attr from an input dictionary
|
||||
function _update_plot_args(plt::Plot, d_in::KW)
|
||||
pargs = plt.attr
|
||||
for (k,v) in _plot_defaults
|
||||
slice_arg!(d_in, pargs, k, v)
|
||||
slice_arg!(d_in, plt.attr, k, v)
|
||||
end
|
||||
|
||||
# handle colors
|
||||
bg = convertColor(pargs[:background_color])
|
||||
fg = pargs[:foreground_color]
|
||||
bg = convertColor(plt.attr[:background_color])
|
||||
fg = plt.attr[:foreground_color]
|
||||
if fg == :auto
|
||||
fg = isdark(bg) ? colorant"white" : colorant"black"
|
||||
end
|
||||
pargs[:background_color] = bg
|
||||
pargs[:foreground_color] = convertColor(fg)
|
||||
# color_or_match!(pargs, :background_color_outside, bg)
|
||||
color_or_nothing!(pargs, :background_color_outside)
|
||||
plt.attr[:background_color] = bg
|
||||
plt.attr[:foreground_color] = convertColor(fg)
|
||||
# color_or_match!(plt.attr, :background_color_outside, bg)
|
||||
color_or_nothing!(plt.attr, :background_color_outside)
|
||||
end
|
||||
|
||||
|
||||
# update a subplots args and axes
|
||||
function _update_subplot_args(plt::Plot, sp::Subplot, d_in::KW, subplot_index::Integer; remove_pair = true)
|
||||
pargs = plt.attr
|
||||
spargs = sp.attr
|
||||
anns = pop!(sp.attr, :annotations, [])
|
||||
|
||||
# grab those args which apply to this subplot
|
||||
for (k,v) in _subplot_defaults
|
||||
slice_arg!(d_in, spargs, k, v, subplot_index, remove_pair = remove_pair)
|
||||
slice_arg!(d_in, sp.attr, k, v, subplot_index, remove_pair = remove_pair)
|
||||
end
|
||||
|
||||
# extend annotations
|
||||
sp.attr[:annotations] = vcat(anns, sp[:annotations])
|
||||
|
||||
# handle legend/colorbar
|
||||
spargs[:legend] = convertLegendValue(spargs[:legend])
|
||||
spargs[:colorbar] = convertLegendValue(spargs[:colorbar])
|
||||
if spargs[:colorbar] == :legend
|
||||
spargs[:colorbar] = spargs[:legend]
|
||||
sp.attr[:legend] = convertLegendValue(sp.attr[:legend])
|
||||
sp.attr[:colorbar] = convertLegendValue(sp.attr[:colorbar])
|
||||
if sp.attr[:colorbar] == :legend
|
||||
sp.attr[:colorbar] = sp.attr[:legend]
|
||||
end
|
||||
|
||||
# background colors
|
||||
# bg = color_or_match!(spargs, :background_color_subplot, pargs[:background_color])
|
||||
color_or_nothing!(spargs, :background_color_subplot)
|
||||
bg = sp[:background_color_subplot]
|
||||
spargs[:color_palette] = get_color_palette(spargs[:color_palette], bg, 30)
|
||||
# color_or_match!(spargs, :background_color_legend, bg)
|
||||
color_or_nothing!(spargs, :background_color_legend)
|
||||
# color_or_match!(spargs, :background_color_inside, bg)
|
||||
color_or_nothing!(spargs, :background_color_inside)
|
||||
# bg = color_or_match!(sp.attr, :background_color_subplot, plt.attr[:background_color])
|
||||
color_or_nothing!(sp.attr, :background_color_subplot)
|
||||
bg = convertColor(sp[:background_color_subplot])
|
||||
sp.attr[:color_palette] = get_color_palette(sp.attr[:color_palette], bg, 30)
|
||||
color_or_nothing!(sp.attr, :background_color_legend)
|
||||
color_or_nothing!(sp.attr, :background_color_inside)
|
||||
|
||||
# foreground colors
|
||||
# fg = color_or_match!(spargs, :foreground_color_subplot, pargs[:foreground_color])
|
||||
color_or_nothing!(spargs, :foreground_color_subplot)
|
||||
# color_or_match!(spargs, :foreground_color_legend, fg)
|
||||
color_or_nothing!(spargs, :foreground_color_legend)
|
||||
# color_or_match!(spargs, :foreground_color_grid, fg)
|
||||
color_or_nothing!(spargs, :foreground_color_grid)
|
||||
# color_or_match!(spargs, :foreground_color_title, fg)
|
||||
color_or_nothing!(spargs, :foreground_color_title)
|
||||
color_or_nothing!(sp.attr, :foreground_color_subplot)
|
||||
color_or_nothing!(sp.attr, :foreground_color_legend)
|
||||
color_or_nothing!(sp.attr, :foreground_color_grid)
|
||||
color_or_nothing!(sp.attr, :foreground_color_title)
|
||||
|
||||
# for k in (:left_margin, :top_margin, :right_margin, :bottom_margin)
|
||||
# if spargs[k] == :match
|
||||
# spargs[k] = spargs[:margin]
|
||||
# if sp.attr[k] == :match
|
||||
# sp.attr[k] = sp.attr[:margin]
|
||||
# end
|
||||
# end
|
||||
|
||||
for letter in (:x, :y, :z)
|
||||
# get (maybe initialize) the axis
|
||||
axissym = Symbol(letter, :axis)
|
||||
axis = if haskey(spargs, axissym)
|
||||
spargs[axissym]
|
||||
else
|
||||
spargs[axissym] = Axis(sp, letter)
|
||||
end
|
||||
axis = get_axis(sp, letter)
|
||||
|
||||
# grab magic args (for example `xaxis = (:flip, :log)`)
|
||||
args = wraptuple(get(d_in, axissym, ()))
|
||||
args = wraptuple(get(d_in, Symbol(letter, :axis), ()))
|
||||
|
||||
# build the KW of arguments from the letter version (i.e. xticks --> ticks)
|
||||
kw = KW()
|
||||
# DD(d_in, "d_in before")
|
||||
|
||||
for (k,v) in _axis_defaults
|
||||
# first get the args without the letter: `tickfont = font(10)`
|
||||
# note: we don't pop because we want this to apply to all axes! (delete after all have finished)
|
||||
@@ -987,29 +988,34 @@ function _update_subplot_args(plt::Plot, sp::Subplot, d_in::KW, subplot_index::I
|
||||
# then get those args that were passed with a leading letter: `xlabel = "X"`
|
||||
lk = Symbol(letter, k)
|
||||
if haskey(d_in, lk)
|
||||
kw[k] = slice_arg(pop!(d_in, lk), subplot_index)
|
||||
kw[k] = slice_arg(d_in[lk], subplot_index)
|
||||
end
|
||||
end
|
||||
|
||||
# update the axis
|
||||
update!(axis, args...; kw...)
|
||||
|
||||
# convert a bool into auto or nothing
|
||||
if isa(axis[:ticks], Bool)
|
||||
axis[:ticks] = axis[:ticks] ? :auto : nothing
|
||||
end
|
||||
|
||||
# # update the axis colors
|
||||
# color_or_match!(axis.d, :foreground_color_axis, fg)
|
||||
color_or_nothing!(axis.d, :foreground_color_axis)
|
||||
# color_or_match!(axis.d, :foreground_color_border, fg)
|
||||
color_or_nothing!(axis.d, :foreground_color_border)
|
||||
# color_or_match!(axis.d, :foreground_color_guide, fg)
|
||||
color_or_nothing!(axis.d, :foreground_color_guide)
|
||||
# color_or_match!(axis.d, :foreground_color_text, fg)
|
||||
color_or_nothing!(axis.d, :foreground_color_text)
|
||||
|
||||
# TODO: need to handle linking here?
|
||||
end
|
||||
|
||||
# now we can get rid of the axis keys without a letter
|
||||
for k in keys(_axis_defaults)
|
||||
delete!(d_in, k)
|
||||
# handle linking here. if we're passed a list of
|
||||
# other subplots to link to, link them together
|
||||
link = axis[:link]
|
||||
if !isempty(link)
|
||||
for other_sp in link
|
||||
other_sp = get_subplot(plt, other_sp)
|
||||
link_axes!(axis, get_axis(other_sp, letter))
|
||||
end
|
||||
axis.d[:link] = []
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
+24
-6
@@ -32,6 +32,15 @@ function Axis(sp::Subplot, letter::Symbol, args...; kw...)
|
||||
update!(Axis(sp, d), args...; kw...)
|
||||
end
|
||||
|
||||
function get_axis(sp::Subplot, letter::Symbol)
|
||||
axissym = Symbol(letter, :axis)
|
||||
if haskey(sp.attr, axissym)
|
||||
sp.attr[axissym]
|
||||
else
|
||||
sp.attr[axissym] = Axis(sp, letter)
|
||||
end
|
||||
end
|
||||
|
||||
function process_axis_arg!(d::KW, arg, letter = "")
|
||||
T = typeof(arg)
|
||||
arg = get(_scaleAliases, arg, arg)
|
||||
@@ -91,6 +100,12 @@ function update!(axis::Axis, args...; kw...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# replace scale aliases
|
||||
if haskey(_scaleAliases, d[:scale])
|
||||
d[:scale] = _scaleAliases[d[:scale]]
|
||||
end
|
||||
|
||||
axis
|
||||
end
|
||||
|
||||
@@ -213,12 +228,15 @@ function widen(lmin, lmax)
|
||||
lmin-eps, lmax+eps
|
||||
end
|
||||
|
||||
# figure out if widening is a good idea
|
||||
# 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
|
||||
function default_should_widen(axis::Axis)
|
||||
should_widen = false
|
||||
for series in series_list(axis.sp)
|
||||
if series.d[:seriestype] in (:scatter,) || series.d[:markershape] != :none
|
||||
should_widen = true
|
||||
if axis[:scale] == :identity
|
||||
for series in series_list(axis.sp)
|
||||
if series.d[:seriestype] in (:scatter,) || series.d[:markershape] != :none
|
||||
should_widen = true
|
||||
end
|
||||
end
|
||||
end
|
||||
should_widen
|
||||
@@ -229,7 +247,7 @@ function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis)
|
||||
ex = axis[:extrema]
|
||||
amin, amax = ex.emin, ex.emax
|
||||
lims = axis[:lims]
|
||||
if isa(lims, Tuple) && length(lims) == 2
|
||||
if (isa(lims, Tuple) || isa(lims, AVec)) && length(lims) == 2
|
||||
if isfinite(lims[1])
|
||||
amin = lims[1]
|
||||
end
|
||||
@@ -237,7 +255,7 @@ function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis)
|
||||
amax = lims[2]
|
||||
end
|
||||
end
|
||||
if amax <= amin
|
||||
if amax <= amin && isfinite(amin)
|
||||
amax = amin + 1.0
|
||||
end
|
||||
if should_widen
|
||||
|
||||
+54
-15
@@ -169,22 +169,61 @@ end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
supportedAxes(::AbstractBackend) = [:left]
|
||||
supportedTypes(::AbstractBackend) = []
|
||||
supportedStyles(::AbstractBackend) = [:solid]
|
||||
supportedMarkers(::AbstractBackend) = [:none]
|
||||
supportedScales(::AbstractBackend) = [:identity]
|
||||
subplotSupported(::AbstractBackend) = false
|
||||
stringsSupported(::AbstractBackend) = false
|
||||
nativeImagesSupported(b::AbstractBackend) = :image in supportedTypes(b)
|
||||
supported_types(::AbstractBackend) = []
|
||||
supported_styles(::AbstractBackend) = [:solid]
|
||||
supported_markers(::AbstractBackend) = [:none]
|
||||
supported_scales(::AbstractBackend) = [:identity]
|
||||
is_subplot_supported(::AbstractBackend) = false
|
||||
is_string_supported(::AbstractBackend) = false
|
||||
nativeImagesSupported(b::AbstractBackend) = :image in supported_types(b)
|
||||
|
||||
supportedAxes() = supportedAxes(backend())
|
||||
supportedTypes() = supportedTypes(backend())
|
||||
supportedStyles() = supportedStyles(backend())
|
||||
supportedMarkers() = supportedMarkers(backend())
|
||||
supportedScales() = supportedScales(backend())
|
||||
subplotSupported() = subplotSupported(backend())
|
||||
stringsSupported() = stringsSupported(backend())
|
||||
supported_types() = supported_types(backend())
|
||||
supported_styles() = supported_styles(backend())
|
||||
supported_markers() = supported_markers(backend())
|
||||
supported_scales() = supported_scales(backend())
|
||||
is_subplot_supported() = is_subplot_supported(backend())
|
||||
is_string_supported() = is_string_supported(backend())
|
||||
nativeImagesSupported() = nativeImagesSupported(backend())
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
# these are args which every backend supports because they're not used in the backend code
|
||||
const _base_supported_args = [
|
||||
:color_palette,
|
||||
:background_color, :background_color_subplot,
|
||||
:foreground_color, :foreground_color_subplot,
|
||||
:group,
|
||||
:seriestype,
|
||||
:seriescolor, :seriesalpha,
|
||||
:smooth,
|
||||
:xerror, :yerror,
|
||||
:subplot,
|
||||
:x, :y, :z,
|
||||
:show, :size,
|
||||
:margin,
|
||||
:left_margin,
|
||||
:right_margin,
|
||||
:top_margin,
|
||||
:bottom_margin,
|
||||
:html_output_format,
|
||||
:layout,
|
||||
:link,
|
||||
:primary,
|
||||
:series_annotations,
|
||||
:subplot_index,
|
||||
:discrete_values,
|
||||
:projection,
|
||||
|
||||
]
|
||||
|
||||
function merge_with_base_supported(v::AVec)
|
||||
v = vcat(v, _base_supported_args)
|
||||
for vi in v
|
||||
if haskey(_axis_defaults, vi)
|
||||
for letter in (:x,:y,:z)
|
||||
push!(v, Symbol(letter,vi))
|
||||
end
|
||||
end
|
||||
end
|
||||
v
|
||||
end
|
||||
|
||||
+9
-10
@@ -2,7 +2,7 @@
|
||||
# https://github.com/bokeh/Bokeh.jl
|
||||
|
||||
|
||||
supportedArgs(::BokehBackend) = [
|
||||
supported_args(::BokehBackend) = merge_with_base_supported([
|
||||
# :annotations,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
@@ -58,13 +58,12 @@ supportedArgs(::BokehBackend) = [
|
||||
# :grid,
|
||||
# :surface,
|
||||
# :levels,
|
||||
]
|
||||
supportedAxes(::BokehBackend) = [:auto, :left]
|
||||
supportedTypes(::BokehBackend) = [:none, :path, :scatter] #,:steppre, :steppost, :sticks, :histogram2d, :hexbin, :histogram, :bar, :hline, :vline, :contour]
|
||||
supportedStyles(::BokehBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::BokehBackend) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::BokehBackend) = [:identity, :ln] #, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::BokehBackend) = false
|
||||
])
|
||||
supported_types(::BokehBackend) = [:path, :scatter]
|
||||
supported_styles(::BokehBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supported_markers(::BokehBackend) = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
|
||||
supported_scales(::BokehBackend) = [:identity, :ln]
|
||||
is_subplot_supported(::BokehBackend) = false
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
@@ -81,7 +80,7 @@ end
|
||||
|
||||
|
||||
const _glyphtypes = KW(
|
||||
:ellipse => :Circle,
|
||||
:circle => :Circle,
|
||||
:rect => :Square,
|
||||
:diamond => :Diamond,
|
||||
:utriangle => :Triangle,
|
||||
@@ -100,7 +99,7 @@ function bokeh_glyph_type(d::KW)
|
||||
st = d[:seriestype]
|
||||
mt = d[:markershape]
|
||||
if st == :scatter && mt == :none
|
||||
mt = :ellipse
|
||||
mt = :circle
|
||||
end
|
||||
|
||||
# if we have a marker, use that
|
||||
|
||||
+12
-14
@@ -2,7 +2,7 @@
|
||||
# https://github.com/dcjones/Gadfly.jl
|
||||
|
||||
|
||||
supportedArgs(::GadflyBackend) = [
|
||||
supported_args(::GadflyBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color, :foreground_color, :color_palette,
|
||||
:group, :label, :seriestype,
|
||||
@@ -15,7 +15,6 @@ supportedArgs(::GadflyBackend) = [
|
||||
:title, :window_title, :show, :size,
|
||||
:x, :xguide, :xlims, :xticks, :xscale, :xflip,
|
||||
:y, :yguide, :ylims, :yticks, :yscale, :yflip,
|
||||
# :z, :zguide, :zlims, :zticks, :zscale, :zflip,
|
||||
:z,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, :colorbar,
|
||||
@@ -23,18 +22,17 @@ supportedArgs(::GadflyBackend) = [
|
||||
:xerror, :yerror,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
]
|
||||
supportedAxes(::GadflyBackend) = [:auto, :left]
|
||||
supportedTypes(::GadflyBackend) = [
|
||||
:none, :line, :path, :steppre, :steppost, :sticks,
|
||||
:scatter, :histogram2d, :hexbin, :histogram,
|
||||
:bar, #:box, :violin, :quiver,
|
||||
:hline, :vline, :contour, :shape
|
||||
])
|
||||
supported_types(::GadflyBackend) = [
|
||||
:path,
|
||||
:scatter, :hexbin,
|
||||
:bar,
|
||||
:contour, :shape
|
||||
]
|
||||
supportedStyles(::GadflyBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::GadflyBackend) = vcat(_allMarkers, Shape)
|
||||
supportedScales(::GadflyBackend) = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::GadflyBackend) = true
|
||||
supported_styles(::GadflyBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supported_markers(::GadflyBackend) = vcat(_allMarkers, Shape)
|
||||
supported_scales(::GadflyBackend) = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
is_subplot_supported(::GadflyBackend) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
@@ -303,7 +301,7 @@ function addGadflySeries!(plt::Plot, d::KW)
|
||||
if st in (:histogram2d, :hexbin) && (isa(d[:fillcolor], ColorGradient) || isa(d[:fillcolor], ColorFunction))
|
||||
push!(gplt.scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(d[:fillcolor], p))))
|
||||
elseif st == :scatter && d[:markershape] == :none
|
||||
d[:markershape] = :ellipse
|
||||
d[:markershape] = :circle
|
||||
end
|
||||
|
||||
# markers
|
||||
|
||||
@@ -84,7 +84,7 @@ function make_polygon(geom::ShapeGeometry, xs::AbstractArray, ys::AbstractArray,
|
||||
x = Compose.x_measure(xs[mod1(i, length(xs))])
|
||||
y = Compose.y_measure(ys[mod1(i, length(ys))])
|
||||
r = rs[mod1(i, length(rs))]
|
||||
polys[i] = T[(x + r * sx, y + r * sy) for (sx,sy) in get_mod(geom.vertices, i)]
|
||||
polys[i] = T[(x + r * sx, y + r * sy) for (sx,sy) in cycle(geom.vertices, i)]
|
||||
end
|
||||
Gadfly.polygon(polys, geom.tag)
|
||||
end
|
||||
|
||||
+66
-106
@@ -2,78 +2,47 @@
|
||||
|
||||
# [WEBSITE]
|
||||
|
||||
supportedArgs(::GLVisualizeBackend) = [
|
||||
supported_args(::GLVisualizeBackend) = merge_with_base_supported([
|
||||
# :annotations,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
# :color_palette,
|
||||
# :fillrange,
|
||||
# :fillcolor,
|
||||
# :fillalpha,
|
||||
# :foreground_color,
|
||||
# :group,
|
||||
# :background_color_legend, :background_color_inside, :background_color_outside,
|
||||
# :foreground_color_grid, :foreground_color_legend, :foreground_color_title,
|
||||
# :foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
|
||||
# :label,
|
||||
# :layout,
|
||||
# :legend,
|
||||
# :linecolor,
|
||||
# :linestyle,
|
||||
:seriestype
|
||||
# :seriescolor, :seriesalpha,
|
||||
# :linewidth,
|
||||
# :linealpha,
|
||||
# :markershape,
|
||||
# :markercolor,
|
||||
# :markersize,
|
||||
# :markeralpha,
|
||||
# :markerstrokewidth,
|
||||
# :markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
# :n,
|
||||
# :bins,
|
||||
# :nc,
|
||||
# :nr,
|
||||
# :pos,
|
||||
# :smooth,
|
||||
# :show,
|
||||
# :size,
|
||||
# :title,
|
||||
# :linecolor, :linestyle, :linewidth, :linealpha,
|
||||
# :markershape, :markercolor, :markersize, :markeralpha,
|
||||
# :markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
# :fillrange, :fillcolor, :fillalpha,
|
||||
# :bins, :bar_width, :bar_edges, :bar_position,
|
||||
# :title, :title_location, :titlefont,
|
||||
# :window_title,
|
||||
# :x,
|
||||
# :xguide,
|
||||
# :xlims,
|
||||
# :xticks,
|
||||
# :y,
|
||||
# :yguide,
|
||||
# :ylims,
|
||||
# :yrightlabel,
|
||||
# :yticks,
|
||||
# :xscale,
|
||||
# :yscale,
|
||||
# :xflip,
|
||||
# :yflip,
|
||||
# :z,
|
||||
# :tickfont,
|
||||
# :guidefont,
|
||||
# :legendfont,
|
||||
# :grid,
|
||||
# :surface
|
||||
# :levels,
|
||||
]
|
||||
supportedAxes(::GLVisualizeBackend) = [:auto, :left]
|
||||
supportedTypes(::GLVisualizeBackend) = [:surface] #, :path, :scatter ,:steppre, :steppost, :sticks, :heatmap, :hexbin, :histogram, :bar, :hline, :vline, :contour]
|
||||
supportedStyles(::GLVisualizeBackend) = [:auto, :solid] #, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::GLVisualizeBackend) = [:none, :auto, :ellipse] #, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::GLVisualizeBackend) = [:identity] #, :log, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::GLVisualizeBackend) = false
|
||||
# :guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
# :tickfont, :guidefont, :legendfont,
|
||||
# :grid, :legend, :colorbar,
|
||||
# :marker_z, :levels,
|
||||
# :ribbon, :quiver, :arrow,
|
||||
# :orientation,
|
||||
# :overwrite_figure,
|
||||
# :polar,
|
||||
# :normalize, :weights,
|
||||
# :contours, :aspect_ratio,
|
||||
# :match_dimensions,
|
||||
# :clims,
|
||||
# :inset_subplots,
|
||||
])
|
||||
supported_types(::GLVisualizeBackend) = [:surface]
|
||||
supported_styles(::GLVisualizeBackend) = [:auto, :solid]
|
||||
supported_markers(::GLVisualizeBackend) = [:none, :auto, :circle]
|
||||
supported_scales(::GLVisualizeBackend) = [:identity]
|
||||
is_subplot_supported(::GLVisualizeBackend) = false
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function _initialize_backend(::GLVisualizeBackend; kw...)
|
||||
@eval begin
|
||||
import GLVisualize
|
||||
export GLVisualize
|
||||
end
|
||||
@eval begin
|
||||
import GLVisualize
|
||||
export GLVisualize
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -82,55 +51,46 @@ immutable GLScreenWrapper
|
||||
window
|
||||
end
|
||||
|
||||
# function _create_plot(pkg::GLVisualizeBackend, d::KW)
|
||||
function _create_backend_figure(plt::Plot{GLVisualizeBackend})
|
||||
# TODO: create the window/canvas/context that is the plot within the backend
|
||||
# TODO: initialize the plot... title, xlabel, bgcolor, etc
|
||||
# init a window
|
||||
window = GLVisualize.glscreen()
|
||||
@async GLVisualize.renderloop(window)
|
||||
window
|
||||
end
|
||||
|
||||
# TODO: this should be moved to the display method?
|
||||
w=GLVisualize.glscreen()
|
||||
@async GLVisualize.renderloop(w)
|
||||
GLScreenWrapper(w)
|
||||
# Plot(GLScreenWrapper(w), pkg, 0, d, KW[])
|
||||
function gl_display(plt::Plot{GLVisualizeBackend})
|
||||
for sp in plt.subplots
|
||||
# TODO: setup subplot
|
||||
|
||||
for series in series_list(sp)
|
||||
# TODO: setup series
|
||||
d = series.d
|
||||
st = d[:seriestype]
|
||||
x, y, z = map(Float32, d[:x]), map(Float32, d[:y]), d[:z]
|
||||
|
||||
if st == :surface
|
||||
ismatrix(x) || (x = repmat(x', length(y), 1))
|
||||
ismatrix(y) || (y = repmat(y, 1, length(x)))
|
||||
z = transpose_z(d, map(Float32, z.surf), false)
|
||||
viz = GLVisualize.visualize((x, y, z), :surface)
|
||||
GLVisualize.view(viz, plt.o)
|
||||
return
|
||||
|
||||
else
|
||||
error("Series type $st not supported by GLVisualize")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _series_added(plt::Plot{GLVisualizeBackend}, series::Series)
|
||||
# TODO: add one series to the underlying package
|
||||
# TODO: this should be moved to the display method?
|
||||
x, y, z = map(Float32, series.d[:x]), map(Float32, series.d[:y]), map(Float32, series.d[:z].surf)
|
||||
GLVisualize.view(GLVisualize.visualize((x*ones(y)', ones(x)*y', z), :surface), plt.o.window)
|
||||
# plt
|
||||
end
|
||||
|
||||
|
||||
# When series data is added/changed, this callback can do dynamic updates to the backend object.
|
||||
# note: if the backend rebuilds the plot from scratch on display, then you might not do anything here.
|
||||
function _series_updated(plt::Plot{GLVisualizeBackend}, series::Series)
|
||||
# TODO
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
# Override this to update plot items (title, xlabel, etc), and add annotations (d[:annotations])
|
||||
function _update_plot_object(plt::Plot{GLVisualizeBackend})
|
||||
# TODO
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{GLVisualizeBackend})
|
||||
# TODO: write a png to io
|
||||
end
|
||||
# function _writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{GLVisualizeBackend})
|
||||
# # TODO: write a png to io
|
||||
# end
|
||||
|
||||
function _display(plt::Plot{GLVisualizeBackend})
|
||||
# TODO: display/show the plot
|
||||
|
||||
# NOTE: I think maybe this should be empty? We can start with the assumption that creating
|
||||
# and adding to a plot will automatically open a window and draw to it, then the display
|
||||
# wouldn't actually need to do anything
|
||||
gl_display(plt)
|
||||
end
|
||||
|
||||
+275
-747
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,12 @@
|
||||
|
||||
# https://github.com/JuliaGraphics/Immerse.jl
|
||||
|
||||
supportedArgs(::ImmerseBackend) = supportedArgs(GadflyBackend())
|
||||
supportedAxes(::ImmerseBackend) = supportedAxes(GadflyBackend())
|
||||
supportedTypes(::ImmerseBackend) = supportedTypes(GadflyBackend())
|
||||
supportedStyles(::ImmerseBackend) = supportedStyles(GadflyBackend())
|
||||
supportedMarkers(::ImmerseBackend) = supportedMarkers(GadflyBackend())
|
||||
supportedScales(::ImmerseBackend) = supportedScales(GadflyBackend())
|
||||
subplotSupported(::ImmerseBackend) = true
|
||||
supported_args(::ImmerseBackend) = supported_args(GadflyBackend())
|
||||
supported_types(::ImmerseBackend) = supported_types(GadflyBackend())
|
||||
supported_styles(::ImmerseBackend) = supported_styles(GadflyBackend())
|
||||
supported_markers(::ImmerseBackend) = supported_markers(GadflyBackend())
|
||||
supported_scales(::ImmerseBackend) = supported_scales(GadflyBackend())
|
||||
is_subplot_supported(::ImmerseBackend) = true
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
+62
-37
@@ -2,39 +2,28 @@
|
||||
|
||||
# significant contributions by: @pkofod
|
||||
|
||||
supportedArgs(::PGFPlotsBackend) = [
|
||||
supported_args(::PGFPlotsBackend) = merge_with_base_supported([
|
||||
# :annotations,
|
||||
:background_color, :foreground_color,
|
||||
:color_palette,
|
||||
# :background_color_legend,
|
||||
:background_color_inside,
|
||||
# :background_color_outside,
|
||||
# :foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
|
||||
# :foreground_color_text, :foreground_color_border,
|
||||
:group,
|
||||
:label,
|
||||
:seriestype,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins,
|
||||
# :bar_width, :bar_edges,
|
||||
# :n, :nc, :nr,
|
||||
:layout,
|
||||
# :smooth,
|
||||
: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,
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend,
|
||||
# :colorbar,
|
||||
# :marker_z, :levels,
|
||||
# :xerror, :yerror,
|
||||
# :ribbon, :quiver, :arrow,
|
||||
# :orientation,
|
||||
# :overwrite_figure,
|
||||
@@ -42,23 +31,22 @@ supportedArgs(::PGFPlotsBackend) = [
|
||||
# :normalize, :weights, :contours,
|
||||
:aspect_ratio,
|
||||
# :match_dimensions,
|
||||
]
|
||||
supportedAxes(::PGFPlotsBackend) = [:auto, :left]
|
||||
supportedTypes(::PGFPlotsBackend) = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour]
|
||||
supportedStyles(::PGFPlotsBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::PGFPlotsBackend) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::PGFPlotsBackend) = [:identity, :ln, :log2, :log10] # :asinh, :sqrt]
|
||||
subplotSupported(::PGFPlotsBackend) = false
|
||||
])
|
||||
supported_types(::PGFPlotsBackend) = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour]
|
||||
supported_styles(::PGFPlotsBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supported_markers(::PGFPlotsBackend) = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon] #vcat(_allMarkers, Shape)
|
||||
supported_scales(::PGFPlotsBackend) = [:identity, :ln, :log2, :log10]
|
||||
is_subplot_supported(::PGFPlotsBackend) = false
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function _initialize_backend(::PGFPlotsBackend; kw...)
|
||||
@eval begin
|
||||
import PGFPlots
|
||||
export PGFPlots
|
||||
end
|
||||
@eval begin
|
||||
import PGFPlots
|
||||
export PGFPlots
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -78,7 +66,7 @@ const _pgfplots_markers = KW(
|
||||
:xcross => "x",
|
||||
:utriangle => "triangle*",
|
||||
:dtriangle => "triangle*",
|
||||
:ellipse => "*",
|
||||
:circle => "*",
|
||||
:rect => "square*",
|
||||
:star5 => "star",
|
||||
:star6 => "asterisk",
|
||||
@@ -145,7 +133,6 @@ end
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function pgf_series(sp::Subplot, series::Series)
|
||||
d = series.d
|
||||
st = d[:seriestype]
|
||||
@@ -173,6 +160,18 @@ function pgf_series(sp::Subplot, series::Series)
|
||||
d[:x], d[:y]
|
||||
end
|
||||
|
||||
# PGFPlots can't handle non-Vector?
|
||||
args = map(a -> if typeof(a) <: AbstractVector && typeof(a) != Vector
|
||||
collect(a)
|
||||
else
|
||||
a
|
||||
end, args)
|
||||
# for (i,a) in enumerate(args)
|
||||
# if typeof(a) <: AbstractVector && typeof(a) != Vector
|
||||
# args[i] = collect(a)
|
||||
# end
|
||||
# end
|
||||
|
||||
# include additional style, then add to the kw
|
||||
if haskey(_pgf_series_extrastyle, st)
|
||||
push!(style, _pgf_series_extrastyle[st])
|
||||
@@ -216,9 +215,12 @@ function pgf_axis(sp::Subplot, letter)
|
||||
end
|
||||
|
||||
# limits
|
||||
lims = axis_limits(axis)
|
||||
kw[Symbol(letter,:min)] = lims[1]
|
||||
kw[Symbol(letter,:max)] = lims[2]
|
||||
# TODO: support zlims
|
||||
if letter != :z
|
||||
lims = axis_limits(axis)
|
||||
kw[Symbol(letter,:min)] = lims[1]
|
||||
kw[Symbol(letter,:max)] = lims[2]
|
||||
end
|
||||
|
||||
# return the style list and KW args
|
||||
style, kw
|
||||
@@ -281,16 +283,39 @@ end
|
||||
|
||||
|
||||
function _writemime(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsBackend})
|
||||
_make_pgf_plot!(plt)
|
||||
writemime(io, mime, plt.o)
|
||||
_make_pgf_plot!(plt)
|
||||
writemime(io, mime, plt.o)
|
||||
end
|
||||
|
||||
function _writemime(io::IO, mime::MIME"image/png", plt::Plot{PGFPlotsBackend})
|
||||
_make_pgf_plot!(plt)
|
||||
writemime(io, mime, plt.o)
|
||||
function _writemime(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsBackend})
|
||||
_make_pgf_plot!(plt)
|
||||
|
||||
# prepare the object
|
||||
pgfplt = PGFPlots.plot(plt.o)
|
||||
|
||||
# save a pdf
|
||||
fn = tempname()*".pdf"
|
||||
PGFPlots.save(PGFPlots.PDF(fn), pgfplt)
|
||||
|
||||
# read it into io
|
||||
write(io, readall(open(fn)))
|
||||
|
||||
# cleanup
|
||||
PGFPlots.cleanup(plt.o)
|
||||
end
|
||||
|
||||
function _display(plt::Plot{PGFPlotsBackend})
|
||||
_make_pgf_plot!(plt)
|
||||
display(plt.o)
|
||||
# prepare the object
|
||||
_make_pgf_plot!(plt)
|
||||
pgfplt = PGFPlots.plot(plt.o)
|
||||
|
||||
# save an svg
|
||||
fn = string(tempname(), ".svg")
|
||||
PGFPlots.save(PGFPlots.SVG(fn), pgfplt)
|
||||
|
||||
# show it
|
||||
open_browser_window(fn)
|
||||
|
||||
# cleanup
|
||||
PGFPlots.cleanup(plt.o)
|
||||
end
|
||||
|
||||
+133
-106
@@ -1,49 +1,48 @@
|
||||
|
||||
# https://plot.ly/javascript/getting-started
|
||||
|
||||
supportedArgs(::PlotlyBackend) = [
|
||||
supported_args(::PlotlyBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color, :foreground_color, :color_palette,
|
||||
# :background_color_legend, :background_color_inside, :background_color_outside,
|
||||
# :foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
|
||||
# :foreground_color_text, :foreground_color_border,
|
||||
:group,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_legend, :foreground_color_guide,
|
||||
# :foreground_color_grid, :foreground_color_axis,
|
||||
:foreground_color_text, :foreground_color_border,
|
||||
:foreground_color_title,
|
||||
:label,
|
||||
:seriestype,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins,
|
||||
:n, :nc, :nr, :layout,
|
||||
# :smooth,
|
||||
: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,
|
||||
:z,
|
||||
:title, :title_location, :titlefont,
|
||||
:window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, :colorbar,
|
||||
:marker_z, :levels,
|
||||
:xerror, :yerror,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
# :overwrite_figure,
|
||||
:polar,
|
||||
# :normalize, :weights, :contours, :aspect_ratio
|
||||
]
|
||||
:normalize, :weights,
|
||||
# :contours, :aspect_ratio,
|
||||
:hover,
|
||||
:inset_subplots,
|
||||
])
|
||||
|
||||
supportedAxes(::PlotlyBackend) = [:auto, :left]
|
||||
supportedTypes(::PlotlyBackend) = [:none, :line, :path, :scatter, :steppre, :steppost,
|
||||
:histogram2d, :histogram, :density, :bar, :contour, :surface, :path3d, :scatter3d,
|
||||
:pie, :heatmap] #,, :sticks, :hexbin, :hline, :vline]
|
||||
supportedStyles(::PlotlyBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supportedMarkers(::PlotlyBackend) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross,
|
||||
:pentagon, :hexagon, :octagon, :vline, :hline] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::PlotlyBackend) = [:identity, :log10] #, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::PlotlyBackend) = true
|
||||
stringsSupported(::PlotlyBackend) = true
|
||||
supported_types(::PlotlyBackend) = [
|
||||
:path, :scatter, :bar, :pie, :heatmap,
|
||||
:contour, :surface, :path3d, :scatter3d, :shape, :scattergl,
|
||||
]
|
||||
supported_styles(::PlotlyBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supported_markers(::PlotlyBackend) = [
|
||||
:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle,
|
||||
:cross, :xcross, :pentagon, :hexagon, :octagon, :vline, :hline
|
||||
]
|
||||
supported_scales(::PlotlyBackend) = [:identity, :log10]
|
||||
is_subplot_supported(::PlotlyBackend) = true
|
||||
is_string_supported(::PlotlyBackend) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
@@ -85,7 +84,7 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function plotlyfont(font::Font, color = font.color)
|
||||
function plotly_font(font::Font, color = font.color)
|
||||
KW(
|
||||
:family => font.family,
|
||||
:size => round(Int, font.pointsize*1.4),
|
||||
@@ -93,20 +92,20 @@ function plotlyfont(font::Font, color = font.color)
|
||||
)
|
||||
end
|
||||
|
||||
function get_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 get_annotation_dict(x, y, ptxt::PlotText)
|
||||
merge(get_annotation_dict(x, y, ptxt.str), KW(
|
||||
:font => plotlyfont(ptxt.font),
|
||||
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,
|
||||
:rotation => ptxt.font.rotation,
|
||||
@@ -136,7 +135,7 @@ end
|
||||
# )
|
||||
# end
|
||||
|
||||
function plotlyscale(scale::Symbol)
|
||||
function plotly_scale(scale::Symbol)
|
||||
if scale == :log10
|
||||
"log"
|
||||
else
|
||||
@@ -144,7 +143,6 @@ function plotlyscale(scale::Symbol)
|
||||
end
|
||||
end
|
||||
|
||||
use_axis_field(ticks) = !(ticks in (nothing, :none))
|
||||
|
||||
# this method gets the start/end in percentage of the canvas for this axis direction
|
||||
function plotly_domain(sp::Subplot, letter)
|
||||
@@ -157,19 +155,12 @@ end
|
||||
|
||||
function plotly_axis(axis::Axis, sp::Subplot)
|
||||
letter = axis[:letter]
|
||||
# d = axis.d
|
||||
ax = KW(
|
||||
:title => axis[:guide],
|
||||
:showgrid => sp[:grid],
|
||||
:zeroline => false,
|
||||
)
|
||||
|
||||
# fgcolor = webcolor(axis[:foreground_color])
|
||||
# tsym = tickssym(letter)
|
||||
|
||||
# spidx = sp[:subplot_index]
|
||||
# d_out[:xaxis] = "x$spidx"
|
||||
# d_out[:yaxis] = "y$spidx"
|
||||
if letter in (:x,:y)
|
||||
ax[:domain] = plotly_domain(sp, letter)
|
||||
ax[:anchor] = "$(letter==:x ? :y : :x)$(plotly_subplot_index(sp))"
|
||||
@@ -180,10 +171,10 @@ function plotly_axis(axis::Axis, sp::Subplot)
|
||||
ax[:tickangle] = rot
|
||||
end
|
||||
|
||||
if use_axis_field(axis[:ticks])
|
||||
ax[:titlefont] = plotlyfont(axis[:guidefont], webcolor(axis[:foreground_color_guide]))
|
||||
ax[:type] = plotlyscale(axis[:scale])
|
||||
ax[:tickfont] = plotlyfont(axis[:tickfont], webcolor(axis[:foreground_color_text]))
|
||||
if !(axis[:ticks] in (nothing, :none))
|
||||
ax[:titlefont] = plotly_font(axis[:guidefont], axis[:foreground_color_guide])
|
||||
ax[:type] = plotly_scale(axis[:scale])
|
||||
ax[:tickfont] = plotly_font(axis[:tickfont], axis[:foreground_color_text])
|
||||
ax[:tickcolor] = webcolor(axis[:foreground_color_border])
|
||||
ax[:linecolor] = webcolor(axis[:foreground_color_border])
|
||||
|
||||
@@ -218,32 +209,35 @@ function plotly_axis(axis::Axis, sp::Subplot)
|
||||
ax
|
||||
end
|
||||
|
||||
# function plotly_layout_json(plt::Plot{PlotlyBackend})
|
||||
# d = plt
|
||||
# function plotly_layout(d::KW, seriesargs::AVec{KW})
|
||||
function plotly_layout(plt::Plot)
|
||||
d_out = KW()
|
||||
|
||||
# # for now, we only support 1 subplot
|
||||
# if length(plt.subplots) > 1
|
||||
# warn("Subplots not supported yet")
|
||||
# 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] = plotlyfont(sp[:titlefont], webcolor(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)
|
||||
# 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] != ""
|
||||
bb = plotarea(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(bbox(sp)), 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,17 +261,12 @@ function plotly_layout(plt::Plot)
|
||||
d_out[:legend] = KW(
|
||||
:bgcolor => webcolor(sp[:background_color_legend]),
|
||||
:bordercolor => webcolor(sp[:foreground_color_legend]),
|
||||
:font => plotlyfont(sp[:legendfont]),
|
||||
:font => plotly_font(sp[:legendfont], sp[:foreground_color_legend]),
|
||||
)
|
||||
end
|
||||
|
||||
# annotations
|
||||
anns = sp[:annotations]
|
||||
d_out[:annotations] = if isempty(anns)
|
||||
KW[]
|
||||
else
|
||||
KW[get_annotation_dict(ann...) for ann in anns]
|
||||
end
|
||||
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
|
||||
@@ -288,8 +277,6 @@ function plotly_layout(plt::Plot)
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# dumpdict(d_out,"",true)
|
||||
# @show d_out[:annotations]
|
||||
|
||||
if ispolar(sp)
|
||||
d_out[:direction] = "counterclockwise"
|
||||
@@ -298,6 +285,11 @@ function plotly_layout(plt::Plot)
|
||||
d_out
|
||||
end
|
||||
|
||||
# turn off hover if nothing's using it
|
||||
if all(series -> series.d[:hover] in (false,:none), plt.series_list)
|
||||
d_out[:hovermode] = "none"
|
||||
end
|
||||
|
||||
d_out
|
||||
end
|
||||
|
||||
@@ -327,6 +319,17 @@ function plotly_subplot_index(sp::Subplot)
|
||||
end
|
||||
|
||||
|
||||
# the Shape contructor will automatically close the shape. since we need it closed,
|
||||
# we split by NaNs and then construct/destruct the shapes to get the closed coords
|
||||
function plotly_close_shapes(x, y)
|
||||
xs, ys = nansplit(x), nansplit(y)
|
||||
for i=1:length(xs)
|
||||
shape = Shape(xs[i], ys[i])
|
||||
xs[i], ys[i] = shape_coords(shape)
|
||||
end
|
||||
nanvcat(xs), nanvcat(ys)
|
||||
end
|
||||
|
||||
# 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)
|
||||
d = series.d
|
||||
@@ -337,17 +340,19 @@ 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]
|
||||
st = d[:seriestype]
|
||||
isscatter = st in (:scatter, :scatter3d)
|
||||
isscatter = st in (:scatter, :scatter3d, :scattergl)
|
||||
hasmarker = isscatter || d[:markershape] != :none
|
||||
hasline = !isscatter
|
||||
# hasline = !isscatter
|
||||
hasline = st in (:path, :path3d)
|
||||
|
||||
# set the "type"
|
||||
if st in (:line, :path, :scatter, :steppre, :steppost)
|
||||
d_out[:type] = "scatter"
|
||||
if st in (:path, :scatter, :scattergl)
|
||||
d_out[:type] = st==:scattergl ? "scattergl" : "scatter"
|
||||
d_out[:mode] = if hasmarker
|
||||
hasline ? "lines+markers" : "markers"
|
||||
else
|
||||
@@ -361,42 +366,58 @@ function plotly_series(plt::Plot, series::Series)
|
||||
end
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
|
||||
elseif st == :shape
|
||||
# to draw polygons, we actually draw lines with fill
|
||||
d_out[:type] = "scatter"
|
||||
d_out[:mode] = "lines"
|
||||
d_out[:x], d_out[:y] = plotly_close_shapes(x, y)
|
||||
# @show map(length, (x,y,d_out[:x],d_out[:y]))
|
||||
# @show d_out[:x] d_out[:y]
|
||||
d_out[:fill] = "tozeroy"
|
||||
d_out[:fillcolor] = webcolor(d[:markercolor], d[:markeralpha])
|
||||
if d[:markerstrokewidth] > 0
|
||||
d_out[:line] = KW(
|
||||
:color => webcolor(d[:markerstrokecolor], d[:markerstrokealpha]),
|
||||
:width => d[:markerstrokewidth],
|
||||
:dash => string(d[:markerstrokestyle]),
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
|
||||
elseif st == :bar
|
||||
d_out[:type] = "bar"
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
d_out[:orientation] = isvertical(d) ? "v" : "h"
|
||||
|
||||
elseif st == :histogram2d
|
||||
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[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha])
|
||||
# elseif st == :histogram2d
|
||||
# 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[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha])
|
||||
|
||||
elseif st in (:histogram, :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[:histogramnorm] = "probability density"
|
||||
end
|
||||
# elseif st in (:histogram, :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[:histogramnorm] = "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[:x], d_out[:y], d_out[:z] = d[:x], d[:y], transpose_z(d, d[:z].surf, false)
|
||||
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[:x], d_out[:y], d_out[:z] = d[:x], d[:y], transpose_z(d, d[:z].surf, false)
|
||||
# d_out[:showscale] = d[:colorbar] != :none
|
||||
d_out[:ncontours] = d[:levels]
|
||||
@@ -405,8 +426,6 @@ function plotly_series(plt::Plot, series::Series)
|
||||
|
||||
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[:x], d_out[:y], d_out[:z] = d[:x], d[:y], transpose_z(d, d[:z].surf, false)
|
||||
d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha])
|
||||
|
||||
@@ -478,6 +497,15 @@ function plotly_series(plt::Plot, series::Series)
|
||||
d_out[:r] = pop!(d_out, :y)
|
||||
end
|
||||
|
||||
# hover text
|
||||
hover = d[:hover]
|
||||
if hover in (:none, false)
|
||||
d_out[:hoverinfo] = "none"
|
||||
elseif hover != nothing
|
||||
d_out[:hoverinfo] = "text"
|
||||
d_out[:text] = hover
|
||||
end
|
||||
|
||||
d_out
|
||||
end
|
||||
|
||||
@@ -523,11 +551,10 @@ function _writemime(io::IO, ::MIME"image/png", plt::Plot{PlotlyBackend})
|
||||
writemime_png_from_html(io, plt)
|
||||
end
|
||||
|
||||
function _writemime(io::IO, ::MIME"text/html", plt::Plot{PlotlyBackend})
|
||||
function _writemime(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyBackend})
|
||||
write(io, html_head(plt) * html_body(plt))
|
||||
end
|
||||
|
||||
# function Base.display(::PlotsDisplay, plt::Plot{PlotlyBackend})
|
||||
function _display(plt::Plot{PlotlyBackend})
|
||||
standalone_html_window(plt)
|
||||
end
|
||||
|
||||
+13
-125
@@ -1,79 +1,12 @@
|
||||
|
||||
# https://github.com/spencerlyon2/PlotlyJS.jl
|
||||
|
||||
supportedArgs(::PlotlyJSBackend) = [
|
||||
:annotation,
|
||||
# :axis,
|
||||
:background_color,
|
||||
:color_palette,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
:fillalpha,
|
||||
:foreground_color,
|
||||
:group,
|
||||
:label,
|
||||
:layout,
|
||||
:legend,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor,
|
||||
:linestyle,
|
||||
:seriestype,
|
||||
:linewidth,
|
||||
:linealpha,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
:markeralpha,
|
||||
:markerstrokewidth,
|
||||
:markerstrokecolor,
|
||||
:markerstrokestyle,
|
||||
:n,
|
||||
:bins,
|
||||
:nc,
|
||||
:nr,
|
||||
# :pos,
|
||||
# :smooth,
|
||||
:show,
|
||||
:size,
|
||||
:title,
|
||||
:window_title,
|
||||
:x,
|
||||
:xguide,
|
||||
:xlims,
|
||||
:xticks,
|
||||
:y,
|
||||
:yguide,
|
||||
:ylims,
|
||||
# :yrightlabel,
|
||||
:yticks,
|
||||
:xscale,
|
||||
:yscale,
|
||||
:xflip,
|
||||
:yflip,
|
||||
:z,
|
||||
:marker_z,
|
||||
:tickfont,
|
||||
:guidefont,
|
||||
:legendfont,
|
||||
:grid,
|
||||
:levels,
|
||||
:xerror,
|
||||
:yerror,
|
||||
:ribbon,
|
||||
:quiver,
|
||||
:orientation,
|
||||
:polar,
|
||||
]
|
||||
supportedAxes(::PlotlyJSBackend) = [:auto, :left]
|
||||
supportedTypes(::PlotlyJSBackend) = [:none, :line, :path, :scatter, :steppre, :steppost,
|
||||
:histogram2d, :histogram, :density, :bar, :contour, :surface, :path3d, :scatter3d,
|
||||
:pie, :heatmap] #,, :sticks, :hexbin, :hline, :vline]
|
||||
supportedStyles(::PlotlyJSBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supportedMarkers(::PlotlyJSBackend) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross,
|
||||
:pentagon, :hexagon, :octagon, :vline, :hline] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::PlotlyJSBackend) = [:identity, :log10] #, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::PlotlyJSBackend) = true
|
||||
stringsSupported(::PlotlyJSBackend) = true
|
||||
supported_args(::PlotlyJSBackend) = supported_args(PlotlyBackend())
|
||||
supported_types(::PlotlyJSBackend) = supported_types(PlotlyBackend())
|
||||
supported_styles(::PlotlyJSBackend) = supported_styles(PlotlyBackend())
|
||||
supported_markers(::PlotlyJSBackend) = supported_markers(PlotlyBackend())
|
||||
is_subplot_supported(::PlotlyJSBackend) = true
|
||||
is_string_supported(::PlotlyJSBackend) = true
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
@@ -83,30 +16,14 @@ function _initialize_backend(::PlotlyJSBackend; kw...)
|
||||
export PlotlyJS
|
||||
end
|
||||
|
||||
for (mime, fmt) in PlotlyJS._mimeformats
|
||||
# mime == "image/png" && continue # don't use plotlyjs's writemime for png
|
||||
@eval Base.writemime(io::IO, m::MIME{Symbol($mime)}, p::Plot{PlotlyJSBackend}) = writemime(io, m, p.o)
|
||||
end
|
||||
|
||||
# override IJulia inline display
|
||||
if isijulia()
|
||||
IJulia.display_dict(plt::AbstractPlot{PlotlyJSBackend}) = IJulia.display_dict(plt.o)
|
||||
end
|
||||
# # override IJulia inline display
|
||||
# if isijulia()
|
||||
# IJulia.display_dict(plt::AbstractPlot{PlotlyJSBackend}) = IJulia.display_dict(plt.o)
|
||||
# end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# function _create_plot(pkg::PlotlyJSBackend, d::KW)
|
||||
# # TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
|
||||
# # TODO: initialize the plot... title, xlabel, bgcolor, etc
|
||||
# # o = PlotlyJS.Plot(PlotlyJS.GenericTrace[], PlotlyJS.Layout(),
|
||||
# # Base.Random.uuid4(), PlotlyJS.ElectronDisplay())
|
||||
# # T = isijulia() ? PlotlyJS.JupyterPlot : PlotlyJS.ElectronPlot
|
||||
# # o = T(PlotlyJS.Plot())
|
||||
# o = PlotlyJS.plot()
|
||||
#
|
||||
# Plot(o, pkg, 0, d, KW[])
|
||||
# end
|
||||
|
||||
function _create_backend_figure(plt::Plot{PlotlyJSBackend})
|
||||
PlotlyJS.plot()
|
||||
@@ -133,47 +50,19 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# TODO: override this to update plot items (title, xlabel, etc) after creation
|
||||
function _update_plot_object(plt::Plot{PlotlyJSBackend})
|
||||
pdict = plotly_layout(plt)
|
||||
syncplot = plt.o
|
||||
w,h = plt[:size]
|
||||
# DD(pdict)
|
||||
PlotlyJS.relayout!(syncplot, pdict, width = w, height = h)
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# accessors for x/y data
|
||||
|
||||
# function getxy(plt::Plot{PlotlyJSBackend}, i::Int)
|
||||
# d = plt.seriesargs[i]
|
||||
# d[:x], d[:y]
|
||||
# end
|
||||
|
||||
# function setxy!{X,Y}(plt::Plot{PlotlyJSBackend}, xy::Tuple{X,Y}, i::Integer)
|
||||
# d = plt.seriesargs[i]
|
||||
# ispolar = get(plt.attr, :polar, false)
|
||||
# xsym = ispolar ? :t : :x
|
||||
# ysym = ispolar ? :r : :y
|
||||
# d[xsym], d[ysym] = xy
|
||||
# # TODO: this is likely ineffecient... we should make a call that ONLY changes the plot data
|
||||
# PlotlyJS.restyle!(plt.o, i, KW(xsym=>(d[xsym],), ysym=>(d[ysym],)))
|
||||
# plt
|
||||
# end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
# function _update_min_padding!(sp::Subplot{PlotlyBackend})
|
||||
# sp.minpad = plotly_minpad(sp)
|
||||
# end
|
||||
|
||||
# function plotlyjs_finalize(plt::Plot)
|
||||
# plotly_finalize(plt)
|
||||
# PlotlyJS.relayout!(plt.o, plotly_layout(plt))
|
||||
# end
|
||||
function _writemime(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend})
|
||||
writemime(io, MIME("text/html"), plt.o)
|
||||
end
|
||||
|
||||
function _writemime(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend})
|
||||
tmpfn = tempname() * "png"
|
||||
@@ -182,6 +71,5 @@ function _writemime(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend})
|
||||
end
|
||||
|
||||
function _display(plt::Plot{PlotlyJSBackend})
|
||||
# plotlyjs_finalize(plt)
|
||||
display(plt.o)
|
||||
end
|
||||
|
||||
+236
-248
@@ -2,54 +2,44 @@
|
||||
# https://github.com/stevengj/PyPlot.jl
|
||||
|
||||
|
||||
supportedArgs(::PyPlotBackend) = [
|
||||
supported_args(::PyPlotBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color, :foreground_color, :color_palette,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
|
||||
:foreground_color_text, :foreground_color_border,
|
||||
:group,
|
||||
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
|
||||
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
|
||||
:label,
|
||||
:seriestype,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins, :bar_width, :bar_edges,
|
||||
:n, :nc, :nr, :layout,
|
||||
:smooth,
|
||||
: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,
|
||||
:bins, :bar_width, :bar_edges, :bar_position,
|
||||
:title, :title_location, :titlefont,
|
||||
:window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, :colorbar,
|
||||
:marker_z, :levels,
|
||||
:xerror, :yerror,
|
||||
:ribbon, :quiver, :arrow,
|
||||
:orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
:normalize, :weights, :contours, :aspect_ratio,
|
||||
:normalize, :weights,
|
||||
:contours, :aspect_ratio,
|
||||
:match_dimensions,
|
||||
:subplot,
|
||||
]
|
||||
supportedAxes(::PyPlotBackend) = _allAxes
|
||||
supportedTypes(::PyPlotBackend) = [
|
||||
:none, :line, :path, :steppre, :steppost, :shape,
|
||||
:scatter, :histogram2d, :hexbin, :histogram, #:density,
|
||||
:bar, :sticks, #:box, :violin, :quiver,
|
||||
:clims,
|
||||
:inset_subplots,
|
||||
])
|
||||
supported_types(::PyPlotBackend) = [
|
||||
:path, :steppre, :steppost, :shape,
|
||||
:scatter, :histogram2d, :hexbin, :histogram,
|
||||
:bar, :sticks,
|
||||
:hline, :vline, :heatmap, :pie, :image,
|
||||
:contour, :contour3d, :path3d, :scatter3d, :surface, :wireframe
|
||||
]
|
||||
supportedStyles(::PyPlotBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supportedMarkers(::PyPlotBackend) = vcat(_allMarkers, Shape)
|
||||
supportedScales(::PyPlotBackend) = [:identity, :ln, :log2, :log10]
|
||||
subplotSupported(::PyPlotBackend) = true
|
||||
# nativeImagesSupported(::PyPlotBackend) = true
|
||||
supported_styles(::PyPlotBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supported_markers(::PyPlotBackend) = vcat(_allMarkers, Shape)
|
||||
supported_scales(::PyPlotBackend) = [:identity, :ln, :log2, :log10]
|
||||
is_subplot_supported(::PyPlotBackend) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
@@ -57,6 +47,9 @@ subplotSupported(::PyPlotBackend) = true
|
||||
|
||||
function _initialize_backend(::PyPlotBackend)
|
||||
@eval begin
|
||||
# see: https://github.com/tbreloff/Plots.jl/issues/308
|
||||
ENV["OVERRIDE_PYPLOT_DISPLAY"] = true
|
||||
|
||||
import PyPlot
|
||||
export PyPlot
|
||||
const pycolors = PyPlot.pywrap(PyPlot.pyimport("matplotlib.colors"))
|
||||
@@ -70,59 +63,42 @@ function _initialize_backend(::PyPlotBackend)
|
||||
const pytransforms = PyPlot.pywrap(PyPlot.pyimport("matplotlib.transforms"))
|
||||
end
|
||||
|
||||
# we don't want every command to update the figure
|
||||
PyPlot.ioff()
|
||||
|
||||
if !isa(Base.Multimedia.displays[end], Base.REPL.REPLDisplay)
|
||||
PyPlot.ioff() # stops wierd behavior of displaying incomplete graphs in IJulia
|
||||
|
||||
# # TODO: how the hell can I use PyQt4??
|
||||
# "pyqt4"=>:qt_pyqt4
|
||||
# PyPlot.backend[1] = "pyqt4"
|
||||
# PyPlot.gui[1] = :qt_pyqt4
|
||||
# PyPlot.switch_backend("Qt4Agg")
|
||||
|
||||
# only turn on the gui if we want it
|
||||
if PyPlot.gui != :none
|
||||
PyPlot.pygui(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
# convert colorant to 4-tuple RGBA
|
||||
getPyPlotColor(c::Colorant, α=nothing) = map(f->float(f(convertColor(c,α))), (red, green, blue, alpha))
|
||||
getPyPlotColor(cvec::ColorVector, α=nothing) = map(getPyPlotColor, convertColor(cvec, α).v)
|
||||
getPyPlotColor(grad::ColorGradient, α=nothing) = map(c -> getPyPlotColor(c, α), grad.colors)
|
||||
getPyPlotColor(scheme::ColorScheme, α=nothing) = getPyPlotColor(convertColor(getColor(scheme), α))
|
||||
getPyPlotColor(vec::AVec, α=nothing) = map(c->getPyPlotColor(c,α), vec)
|
||||
getPyPlotColor(c, α=nothing) = getPyPlotColor(convertColor(c, α))
|
||||
py_color(c::Colorant, α=nothing) = map(f->float(f(convertColor(c,α))), (red, green, blue, alpha))
|
||||
py_color(cvec::ColorVector, α=nothing) = map(py_color, convertColor(cvec, α).v)
|
||||
py_color(grad::ColorGradient, α=nothing) = map(c -> py_color(c, α), grad.colors)
|
||||
py_color(scheme::ColorScheme, α=nothing) = py_color(convertColor(getColor(scheme), α))
|
||||
py_color(vec::AVec, α=nothing) = map(c->py_color(c,α), vec)
|
||||
py_color(c, α=nothing) = py_color(convertColor(c, α))
|
||||
|
||||
function getPyPlotColorMap(c::ColorGradient, α=nothing)
|
||||
pyvals = [(v, getPyPlotColor(getColorZ(c, v), α)) for v in c.values]
|
||||
function py_colormap(c::ColorGradient, α=nothing)
|
||||
pyvals = [(v, py_color(getColorZ(c, v), α)) for v in c.values]
|
||||
pycolors.pymember("LinearSegmentedColormap")[:from_list]("tmp", pyvals)
|
||||
end
|
||||
|
||||
# convert vectors and ColorVectors to standard ColorGradients
|
||||
# TODO: move this logic to colors.jl and keep a barebones wrapper for pyplot
|
||||
getPyPlotColorMap(cv::ColorVector, α=nothing) = getPyPlotColorMap(ColorGradient(cv.v), α)
|
||||
getPyPlotColorMap(v::AVec, α=nothing) = getPyPlotColorMap(ColorGradient(v), α)
|
||||
py_colormap(cv::ColorVector, α=nothing) = py_colormap(ColorGradient(cv.v), α)
|
||||
py_colormap(v::AVec, α=nothing) = py_colormap(ColorGradient(v), α)
|
||||
|
||||
# anything else just gets a bluesred gradient
|
||||
getPyPlotColorMap(c, α=nothing) = getPyPlotColorMap(default_gradient(), α)
|
||||
py_colormap(c, α=nothing) = py_colormap(default_gradient(), α)
|
||||
|
||||
function getPyPlotCustomShading(c, z, α=nothing)
|
||||
cmap = getPyPlotColorMap(c, α)
|
||||
# sm = pycmap.pymember("ScalarMappable")(cmap = cmap)
|
||||
# sm[:set_array](z)
|
||||
# sm
|
||||
function py_shading(c, z, α=nothing)
|
||||
cmap = py_colormap(c, α)
|
||||
ls = pycolors.pymember("LightSource")(270,45)
|
||||
ls[:shade](z, cmap, vert_exag=0.1, blend_mode="soft")
|
||||
end
|
||||
|
||||
# get the style (solid, dashed, etc)
|
||||
function getPyPlotLineStyle(seriestype::Symbol, linestyle::Symbol)
|
||||
function py_linestyle(seriestype::Symbol, linestyle::Symbol)
|
||||
seriestype == :none && return " "
|
||||
linestyle == :solid && return "-"
|
||||
linestyle == :dash && return "--"
|
||||
@@ -132,7 +108,7 @@ function getPyPlotLineStyle(seriestype::Symbol, linestyle::Symbol)
|
||||
return "-"
|
||||
end
|
||||
|
||||
function getPyPlotMarker(marker::Shape)
|
||||
function py_marker(marker::Shape)
|
||||
x, y = shape_coords(marker)
|
||||
n = length(x)
|
||||
mat = zeros(n+1,2)
|
||||
@@ -150,7 +126,7 @@ const _path_CLOSEPOLY = UInt8(79)
|
||||
|
||||
# see http://matplotlib.org/users/path_tutorial.html
|
||||
# and http://matplotlib.org/api/path_api.html#matplotlib.path.Path
|
||||
function buildPyPlotPath(x, y)
|
||||
function py_path(x, y)
|
||||
n = length(x)
|
||||
mat = zeros(n+1, 2)
|
||||
codes = zeros(UInt8, n+1)
|
||||
@@ -171,9 +147,9 @@ function buildPyPlotPath(x, y)
|
||||
end
|
||||
|
||||
# get the marker shape
|
||||
function getPyPlotMarker(marker::Symbol)
|
||||
function py_marker(marker::Symbol)
|
||||
marker == :none && return " "
|
||||
marker == :ellipse && return "o"
|
||||
marker == :circle && return "o"
|
||||
marker == :rect && return "s"
|
||||
marker == :diamond && return "D"
|
||||
marker == :utriangle && return "^"
|
||||
@@ -184,32 +160,32 @@ function getPyPlotMarker(marker::Symbol)
|
||||
marker == :pentagon && return "p"
|
||||
marker == :hexagon && return "h"
|
||||
marker == :octagon && return "8"
|
||||
haskey(_shapes, marker) && return getPyPlotMarker(_shapes[marker])
|
||||
haskey(_shapes, marker) && return py_marker(_shapes[marker])
|
||||
|
||||
warn("Unknown marker $marker")
|
||||
return "o"
|
||||
end
|
||||
|
||||
# getPyPlotMarker(markers::AVec) = map(getPyPlotMarker, markers)
|
||||
function getPyPlotMarker(markers::AVec)
|
||||
# py_marker(markers::AVec) = map(py_marker, markers)
|
||||
function py_marker(markers::AVec)
|
||||
warn("Vectors of markers are currently unsupported in PyPlot: $markers")
|
||||
getPyPlotMarker(markers[1])
|
||||
py_marker(markers[1])
|
||||
end
|
||||
|
||||
# pass through
|
||||
function getPyPlotMarker(marker::AbstractString)
|
||||
function py_marker(marker::AbstractString)
|
||||
@assert length(marker) == 1
|
||||
marker
|
||||
end
|
||||
|
||||
function getPyPlotStepStyle(seriestype::Symbol)
|
||||
function py_stepstyle(seriestype::Symbol)
|
||||
seriestype == :steppost && return "steps-post"
|
||||
seriestype == :steppre && return "steps-pre"
|
||||
return "default"
|
||||
end
|
||||
|
||||
# untested... return a FontProperties object from a Plots.Font
|
||||
function getPyPlotFont(font::Font)
|
||||
function py_font(font::Font)
|
||||
pyfont.pymember("FontProperties")(
|
||||
family = font.family,
|
||||
size = font.size
|
||||
@@ -225,18 +201,18 @@ function add_pyfixedformatter(cbar, vals::AVec)
|
||||
cbar[:update_ticks]()
|
||||
end
|
||||
|
||||
# TODO: smoothing should be moved into the SliceIt method, should not touch backends
|
||||
function handleSmooth(plt::Plot{PyPlotBackend}, ax, d::KW, smooth::Bool)
|
||||
if smooth
|
||||
xs, ys = regressionXY(d[:x], d[:y])
|
||||
ax[:plot](xs, ys,
|
||||
# linestyle = getPyPlotLineStyle(:path, :dashdot),
|
||||
color = getPyPlotColor(d[:linecolor]),
|
||||
linewidth = 2
|
||||
)
|
||||
end
|
||||
end
|
||||
handleSmooth(plt::Plot{PyPlotBackend}, ax, d::KW, smooth::Real) = handleSmooth(plt, ax, d, true)
|
||||
# # TODO: smoothing should be moved into the SliceIt method, should not touch backends
|
||||
# function handleSmooth(plt::Plot{PyPlotBackend}, ax, d::KW, smooth::Bool)
|
||||
# if smooth
|
||||
# xs, ys = regressionXY(d[:x], d[:y])
|
||||
# ax[:plot](xs, ys,
|
||||
# # linestyle = py_linestyle(:path, :dashdot),
|
||||
# color = py_color(d[:linecolor]),
|
||||
# linewidth = 2
|
||||
# )
|
||||
# end
|
||||
# end
|
||||
# handleSmooth(plt::Plot{PyPlotBackend}, ax, d::KW, smooth::Real) = handleSmooth(plt, ax, d, true)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -254,7 +230,7 @@ end
|
||||
|
||||
# total hack due to PyPlot bug (see issue #145).
|
||||
# hack: duplicate the color vector when the total rgba fields is the same as the series length
|
||||
function color_fix(c, x)
|
||||
function py_color_fix(c, x)
|
||||
if (typeof(c) <: AbstractArray && length(c)*4 == length(x)) ||
|
||||
(typeof(c) <: Tuple && length(x) == 4)
|
||||
vcat(c, c)
|
||||
@@ -263,55 +239,49 @@ function color_fix(c, x)
|
||||
end
|
||||
end
|
||||
|
||||
pylinecolor(d::KW) = getPyPlotColor(d[:linecolor], d[:linealpha])
|
||||
pymarkercolor(d::KW) = getPyPlotColor(d[:markercolor], d[:markeralpha])
|
||||
pymarkerstrokecolor(d::KW) = getPyPlotColor(d[:markerstrokecolor], d[:markerstrokealpha])
|
||||
pyfillcolor(d::KW) = getPyPlotColor(d[:fillcolor], d[:fillalpha])
|
||||
py_linecolor(d::KW) = py_color(d[:linecolor], d[:linealpha])
|
||||
py_markercolor(d::KW) = py_color(d[:markercolor], d[:markeralpha])
|
||||
py_markerstrokecolor(d::KW) = py_color(d[:markerstrokecolor], d[:markerstrokealpha])
|
||||
py_fillcolor(d::KW) = py_color(d[:fillcolor], d[:fillalpha])
|
||||
|
||||
pylinecolormap(d::KW) = getPyPlotColorMap(d[:linecolor], d[:linealpha])
|
||||
pymarkercolormap(d::KW) = getPyPlotColorMap(d[:markercolor], d[:markeralpha])
|
||||
pyfillcolormap(d::KW) = getPyPlotColorMap(d[:fillcolor], d[:fillalpha])
|
||||
py_linecolormap(d::KW) = py_colormap(d[:linecolor], d[:linealpha])
|
||||
py_markercolormap(d::KW) = py_colormap(d[:markercolor], d[:markeralpha])
|
||||
py_fillcolormap(d::KW) = py_colormap(d[:fillcolor], d[:fillalpha])
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# TODO: these can probably be removed eventually... right now they're just keeping things working before cleanup
|
||||
|
||||
getAxis(sp::Subplot) = sp.o
|
||||
# getAxis(sp::Subplot) = sp.o
|
||||
|
||||
function getAxis(plt::Plot{PyPlotBackend}, series::Series)
|
||||
sp = get_subplot(plt, get(series.d, :subplot, 1))
|
||||
getAxis(sp)
|
||||
end
|
||||
# function getAxis(plt::Plot{PyPlotBackend}, series::Series)
|
||||
# sp = get_subplot(plt, get(series.d, :subplot, 1))
|
||||
# getAxis(sp)
|
||||
# end
|
||||
|
||||
getfig(o) = o
|
||||
# getfig(o) = o
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Figure utils -- F*** matplotlib for making me work so hard to figure this crap out
|
||||
|
||||
# the drawing surface
|
||||
canvas(fig) = fig[:canvas]
|
||||
py_canvas(fig) = fig[:canvas]
|
||||
|
||||
# the object controlling draw commands
|
||||
renderer(fig) = canvas(fig)[:get_renderer]()
|
||||
py_renderer(fig) = py_canvas(fig)[:get_renderer]()
|
||||
|
||||
# draw commands... paint the screen (probably updating internals too)
|
||||
drawfig(fig) = fig[:draw](renderer(fig))
|
||||
drawax(ax) = ax[:draw](renderer(ax[:get_figure]()))
|
||||
py_drawfig(fig) = fig[:draw](py_renderer(fig))
|
||||
# py_drawax(ax) = ax[:draw](py_renderer(ax[:get_figure]()))
|
||||
|
||||
# get a vector [left, right, bottom, top] in PyPlot coords (origin is bottom-left!)
|
||||
get_extents(obj) = obj[:get_window_extent]()[:get_points]()
|
||||
py_extents(obj) = obj[:get_window_extent]()[:get_points]()
|
||||
|
||||
# # bounding box of the figure
|
||||
# function py_bbox_fig(fig)
|
||||
# fl, fr, fb, ft = get_extents(fig)
|
||||
# BoundingBox(0px, 0px, (fr-fl)*px, (ft-fb)*px)
|
||||
# end
|
||||
# py_bbox_fig(plt::Plot) = py_bbox_fig(plt.o)
|
||||
|
||||
# compute a bounding box (with origin top-left), however pyplot gives coords with origin bottom-left
|
||||
function py_bbox(obj)
|
||||
fl, fr, fb, ft = get_extents(obj[:get_figure]())
|
||||
l, r, b, t = get_extents(obj)
|
||||
fl, fr, fb, ft = py_extents(obj[:get_figure]())
|
||||
l, r, b, t = py_extents(obj)
|
||||
BoundingBox(l*px, (ft-t)*px, (r-l)*px, (t-b)*px)
|
||||
end
|
||||
|
||||
@@ -359,24 +329,17 @@ end
|
||||
function _create_backend_figure(plt::Plot{PyPlotBackend})
|
||||
w,h = map(px2inch, plt[:size])
|
||||
|
||||
# reuse the current figure?
|
||||
# # reuse the current figure?
|
||||
fig = if plt[:overwrite_figure]
|
||||
PyPlot.gcf()
|
||||
else
|
||||
PyPlot.figure()
|
||||
fig = PyPlot.figure()
|
||||
# finalizer(fig, close)
|
||||
fig
|
||||
end
|
||||
|
||||
# # update the specs
|
||||
# fig[:set_size_inches](w, h, forward = true)
|
||||
# fig[:set_facecolor](getPyPlotColor(plt[:background_color_outside]))
|
||||
# fig[:set_dpi](DPI)
|
||||
# # fig[:set_tight_layout](true)
|
||||
|
||||
# clear the figure
|
||||
PyPlot.clf()
|
||||
|
||||
# # resize the window
|
||||
# PyPlot.plt[:get_current_fig_manager]()[:resize](plt[:size]...)
|
||||
fig
|
||||
end
|
||||
|
||||
@@ -405,15 +368,16 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
d = series.d
|
||||
st = d[:seriestype]
|
||||
sp = d[:subplot]
|
||||
ax = sp.o
|
||||
|
||||
if !(st in supportedTypes(plt.backend))
|
||||
error("seriestype $(st) is unsupported in PyPlot. Choose from: $(supportedTypes(plt.backend))")
|
||||
if !(st in supported_types(plt.backend))
|
||||
error("seriestype $(st) is unsupported in PyPlot. Choose from: $(supported_types(plt.backend))")
|
||||
end
|
||||
|
||||
# PyPlot doesn't handle mismatched x/y
|
||||
fix_xy_lengths!(plt, d)
|
||||
|
||||
ax = getAxis(plt, series)
|
||||
# ax = getAxis(plt, series)
|
||||
x, y, z = d[:x], d[:y], d[:z]
|
||||
xyargs = (st in _3dTypes ? (x,y,z) : (x,y))
|
||||
|
||||
@@ -440,17 +404,17 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
# for each plotting command, optionally build and add a series handle to the list
|
||||
|
||||
# line plot
|
||||
if st in (:path, :line, :path3d, :steppre, :steppost)
|
||||
if st in (:path, :path3d, :steppre, :steppost)
|
||||
if d[:linewidth] > 0
|
||||
handle = ax[:plot](xyargs...;
|
||||
label = d[:label],
|
||||
zorder = plt.n,
|
||||
color = pylinecolor(d),
|
||||
color = py_linecolor(d),
|
||||
linewidth = d[:linewidth],
|
||||
linestyle = getPyPlotLineStyle(st, d[:linestyle]),
|
||||
linestyle = py_linestyle(st, d[:linestyle]),
|
||||
solid_capstyle = "round",
|
||||
# dash_capstyle = "round",
|
||||
drawstyle = getPyPlotStepStyle(st)
|
||||
drawstyle = py_stepstyle(st)
|
||||
)[1]
|
||||
push!(handles, handle)
|
||||
|
||||
@@ -463,10 +427,10 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
:arrowstyle => "simple,head_length=$(a.headlength),head_width=$(a.headwidth)",
|
||||
:shrinkA => 0,
|
||||
:shrinkB => 0,
|
||||
:edgecolor => pylinecolor(d),
|
||||
:facecolor => pylinecolor(d),
|
||||
:edgecolor => py_linecolor(d),
|
||||
:facecolor => py_linecolor(d),
|
||||
:linewidth => d[:linewidth],
|
||||
:linestyle => getPyPlotLineStyle(st, d[:linestyle]),
|
||||
:linestyle => py_linestyle(st, d[:linestyle]),
|
||||
)
|
||||
add_arrows(x, y) do xyprev, xy
|
||||
ax[:annotate]("",
|
||||
@@ -495,8 +459,8 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
handle = ax[isvertical(d) ? :bar : :barh](x, y;
|
||||
label = d[:label],
|
||||
zorder = plt.n,
|
||||
color = pyfillcolor(d),
|
||||
edgecolor = pylinecolor(d),
|
||||
color = py_fillcolor(d),
|
||||
edgecolor = py_linecolor(d),
|
||||
linewidth = d[:linewidth],
|
||||
align = d[:bar_edges] ? "edge" : "center",
|
||||
extrakw...
|
||||
@@ -509,8 +473,8 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
handle = ax[isvertical(d) ? :bar : :barh](x, y;
|
||||
label = d[:label],
|
||||
zorder = plt.n,
|
||||
color = pylinecolor(d),
|
||||
edgecolor = pylinecolor(d),
|
||||
color = py_linecolor(d),
|
||||
edgecolor = py_linecolor(d),
|
||||
linewidth = d[:linewidth],
|
||||
align = "center",
|
||||
extrakw...
|
||||
@@ -519,15 +483,20 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
end
|
||||
|
||||
# add markers?
|
||||
if d[:markershape] != :none && st in (:path, :line, :scatter, :path3d,
|
||||
if d[:markershape] != :none && st in (:path, :scatter, :path3d,
|
||||
:scatter3d, :steppre, :steppost,
|
||||
:bar, :sticks)
|
||||
extrakw = KW()
|
||||
if d[:marker_z] == nothing
|
||||
extrakw[:c] = color_fix(pymarkercolor(d), x)
|
||||
extrakw[:c] = py_color_fix(py_markercolor(d), x)
|
||||
else
|
||||
extrakw[:c] = convert(Vector{Float64}, d[:marker_z])
|
||||
extrakw[:cmap] = pymarkercolormap(d)
|
||||
extrakw[:cmap] = py_markercolormap(d)
|
||||
clims = sp[:clims]
|
||||
if isa(clims, Tuple) && length(clims) == 2
|
||||
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
|
||||
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
|
||||
end
|
||||
needs_colorbar = true
|
||||
end
|
||||
xyargs = if st in (:bar, :sticks) && !isvertical(d)
|
||||
@@ -538,9 +507,9 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
handle = ax[:scatter](xyargs...;
|
||||
label = d[:label],
|
||||
zorder = plt.n + 0.5,
|
||||
marker = getPyPlotMarker(d[:markershape]),
|
||||
marker = py_marker(d[:markershape]),
|
||||
s = d[:markersize] .^ 2,
|
||||
edgecolors = pymarkerstrokecolor(d),
|
||||
edgecolors = py_markerstrokecolor(d),
|
||||
linewidths = d[:markerstrokewidth],
|
||||
extrakw...
|
||||
)
|
||||
@@ -551,8 +520,8 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
handle = ax[:hist](y;
|
||||
label = d[:label],
|
||||
zorder = plt.n,
|
||||
color = pyfillcolor(d),
|
||||
edgecolor = pylinecolor(d),
|
||||
color = py_fillcolor(d),
|
||||
edgecolor = py_linecolor(d),
|
||||
linewidth = d[:linewidth],
|
||||
bins = d[:bins],
|
||||
normed = d[:normalize],
|
||||
@@ -572,13 +541,19 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
end
|
||||
|
||||
if st == :histogram2d
|
||||
clims = sp[:clims]
|
||||
if isa(clims, Tuple) && length(clims) == 2
|
||||
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
|
||||
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
|
||||
end
|
||||
handle = ax[:hist2d](x, y;
|
||||
label = d[:label],
|
||||
zorder = plt.n,
|
||||
bins = d[:bins],
|
||||
normed = d[:normalize],
|
||||
weights = d[:weights],
|
||||
cmap = pyfillcolormap(d) # applies to the pcolorfast object
|
||||
cmap = py_fillcolormap(d), # applies to the pcolorfast object
|
||||
extrakw...
|
||||
)[4]
|
||||
push!(handles, handle)
|
||||
needs_colorbar = true
|
||||
@@ -591,13 +566,19 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
end
|
||||
|
||||
if st == :hexbin
|
||||
clims = sp[:clims]
|
||||
if isa(clims, Tuple) && length(clims) == 2
|
||||
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
|
||||
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
|
||||
end
|
||||
handle = ax[:hexbin](x, y;
|
||||
label = d[:label],
|
||||
zorder = plt.n,
|
||||
gridsize = d[:bins],
|
||||
linewidths = d[:linewidth],
|
||||
edgecolors = pylinecolor(d),
|
||||
cmap = pyfillcolormap(d) # applies to the pcolorfast object
|
||||
edgecolors = py_linecolor(d),
|
||||
cmap = py_fillcolormap(d), # applies to the pcolorfast object
|
||||
extrakw...
|
||||
)
|
||||
push!(handles, handle)
|
||||
needs_colorbar = true
|
||||
@@ -608,8 +589,8 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
func = ax[st == :hline ? :axhline : :axvline]
|
||||
handle = func(yi;
|
||||
linewidth=d[:linewidth],
|
||||
color=pylinecolor(d),
|
||||
linestyle=getPyPlotLineStyle(st, d[:linestyle])
|
||||
color=py_linecolor(d),
|
||||
linestyle=py_linestyle(st, d[:linestyle])
|
||||
)
|
||||
push!(handles, handle)
|
||||
end
|
||||
@@ -620,6 +601,11 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
z = transpose_z(d, z.surf)
|
||||
needs_colorbar = true
|
||||
|
||||
clims = sp[:clims]
|
||||
if isa(clims, Tuple) && length(clims) == 2
|
||||
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
|
||||
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
|
||||
end
|
||||
|
||||
if st == :contour3d
|
||||
extrakw[:extend3d] = true
|
||||
@@ -630,8 +616,8 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
label = d[:label],
|
||||
zorder = plt.n,
|
||||
linewidths = d[:linewidth],
|
||||
linestyles = getPyPlotLineStyle(st, d[:linestyle]),
|
||||
cmap = pylinecolormap(d),
|
||||
linestyles = py_linestyle(st, d[:linestyle]),
|
||||
cmap = py_linecolormap(d),
|
||||
extrakw...
|
||||
)
|
||||
push!(handles, handle)
|
||||
@@ -641,7 +627,7 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
handle = ax[:contourf](x, y, z, levelargs...;
|
||||
label = d[:label],
|
||||
zorder = plt.n + 0.5,
|
||||
cmap = pyfillcolormap(d),
|
||||
cmap = py_fillcolormap(d),
|
||||
extrakw...
|
||||
)
|
||||
push!(handles, handle)
|
||||
@@ -659,10 +645,15 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
z = transpose_z(d, z)
|
||||
if st == :surface
|
||||
if d[:marker_z] != nothing
|
||||
extrakw[:facecolors] = getPyPlotCustomShading(d[:fillcolor], d[:marker_z], d[:fillalpha])
|
||||
extrakw[:facecolors] = py_shading(d[:fillcolor], d[:marker_z], d[:fillalpha])
|
||||
extrakw[:shade] = false
|
||||
clims = sp[:clims]
|
||||
if isa(clims, Tuple) && length(clims) == 2
|
||||
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
|
||||
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
|
||||
end
|
||||
else
|
||||
extrakw[:cmap] = pyfillcolormap(d)
|
||||
extrakw[:cmap] = py_fillcolormap(d)
|
||||
needs_colorbar = true
|
||||
end
|
||||
end
|
||||
@@ -672,7 +663,7 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
rstride = 1,
|
||||
cstride = 1,
|
||||
linewidth = d[:linewidth],
|
||||
edgecolor = pylinecolor(d),
|
||||
edgecolor = py_linecolor(d),
|
||||
extrakw...
|
||||
)
|
||||
push!(handles, handle)
|
||||
@@ -683,7 +674,7 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
offset = (zdir == "y" ? maximum : minimum)(mat)
|
||||
handle = ax[:contourf](x, y, z, levelargs...;
|
||||
zdir = zdir,
|
||||
cmap = pyfillcolormap(d),
|
||||
cmap = py_fillcolormap(d),
|
||||
offset = (zdir == "y" ? maximum : minimum)(mat) # where to draw the contour plane
|
||||
)
|
||||
push!(handles, handle)
|
||||
@@ -698,12 +689,18 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
|
||||
elseif typeof(z) <: AbstractVector
|
||||
# tri-surface plot (http://matplotlib.org/mpl_toolkits/mplot3d/tutorial.html#tri-surface-plots)
|
||||
clims = sp[:clims]
|
||||
if isa(clims, Tuple) && length(clims) == 2
|
||||
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
|
||||
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
|
||||
end
|
||||
handle = ax[:plot_trisurf](x, y, z;
|
||||
label = d[:label],
|
||||
zorder = plt.n,
|
||||
cmap = pyfillcolormap(d),
|
||||
cmap = py_fillcolormap(d),
|
||||
linewidth = d[:linewidth],
|
||||
edgecolor = pylinecolor(d)
|
||||
edgecolor = py_linecolor(d),
|
||||
extrakw...
|
||||
)
|
||||
push!(handles, handle)
|
||||
needs_colorbar = true
|
||||
@@ -724,7 +721,7 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
end
|
||||
handle = ax[:imshow](z;
|
||||
zorder = plt.n,
|
||||
cmap = getPyPlotColorMap([:black, :white]),
|
||||
cmap = py_colormap([:black, :white]),
|
||||
vmin = 0.0,
|
||||
vmax = 1.0
|
||||
)
|
||||
@@ -745,11 +742,19 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
if !isempty(dvals)
|
||||
discrete_colorbar_values = dvals
|
||||
end
|
||||
|
||||
clims = sp[:clims]
|
||||
if isa(clims, Tuple) && length(clims) == 2
|
||||
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
|
||||
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
|
||||
end
|
||||
|
||||
handle = ax[:pcolormesh](x, y, z;
|
||||
label = d[:label],
|
||||
zorder = plt.n,
|
||||
cmap = pyfillcolormap(d),
|
||||
edgecolors = (d[:linewidth] > 0 ? pylinecolor(d) : "face")
|
||||
cmap = py_fillcolormap(d),
|
||||
edgecolors = (d[:linewidth] > 0 ? py_linecolor(d) : "face"),
|
||||
extrakw...
|
||||
)
|
||||
push!(handles, handle)
|
||||
needs_colorbar = true
|
||||
@@ -766,12 +771,12 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
end
|
||||
|
||||
if st == :shape
|
||||
path = buildPyPlotPath(x, y)
|
||||
path = py_path(x, y)
|
||||
patches = pypatches.pymember("PathPatch")(path;
|
||||
label = d[:label],
|
||||
zorder = plt.n,
|
||||
edgecolor = pymarkerstrokecolor(d),
|
||||
facecolor = pymarkercolor(d),
|
||||
edgecolor = py_markerstrokecolor(d),
|
||||
facecolor = py_markercolor(d),
|
||||
linewidth = d[:markerstrokewidth],
|
||||
fill = true
|
||||
)
|
||||
@@ -796,8 +801,8 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
|
||||
d[:serieshandle] = handles
|
||||
|
||||
# smoothing
|
||||
handleSmooth(plt, ax, d, d[:smooth])
|
||||
# # smoothing
|
||||
# handleSmooth(plt, ax, d, d[:smooth])
|
||||
|
||||
# add the colorbar legend
|
||||
if needs_colorbar && sp[:colorbar] != :none
|
||||
@@ -837,7 +842,7 @@ function _series_added(plt::Plot{PyPlotBackend}, series::Series)
|
||||
|
||||
handle = ax[f](args...;
|
||||
zorder = plt.n,
|
||||
facecolor = pyfillcolor(d),
|
||||
facecolor = py_fillcolor(d),
|
||||
linewidths = 0
|
||||
)
|
||||
push!(handles, handle)
|
||||
@@ -849,7 +854,7 @@ end
|
||||
|
||||
function update_limits!(sp::Subplot{PyPlotBackend}, series::Series, letters)
|
||||
for letter in letters
|
||||
setPyPlotLims(sp.o, sp[Symbol(letter, :axis)])
|
||||
py_set_lims(sp.o, sp[Symbol(letter, :axis)])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -873,13 +878,13 @@ end
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
function setPyPlotLims(ax, axis::Axis)
|
||||
function py_set_lims(ax, axis::Axis)
|
||||
letter = axis[:letter]
|
||||
lfrom, lto = axis_limits(axis)
|
||||
ax[Symbol("set_", letter, "lim")](lfrom, lto)
|
||||
end
|
||||
|
||||
function addPyPlotTicks(ax, ticks, letter)
|
||||
function py_set_ticks(ax, ticks, letter)
|
||||
ticks == :auto && return
|
||||
axis = ax[Symbol(letter,"axis")]
|
||||
if ticks == :none || ticks == nothing
|
||||
@@ -902,26 +907,54 @@ function addPyPlotTicks(ax, ticks, letter)
|
||||
end
|
||||
end
|
||||
|
||||
function applyPyPlotScale(ax, scaleType::Symbol, letter)
|
||||
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
|
||||
|
||||
function py_set_scale(ax, axis::Axis)
|
||||
scale = axis[:scale]
|
||||
letter = axis[:letter]
|
||||
scale in supported_scales() || return warn("Unhandled scale value in pyplot: $scale")
|
||||
func = ax[Symbol("set_", letter, "scale")]
|
||||
scaleType == :identity && return func("linear")
|
||||
scaleType == :ln && return func("log", basex = e, basey = e)
|
||||
scaleType == :log2 && return func("log", basex = 2, basey = 2)
|
||||
scaleType == :log10 && return func("log", basex = 10, basey = 10)
|
||||
warn("Unhandled scaleType: ", scaleType)
|
||||
kw = KW()
|
||||
arg = if scale == :identity
|
||||
"linear"
|
||||
else
|
||||
kw[Symbol(:base,letter)] = if scale == :ln
|
||||
e
|
||||
elseif scale == :log2
|
||||
2
|
||||
elseif scale == :log10
|
||||
10
|
||||
end
|
||||
kw[Symbol(:linthresh,letter)] = max(1e-16, py_compute_axis_minval(axis))
|
||||
"symlog"
|
||||
end
|
||||
func(arg; kw...)
|
||||
end
|
||||
|
||||
|
||||
function updateAxisColors(ax, a::Axis)
|
||||
function py_set_axis_colors(ax, a::Axis)
|
||||
for (loc, spine) in ax[:spines]
|
||||
spine[:set_color](getPyPlotColor(a[:foreground_color_border]))
|
||||
spine[:set_color](py_color(a[:foreground_color_border]))
|
||||
end
|
||||
axissym = Symbol(a[:letter], :axis)
|
||||
if haskey(ax, axissym)
|
||||
ax[:tick_params](axis=string(a[:letter]), which="both",
|
||||
colors=getPyPlotColor(a[:foreground_color_axis]),
|
||||
labelcolor=getPyPlotColor(a[:foreground_color_text]))
|
||||
ax[axissym][:label][:set_color](getPyPlotColor(a[:foreground_color_guide]))
|
||||
colors=py_color(a[:foreground_color_axis]),
|
||||
labelcolor=py_color(a[:foreground_color_text]))
|
||||
ax[axissym][:label][:set_color](py_color(a[:foreground_color_guide]))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -934,7 +967,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
w, h = plt[:size]
|
||||
fig = plt.o
|
||||
fig[:set_size_inches](px2inch(w), px2inch(h), forward = true)
|
||||
fig[:set_facecolor](getPyPlotColor(plt[:background_color_outside]))
|
||||
fig[:set_facecolor](py_color(plt[:background_color_outside]))
|
||||
fig[:set_dpi](DPI)
|
||||
|
||||
# resize the window
|
||||
@@ -942,14 +975,15 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
|
||||
# update subplots
|
||||
for sp in plt.subplots
|
||||
ax = getAxis(sp)
|
||||
# ax = getAxis(sp)
|
||||
ax = sp.o
|
||||
if ax == nothing
|
||||
continue
|
||||
end
|
||||
|
||||
# add the annotations
|
||||
for ann in sp[:annotations]
|
||||
createPyPlotAnnotationObject(sp, ann...)
|
||||
py_add_annotations(sp, ann...)
|
||||
end
|
||||
|
||||
# title
|
||||
@@ -964,7 +998,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
end
|
||||
ax[field][:set_text](sp[:title])
|
||||
ax[field][:set_fontsize](sp[:titlefont].pointsize)
|
||||
ax[field][:set_color](getPyPlotColor(sp[:foreground_color_title]))
|
||||
ax[field][:set_color](py_color(sp[:foreground_color_title]))
|
||||
# ax[:set_title](sp[:title], loc = loc)
|
||||
end
|
||||
|
||||
@@ -973,9 +1007,9 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
axissym = Symbol(letter, :axis)
|
||||
axis = sp[axissym]
|
||||
haskey(ax, axissym) || continue
|
||||
applyPyPlotScale(ax, axis[:scale], letter)
|
||||
setPyPlotLims(ax, axis)
|
||||
addPyPlotTicks(ax, get_ticks(axis), letter)
|
||||
py_set_scale(ax, axis)
|
||||
py_set_lims(ax, axis)
|
||||
py_set_ticks(ax, get_ticks(axis), letter)
|
||||
ax[Symbol("set_", letter, "label")](axis[:guide])
|
||||
if get(axis.d, :flip, false)
|
||||
ax[Symbol("invert_", letter, "axis")]()
|
||||
@@ -986,11 +1020,11 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
lab[:set_rotation](axis[:rotation])
|
||||
end
|
||||
if sp[:grid]
|
||||
fgcolor = getPyPlotColor(sp[:foreground_color_grid])
|
||||
fgcolor = py_color(sp[:foreground_color_grid])
|
||||
ax[axissym][:grid](true, color = fgcolor)
|
||||
ax[:set_axisbelow](true)
|
||||
end
|
||||
updateAxisColors(ax, axis)
|
||||
py_set_axis_colors(ax, axis)
|
||||
end
|
||||
|
||||
# aspect ratio
|
||||
@@ -1000,12 +1034,12 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
end
|
||||
|
||||
# legend
|
||||
addPyPlotLegend(plt, sp, ax)
|
||||
py_add_legend(plt, sp, ax)
|
||||
|
||||
# this sets the bg color inside the grid
|
||||
ax[:set_axis_bgcolor](getPyPlotColor(sp[:background_color_inside]))
|
||||
ax[:set_axis_bgcolor](py_color(sp[:background_color_inside]))
|
||||
end
|
||||
drawfig(fig)
|
||||
py_drawfig(fig)
|
||||
end
|
||||
|
||||
|
||||
@@ -1045,18 +1079,18 @@ end
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
function createPyPlotAnnotationObject(sp::Subplot{PyPlotBackend}, x, y, val)
|
||||
function py_add_annotations(sp::Subplot{PyPlotBackend}, x, y, val)
|
||||
ax = sp.o
|
||||
ax[:annotate](val, xy = (x,y), zorder = 999)
|
||||
end
|
||||
|
||||
|
||||
function createPyPlotAnnotationObject(sp::Subplot{PyPlotBackend}, x, y, val::PlotText)
|
||||
function py_add_annotations(sp::Subplot{PyPlotBackend}, x, y, val::PlotText)
|
||||
ax = sp.o
|
||||
ax[:annotate](val.str,
|
||||
xy = (x,y),
|
||||
family = val.font.family,
|
||||
color = getPyPlotColor(val.font.color),
|
||||
color = py_color(val.font.color),
|
||||
horizontalalignment = val.font.halign == :hcenter ? "center" : string(val.font.halign),
|
||||
verticalalignment = val.font.valign == :vcenter ? "center" : string(val.font.valign),
|
||||
rotation = val.font.rotation * 180 / π,
|
||||
@@ -1093,24 +1127,17 @@ const _pyplot_legend_pos = KW(
|
||||
:topleft => "upper left"
|
||||
)
|
||||
|
||||
function addPyPlotLegend(plt::Plot, sp::Subplot, ax)
|
||||
function py_add_legend(plt::Plot, sp::Subplot, ax)
|
||||
leg = sp[:legend]
|
||||
if leg != :none
|
||||
# gotta do this to ensure both axes are included
|
||||
labels = []
|
||||
handles = []
|
||||
# for series in plt.series_list
|
||||
# if get_subplot(series) === sp &&
|
||||
# series.d[:label] != "" &&
|
||||
# !(series.d[:seriestype] in (
|
||||
# :hexbin,:histogram2d,:hline,:vline,
|
||||
# :contour,:contour3d,:surface,:wireframe,
|
||||
# :heatmap,:path3d,:scatter3d, :pie, :image))
|
||||
for series in series_list(sp)
|
||||
if should_add_to_legend(series)
|
||||
# add a line/marker and a label
|
||||
push!(handles, if series.d[:seriestype] == :histogram
|
||||
PyPlot.plt[:Line2D]((0,1),(0,0), color=pyfillcolor(series.d), linewidth=4)
|
||||
PyPlot.plt[:Line2D]((0,1),(0,0), color=py_fillcolor(series.d), linewidth=4)
|
||||
else
|
||||
series.d[:serieshandle][1]
|
||||
end)
|
||||
@@ -1129,14 +1156,14 @@ function addPyPlotLegend(plt::Plot, sp::Subplot, ax)
|
||||
)
|
||||
leg[:set_zorder](1000)
|
||||
|
||||
fgcolor = getPyPlotColor(sp[:foreground_color_legend])
|
||||
fgcolor = py_color(sp[:foreground_color_legend])
|
||||
for txt in leg[:get_texts]()
|
||||
PyPlot.plt[:setp](txt, color = fgcolor)
|
||||
end
|
||||
|
||||
# set some legend properties
|
||||
frame = leg[:get_frame]()
|
||||
frame[:set_facecolor](getPyPlotColor(sp[:background_color_legend]))
|
||||
frame[:set_facecolor](py_color(sp[:background_color_legend]))
|
||||
frame[:set_edgecolor](fgcolor)
|
||||
end
|
||||
end
|
||||
@@ -1144,30 +1171,6 @@ end
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
# # add legend, update colors and positions, then draw
|
||||
# function finalizePlot(plt::Plot{PyPlotBackend})
|
||||
# # for sp in plt.subplots
|
||||
# # # ax = getLeftAxis(plt)
|
||||
# # ax = getAxis(sp)
|
||||
# # ax == nothing && continue
|
||||
# # addPyPlotLegend(plt, sp, ax)
|
||||
# # for asym in (:xaxis, :yaxis, :zaxis)
|
||||
# # updateAxisColors(ax, sp.attr[asym])
|
||||
# # end
|
||||
# # end
|
||||
# drawfig(plt.o)
|
||||
# # plt.layout.bbox = py_bbox_fig(plt)
|
||||
#
|
||||
# # TODO: these should be called outside of pyplot... how?
|
||||
# update_child_bboxes!(plt.layout)
|
||||
# _update_position!(plt.layout)
|
||||
#
|
||||
# PyPlot.draw()
|
||||
# end
|
||||
|
||||
# function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
||||
# drawfig(plt.o)
|
||||
# end
|
||||
|
||||
# Use the bounding boxes (and methods left/top/right/bottom/width/height) `sp.bbox` and `sp.plotarea` to
|
||||
# position the subplot in the backend.
|
||||
@@ -1175,7 +1178,6 @@ function _update_plot_object(plt::Plot{PyPlotBackend})
|
||||
for sp in plt.subplots
|
||||
ax = sp.o
|
||||
ax == nothing && return
|
||||
# figw, figh = size(py_bbox_fig(sp.plt))
|
||||
figw, figh = sp.plt[:size]
|
||||
figw, figh = figw*px, figh*px
|
||||
pcts = bbox_to_pcts(sp.plotarea, figw, figh)
|
||||
@@ -1196,20 +1198,8 @@ end
|
||||
# -----------------------------------------------------------------
|
||||
# display/output
|
||||
|
||||
# function Base.display(::PlotsDisplay, plt::Plot{PyPlotBackend})
|
||||
# finalizePlot(plt)
|
||||
# if isa(Base.Multimedia.displays[end], Base.REPL.REPLDisplay)
|
||||
# display(getfig(plt.o))
|
||||
# end
|
||||
# getfig(plt.o)[:show]()
|
||||
# end
|
||||
|
||||
function _display(plt::Plot{PyPlotBackend})
|
||||
# finalizePlot(plt)
|
||||
if isa(Base.Multimedia.displays[end], Base.REPL.REPLDisplay)
|
||||
display(getfig(plt.o))
|
||||
end
|
||||
getfig(plt.o)[:show]()
|
||||
plt.o[:show]()
|
||||
end
|
||||
|
||||
|
||||
@@ -1225,10 +1215,8 @@ const _pyplot_mimeformats = Dict(
|
||||
|
||||
|
||||
for (mime, fmt) in _pyplot_mimeformats
|
||||
# @eval function Base.writemime(io::IO, ::MIME{Symbol($mime)}, plt::Plot{PyPlotBackend})
|
||||
@eval function _writemime(io::IO, ::MIME{Symbol($mime)}, plt::Plot{PyPlotBackend})
|
||||
# finalizePlot(plt)
|
||||
fig = getfig(plt.o)
|
||||
fig = plt.o
|
||||
fig.o["canvas"][:print_figure](
|
||||
io,
|
||||
format=$fmt,
|
||||
|
||||
+10
-33
@@ -2,52 +2,29 @@
|
||||
# https://github.com/tbreloff/Qwt.jl
|
||||
|
||||
|
||||
supportedArgs(::QwtBackend) = [
|
||||
supported_args(::QwtBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:axis,
|
||||
:background_color,
|
||||
:linecolor,
|
||||
:color_palette,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
:foreground_color,
|
||||
:group,
|
||||
:label,
|
||||
:layout,
|
||||
:legend,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linestyle,
|
||||
:seriestype,
|
||||
:linewidth,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
:n,
|
||||
:bins,
|
||||
:nc,
|
||||
:nr,
|
||||
:pos,
|
||||
:smooth,
|
||||
:show,
|
||||
:size,
|
||||
:title,
|
||||
:window_title,
|
||||
:x,
|
||||
:xguide,
|
||||
:xlims,
|
||||
:xticks,
|
||||
:y,
|
||||
:yguide,
|
||||
:ylims,
|
||||
:yrightlabel,
|
||||
:yticks,
|
||||
:xscale,
|
||||
:yscale,
|
||||
]
|
||||
supportedTypes(::QwtBackend) = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter, :histogram2d, :hexbin, :histogram, :bar, :hline, :vline]
|
||||
supportedMarkers(::QwtBackend) = [:none, :auto, :rect, :ellipse, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :star8, :hexagon]
|
||||
supportedScales(::QwtBackend) = [:identity, :log10]
|
||||
subplotSupported(::QwtBackend) = true
|
||||
:guide, :lims, :ticks, :scale,
|
||||
])
|
||||
supported_types(::QwtBackend) = [:path, :scatter, :hexbin, :bar]
|
||||
supported_markers(::QwtBackend) = [:none, :auto, :rect, :circle, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :star8, :hexagon]
|
||||
supported_scales(::QwtBackend) = [:identity, :log10]
|
||||
is_subplot_supported(::QwtBackend) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
@@ -95,13 +72,13 @@ function adjustQwtKeywords(plt::Plot{QwtBackend}, iscreating::Bool; kw...)
|
||||
if st == :scatter
|
||||
d[:seriestype] = :none
|
||||
if d[:markershape] == :none
|
||||
d[:markershape] = :ellipse
|
||||
d[:markershape] = :circle
|
||||
end
|
||||
|
||||
elseif st in (:hline, :vline)
|
||||
addLineMarker(plt, d)
|
||||
d[:seriestype] = :none
|
||||
d[:markershape] = :ellipse
|
||||
d[:markershape] = :circle
|
||||
d[:markersize] = 1
|
||||
if st == :vline
|
||||
d[:x], d[:y] = d[:y], d[:x]
|
||||
@@ -184,7 +161,7 @@ function updateLimsAndTicks(plt::Plot{QwtBackend}, d::KW, isx::Bool)
|
||||
# scaletype == :log && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(e))
|
||||
# scaletype == :log2 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(2))
|
||||
scaletype == :log10 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLog10ScaleEngine())
|
||||
scaletype in supportedScales() || warn("Unsupported scale type: ", scaletype)
|
||||
scaletype in supported_scales() || warn("Unsupported scale type: ", scaletype)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -19,9 +19,9 @@ function _create_backend_figure(plt::Plot{[PkgName]Backend})
|
||||
nothing
|
||||
end
|
||||
|
||||
# this is called early in the pipeline, use it to make the plot current or something
|
||||
function _prepare_plot_object(plt::Plot{[PkgName]Backend})
|
||||
end
|
||||
# # this is called early in the pipeline, use it to make the plot current or something
|
||||
# function _prepare_plot_object(plt::Plot{[PkgName]Backend})
|
||||
# end
|
||||
|
||||
# Set up the subplot within the backend object.
|
||||
function _initialize_subplot(plt::Plot{[PkgName]Backend}, sp::Subplot{[PkgName]Backend})
|
||||
|
||||
@@ -1,69 +1,29 @@
|
||||
|
||||
# https://github.com/Evizero/UnicodePlots.jl
|
||||
|
||||
supportedArgs(::UnicodePlotsBackend) = [
|
||||
# :annotations,
|
||||
# :args,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
# :linecolor,
|
||||
# :fill,
|
||||
# :foreground_color,
|
||||
:group,
|
||||
# :heatmap_c,
|
||||
# :kwargs,
|
||||
supported_args(::UnicodePlotsBackend) = merge_with_base_supported([
|
||||
:label,
|
||||
# :layout,
|
||||
:legend,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linestyle,
|
||||
:seriestype,
|
||||
# :linewidth,
|
||||
:markershape,
|
||||
# :markercolor,
|
||||
# :markersize,
|
||||
# :markerstrokewidth,
|
||||
# :markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
# :n,
|
||||
:bins,
|
||||
# :nc,
|
||||
# :nr,
|
||||
# :pos,
|
||||
# :reg,
|
||||
# :ribbon,
|
||||
:show,
|
||||
:size,
|
||||
:title,
|
||||
:window_title,
|
||||
:x,
|
||||
:xguide,
|
||||
:xlims,
|
||||
# :xticks,
|
||||
:y,
|
||||
:yguide,
|
||||
:ylims,
|
||||
# :yrightlabel,
|
||||
# :yticks,
|
||||
# :xscale,
|
||||
# :yscale,
|
||||
# :xflip,
|
||||
# :yflip,
|
||||
# :z,
|
||||
]
|
||||
supportedAxes(::UnicodePlotsBackend) = [:auto, :left]
|
||||
supportedTypes(::UnicodePlotsBackend) = [
|
||||
:path, :steppre, :steppost, :scatter,
|
||||
:histogram2d, :hline, :vline
|
||||
:guide, :lims,
|
||||
])
|
||||
supported_types(::UnicodePlotsBackend) = [
|
||||
:path, :scatter,
|
||||
:histogram2d
|
||||
]
|
||||
supportedStyles(::UnicodePlotsBackend) = [:auto, :solid]
|
||||
supportedMarkers(::UnicodePlotsBackend) = [:none, :auto, :ellipse]
|
||||
supportedScales(::UnicodePlotsBackend) = [:identity]
|
||||
subplotSupported(::UnicodePlotsBackend) = true
|
||||
supported_styles(::UnicodePlotsBackend) = [:auto, :solid]
|
||||
supported_markers(::UnicodePlotsBackend) = [:none, :auto, :circle]
|
||||
supported_scales(::UnicodePlotsBackend) = [:identity]
|
||||
is_subplot_supported(::UnicodePlotsBackend) = true
|
||||
|
||||
|
||||
# don't warn on unsupported... there's just too many warnings!!
|
||||
warnOnUnsupportedArgs(pkg::UnicodePlotsBackend, d::KW) = nothing
|
||||
warnOnUnsupported_args(pkg::UnicodePlotsBackend, d::KW) = nothing
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
+10
-45
@@ -3,64 +3,29 @@
|
||||
|
||||
# credit goes to https://github.com/jverzani for contributing to the first draft of this backend implementation
|
||||
|
||||
supportedArgs(::WinstonBackend) = [
|
||||
supported_args(::WinstonBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
# :args,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
:linecolor,
|
||||
:color_palette,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
# :foreground_color,
|
||||
:group,
|
||||
# :heatmap_c,
|
||||
# :kwargs,
|
||||
:label,
|
||||
# :layout,
|
||||
:legend,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linestyle,
|
||||
:seriestype,
|
||||
:linewidth,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
# :markerstrokewidth,
|
||||
# :markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
# :n,
|
||||
:bins,
|
||||
# :nc,
|
||||
# :nr,
|
||||
# :pos,
|
||||
:smooth,
|
||||
# :ribbon,
|
||||
:show,
|
||||
:size,
|
||||
:title,
|
||||
:window_title,
|
||||
:x,
|
||||
:xguide,
|
||||
:xlims,
|
||||
# :xticks,
|
||||
:y,
|
||||
:yguide,
|
||||
:ylims,
|
||||
# :yrightlabel,
|
||||
# :yticks,
|
||||
:xscale,
|
||||
:yscale,
|
||||
# :xflip,
|
||||
# :yflip,
|
||||
# :z,
|
||||
]
|
||||
supportedAxes(::WinstonBackend) = [:auto, :left]
|
||||
supportedTypes(::WinstonBackend) = [:none, :line, :path, :sticks, :scatter, :histogram, :bar]
|
||||
supportedStyles(::WinstonBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supportedMarkers(::WinstonBackend) = [:none, :auto, :rect, :ellipse, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
|
||||
supportedScales(::WinstonBackend) = [:identity, :log10]
|
||||
subplotSupported(::WinstonBackend) = false
|
||||
:guide, :lims, :scale,
|
||||
])
|
||||
supported_types(::WinstonBackend) = [:path, :scatter, :bar]
|
||||
supported_styles(::WinstonBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supported_markers(::WinstonBackend) = [:none, :auto, :rect, :circle, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
|
||||
supported_scales(::WinstonBackend) = [:identity, :log10]
|
||||
is_subplot_supported(::WinstonBackend) = false
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
@@ -87,7 +52,7 @@ end
|
||||
|
||||
@compat const winston_marker = KW(:none=>".",
|
||||
:rect => "square",
|
||||
:ellipse=>"circle",
|
||||
:circle=>"circle",
|
||||
:diamond=>"diamond",
|
||||
:utriangle=>"triangle",
|
||||
:dtriangle=>"down-triangle",
|
||||
@@ -170,7 +135,7 @@ function _series_added(plt::Plot{WinstonBackend}, series::Series)
|
||||
|
||||
elseif d[:seriestype] == :scatter
|
||||
if d[:markershape] == :none
|
||||
d[:markershape] = :ellipse
|
||||
d[:markershape] = :circle
|
||||
end
|
||||
|
||||
# elseif d[:seriestype] == :step
|
||||
|
||||
@@ -23,6 +23,8 @@ convertColor(c::Symbol) = parse(Colorant, string(c))
|
||||
convertColor(c::Colorant) = c
|
||||
convertColor(cvec::AbstractVector) = map(convertColor, cvec)
|
||||
convertColor(c::ColorScheme) = c
|
||||
convertColor(v::Void) = RGBA(0,0,0,0)
|
||||
convertColor(b::Bool) = b ? RGBA(0,0,0,1) : RGBA(0,0,0,0)
|
||||
|
||||
function convertColor(c, α::Real)
|
||||
c = convertColor(c)
|
||||
@@ -119,6 +121,11 @@ function ColorGradient(grad::ColorGradient; alpha = nothing)
|
||||
ColorGradient(convertColor(grad.colors, alpha), grad.values)
|
||||
end
|
||||
|
||||
# anything else just gets the default gradient
|
||||
function ColorGradient(cw; alpha=nothing)
|
||||
ColorGradient(default_gradient(), alpha=alpha)
|
||||
end
|
||||
|
||||
getColor(gradient::ColorGradient, idx::Int) = gradient.colors[mod1(idx, length(gradient.colors))]
|
||||
|
||||
function getColorZ(gradient::ColorGradient, z::Real)
|
||||
|
||||
+40
-4
@@ -12,8 +12,15 @@ compute_angle(v::P2) = (angle = atan2(v[2], v[1]); angle < 0 ? 2π - angle : ang
|
||||
# -------------------------------------------------------------
|
||||
|
||||
immutable Shape
|
||||
x::AVec
|
||||
y::AVec
|
||||
x::Vector{Float64}
|
||||
y::Vector{Float64}
|
||||
function Shape(x::AVec, y::AVec)
|
||||
if x[1] != x[end] || y[1] != y[end]
|
||||
new(vcat(x, x[1]), vcat(y, y[1]))
|
||||
else
|
||||
new(x, y)
|
||||
end
|
||||
end
|
||||
end
|
||||
Shape(verts::AVec) = Shape(unzip(verts)...)
|
||||
|
||||
@@ -93,8 +100,29 @@ function makearrowhead(angle; h = 2.0, w = 0.4)
|
||||
from_polar(angle + 0.5π, w) - tip, (0,0)])
|
||||
end
|
||||
|
||||
const _shape_keys = Symbol[
|
||||
:circle,
|
||||
:rect,
|
||||
:star5,
|
||||
:diamond,
|
||||
:hexagon,
|
||||
:cross,
|
||||
:xcross,
|
||||
:utriangle,
|
||||
:dtriangle,
|
||||
:pentagon,
|
||||
:heptagon,
|
||||
:octagon,
|
||||
:star4,
|
||||
:star6,
|
||||
:star7,
|
||||
:star8,
|
||||
:vline,
|
||||
:hline,
|
||||
]
|
||||
|
||||
const _shapes = KW(
|
||||
:ellipse => makeshape(20),
|
||||
:circle => makeshape(20),
|
||||
:rect => makeshape(4, offset=-0.25),
|
||||
:diamond => makeshape(4),
|
||||
:utriangle => makeshape(3),
|
||||
@@ -218,7 +246,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 +288,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
|
||||
|
||||
+13
-6
@@ -115,15 +115,17 @@ PlotExample("Line types",
|
||||
PlotExample("Line styles",
|
||||
"",
|
||||
[:(begin
|
||||
styles = setdiff(supportedStyles(), [:auto])'
|
||||
plot(cumsum(randn(20,length(styles)),1), style=:auto, label=map(string,styles), w=5)
|
||||
styles = filter(s -> s in supported_styles(), [:solid, :dash, :dot, :dashdot, :dashdotdot])'
|
||||
n = length(styles)
|
||||
y = cumsum(randn(20,n),1)
|
||||
plot(y, line = (5, styles), label = map(string,styles))
|
||||
end)]
|
||||
),
|
||||
|
||||
PlotExample("Marker types",
|
||||
"",
|
||||
[:(begin
|
||||
markers = setdiff(supportedMarkers(), [:none,:auto,Shape])'
|
||||
markers = filter(m -> m in supported_markers(), Plots._shape_keys)'
|
||||
n = length(markers)
|
||||
x = linspace(0,10,n+2)[2:end-1]
|
||||
y = repmat(reverse(x)', n, 1)
|
||||
@@ -264,7 +266,7 @@ PlotExample("Groups and Subplots",
|
||||
"",
|
||||
[:(begin
|
||||
group = rand(map(i->"group $i",1:4),100)
|
||||
plot(rand(100), layout=@layout([a b;c]), group=group, n=3, linetype=[:bar :scatter :steppre])
|
||||
plot(rand(100), layout=@layout([a b;c]), group=group, linetype=[:bar :scatter :steppre])
|
||||
end)]
|
||||
),
|
||||
|
||||
@@ -325,11 +327,13 @@ function test_examples(pkgname::Symbol, idx::Int; debug = false, disp = true)
|
||||
end
|
||||
|
||||
# generate all plots and create a dict mapping idx --> plt
|
||||
function test_examples(pkgname::Symbol; debug = false, disp = true)
|
||||
function test_examples(pkgname::Symbol; debug = false, disp = true, sleep = nothing,
|
||||
skip = [], only = nothing)
|
||||
Plots._debugMode.on = debug
|
||||
plts = Dict()
|
||||
for i in 1:length(_examples)
|
||||
|
||||
only != nothing && !(i in only) && continue
|
||||
i in skip && continue
|
||||
try
|
||||
plt = test_examples(pkgname, i, debug=debug, disp=disp)
|
||||
plts[i] = plt
|
||||
@@ -337,6 +341,9 @@ function test_examples(pkgname::Symbol; debug = false, disp = true)
|
||||
# TODO: put error info into markdown?
|
||||
warn("Example $pkgname:$i:$(_examples[i].header) failed with: $ex")
|
||||
end
|
||||
if sleep != nothing
|
||||
Base.sleep(sleep)
|
||||
end
|
||||
end
|
||||
plts
|
||||
end
|
||||
|
||||
+97
-99
@@ -5,6 +5,8 @@
|
||||
const px = AbsoluteLength(0.254)
|
||||
const pct = Length{:pct, Float64}(1.0)
|
||||
|
||||
to_pixels(m::AbsoluteLength) = m.value / 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)
|
||||
@@ -89,6 +101,21 @@ end
|
||||
|
||||
Base.show(io::IO, layout::AbstractLayout) = print(io, "$(typeof(layout))$(size(layout))")
|
||||
|
||||
# create a new bbox
|
||||
function bbox(x, y, w, h; h_anchor = :left, v_anchor = :top)
|
||||
left = if h_anchor == :left
|
||||
x
|
||||
else
|
||||
x - w * (h_anchor == :right ? 1.0 : 0.5)
|
||||
end
|
||||
top = if v_anchor == :top
|
||||
y
|
||||
else
|
||||
y - h * (v_anchor == :bottom ? 1.0 : 0.5)
|
||||
end
|
||||
BoundingBox(left, top, w, h)
|
||||
end
|
||||
|
||||
# this is the available area for drawing everything in this layout... as percentages of total canvas
|
||||
bbox(layout::AbstractLayout) = layout.bbox
|
||||
bbox!(layout::AbstractLayout, bb::BoundingBox) = (layout.bbox = bb)
|
||||
@@ -97,25 +124,23 @@ bbox!(layout::AbstractLayout, bb::BoundingBox) = (layout.bbox = bb)
|
||||
Base.parent(layout::AbstractLayout) = layout.parent
|
||||
parent_bbox(layout::AbstractLayout) = bbox(parent(layout))
|
||||
|
||||
# NOTE: these should be implemented for subplots in each backend!
|
||||
# they represent the minimum size of the axes and guides
|
||||
min_padding_left(layout::AbstractLayout) = 0mm
|
||||
min_padding_top(layout::AbstractLayout) = 0mm
|
||||
min_padding_right(layout::AbstractLayout) = 0mm
|
||||
min_padding_bottom(layout::AbstractLayout) = 0mm
|
||||
# padding_w(layout::AbstractLayout) = left_padding(layout) + right_padding(layout)
|
||||
# padding_h(layout::AbstractLayout) = bottom_padding(layout) + top_padding(layout)
|
||||
# padding(layout::AbstractLayout) = (padding_w(layout), padding_h(layout))
|
||||
|
||||
padding_w(layout::AbstractLayout) = left_padding(layout) + right_padding(layout)
|
||||
padding_h(layout::AbstractLayout) = bottom_padding(layout) + top_padding(layout)
|
||||
padding(layout::AbstractLayout) = (padding_w(layout), padding_h(layout))
|
||||
update_position!(layout::AbstractLayout) = nothing
|
||||
update_child_bboxes!(layout::AbstractLayout, minimum_perimeter = [0mm,0mm,0mm,0mm]) = nothing
|
||||
|
||||
_update_position!(layout::AbstractLayout) = nothing
|
||||
update_child_bboxes!(layout::AbstractLayout) = nothing
|
||||
left(layout::AbstractLayout) = left(bbox(layout))
|
||||
top(layout::AbstractLayout) = top(bbox(layout))
|
||||
right(layout::AbstractLayout) = right(bbox(layout))
|
||||
bottom(layout::AbstractLayout) = bottom(bbox(layout))
|
||||
width(layout::AbstractLayout) = width(bbox(layout))
|
||||
height(layout::AbstractLayout) = height(bbox(layout))
|
||||
|
||||
width(layout::AbstractLayout) = width(layout.bbox)
|
||||
height(layout::AbstractLayout) = height(layout.bbox)
|
||||
|
||||
plotarea(layout::AbstractLayout) = defaultbox
|
||||
plotarea!(layout::AbstractLayout, bbox::BoundingBox) = nothing
|
||||
# pass these through to the bbox methods if there's no plotarea
|
||||
plotarea(layout::AbstractLayout) = bbox(layout)
|
||||
plotarea!(layout::AbstractLayout, bb::BoundingBox) = bbox!(layout, bb)
|
||||
|
||||
attr(layout::AbstractLayout, k::Symbol) = layout.attr[k]
|
||||
attr(layout::AbstractLayout, k::Symbol, v) = get(layout.attr, k, v)
|
||||
@@ -204,6 +229,12 @@ rightpad(layout::GridLayout) = layout.minpad[3]
|
||||
bottompad(layout::GridLayout) = layout.minpad[4]
|
||||
|
||||
|
||||
# here's how this works... first we recursively "update the minimum padding" (which
|
||||
# means to calculate the minimum size needed from the edge of the subplot to plot area)
|
||||
# for the whole layout tree. then we can compute the "padding borders" of this
|
||||
# layout as the biggest padding of the children on the perimeter. then we need to
|
||||
# recursively pass those borders back down the tree, one side at a time, but ONLY
|
||||
# to those perimeter children.
|
||||
|
||||
# leftpad, toppad, rightpad, bottompad
|
||||
function _update_min_padding!(layout::GridLayout)
|
||||
@@ -217,10 +248,11 @@ function _update_min_padding!(layout::GridLayout)
|
||||
end
|
||||
|
||||
|
||||
function _update_position!(layout::GridLayout)
|
||||
map(_update_position!, layout.grid)
|
||||
function update_position!(layout::GridLayout)
|
||||
map(update_position!, layout.grid)
|
||||
end
|
||||
|
||||
# some lengths are fixed... we have to split up the free space among the list v
|
||||
function recompute_lengths(v)
|
||||
# dump(v)
|
||||
tot = 0pct
|
||||
@@ -242,11 +274,11 @@ function recompute_lengths(v)
|
||||
end
|
||||
|
||||
# recursively compute the bounding boxes for the layout and plotarea (relative to canvas!)
|
||||
function update_child_bboxes!(layout::GridLayout)
|
||||
function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0mm,0mm])
|
||||
nr, nc = size(layout)
|
||||
|
||||
# create a matrix for each minimum padding direction
|
||||
_update_min_padding!(layout)
|
||||
# # create a matrix for each minimum padding direction
|
||||
# _update_min_padding!(layout)
|
||||
|
||||
minpad_left = map(leftpad, layout.grid)
|
||||
minpad_top = map(toppad, layout.grid)
|
||||
@@ -263,6 +295,12 @@ function update_child_bboxes!(layout::GridLayout)
|
||||
pad_bottom = maximum(minpad_bottom, 2)
|
||||
# @show pad_left pad_top pad_right pad_bottom
|
||||
|
||||
# make sure the perimeter match the parent
|
||||
pad_left[1] = max(pad_left[1], minimum_perimeter[1])
|
||||
pad_top[1] = max(pad_top[1], minimum_perimeter[2])
|
||||
pad_right[end] = max(pad_right[end], minimum_perimeter[3])
|
||||
pad_bottom[end] = max(pad_bottom[end], minimum_perimeter[4])
|
||||
|
||||
# scale this up to the total padding in each direction
|
||||
total_pad_horizontal = sum(pad_left + pad_right)
|
||||
total_pad_vertical = sum(pad_top + pad_bottom)
|
||||
@@ -303,11 +341,36 @@ function update_child_bboxes!(layout::GridLayout)
|
||||
child_height = pad_top[r] + plotarea_height + pad_bottom[r]
|
||||
bbox!(child, BoundingBox(child_left, child_top, child_width, child_height))
|
||||
|
||||
# this is the minimum perimeter as decided by this child's parent, so that
|
||||
# all children on this border have the same value
|
||||
min_child_perimeter = [
|
||||
c == 1 ? layout.minpad[1] : 0mm,
|
||||
r == 1 ? layout.minpad[2] : 0mm,
|
||||
c == nc ? layout.minpad[3] : 0mm,
|
||||
r == nr ? layout.minpad[4] : 0mm
|
||||
]
|
||||
|
||||
# recursively update the child's children
|
||||
update_child_bboxes!(child)
|
||||
update_child_bboxes!(child, min_child_perimeter)
|
||||
end
|
||||
end
|
||||
|
||||
# for each inset (floating) subplot, resolve the relative position
|
||||
# to absolute canvas coordinates, relative to the parent's plotarea
|
||||
function update_inset_bboxes!(plt::Plot)
|
||||
for sp in plt.inset_subplots
|
||||
p_area = Measures.resolve(plotarea(sp.parent), sp[:relative_bbox])
|
||||
# @show bbox(sp.parent) sp[:relative_bbox] p_area
|
||||
plotarea!(sp, p_area)
|
||||
|
||||
bbox!(sp, bbox(
|
||||
left(p_area) - leftpad(sp),
|
||||
top(p_area) - toppad(sp),
|
||||
width(p_area) + leftpad(sp) + rightpad(sp),
|
||||
height(p_area) + toppad(sp) + bottompad(sp)
|
||||
))
|
||||
end
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
@@ -376,40 +439,21 @@ end
|
||||
|
||||
layout_args(huh) = error("unhandled layout type $(typeof(huh)): $huh")
|
||||
|
||||
# # pass the layout arg through
|
||||
# function build_layout(d::KW)
|
||||
# build_layout(get(d, :layout, default(:layout)))
|
||||
# end
|
||||
#
|
||||
# function build_layout(n::Integer)
|
||||
# nr, nc = compute_gridsize(n, -1, -1)
|
||||
# build_layout(GridLayout(nr, nc), n)
|
||||
# end
|
||||
#
|
||||
# function build_layout{I<:Integer}(sztup::NTuple{2,I})
|
||||
# nr, nc = sztup
|
||||
# build_layout(GridLayout(nr, nc))
|
||||
# end
|
||||
#
|
||||
# function build_layout{I<:Integer}(sztup::NTuple{3,I})
|
||||
# n, nr, nc = sztup
|
||||
# nr, nc = compute_gridsize(n, nr, nc)
|
||||
# build_layout(GridLayout(nr, nc), n)
|
||||
# end
|
||||
#
|
||||
# # compute number of subplots
|
||||
# function build_layout(layout::GridLayout)
|
||||
# # recursively get the size of the grid
|
||||
# n = calc_num_subplots(layout)
|
||||
# build_layout(layout, n)
|
||||
# end
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
|
||||
function build_layout(args...)
|
||||
layout, n = layout_args(args...)
|
||||
build_layout(layout, n)
|
||||
end
|
||||
|
||||
# n is the number of subplots
|
||||
# # just a single subplot
|
||||
# function build_layout(sp::Subplot, n::Integer)
|
||||
# sp, Subplot[sp], SubplotMap(gensym() => sp)
|
||||
# end
|
||||
|
||||
# n is the number of subplots... build a grid and initialize the inner subplots recursively
|
||||
function build_layout(layout::GridLayout, n::Integer)
|
||||
nr, nc = size(layout)
|
||||
subplots = Subplot[]
|
||||
@@ -512,44 +556,13 @@ rowsize(v) = isrow(v) ? length(v.args) : 1
|
||||
|
||||
|
||||
function create_grid(expr::Expr)
|
||||
# cellsym = gensym(:cell)
|
||||
# @show expr
|
||||
if iscol(expr)
|
||||
create_grid_vcat(expr)
|
||||
# rowsizes = map(rowsize, expr.args)
|
||||
# rmin, rmax = extrema(rowsizes)
|
||||
# if rmin > 0 && rmin == rmax
|
||||
# # we have a grid... build the whole thing
|
||||
# # note: rmin is the number of columns
|
||||
# nr = length(expr.args)
|
||||
# nc = rmin
|
||||
#
|
||||
# :(let cell = GridLayout($nr, $nc)
|
||||
# $([:(cell[$r,$c] = $(create_grid(expr.args[r], c))) for r=1:nr, c=1:nc]...)
|
||||
# for r=1:nr
|
||||
# layout = $(create_grid(expr.args[r])
|
||||
# cell[r,]
|
||||
# $([:($cellsym[$r,1] = $(create_grid(expr.args[r]))) for r=1:length(expr.args)]...)
|
||||
# $cellsym
|
||||
# end)
|
||||
# else
|
||||
# # otherwise just build one row at a time
|
||||
# :(let
|
||||
# $cellsym = GridLayout($(length(expr.args)), 1)
|
||||
# $([:($cellsym[$i,1] = $(create_grid(expr.args[i]))) for i=1:length(expr.args)]...)
|
||||
# $cellsym
|
||||
# end)
|
||||
# end
|
||||
elseif isrow(expr)
|
||||
:(let cell = GridLayout(1, $(length(expr.args)))
|
||||
$([:(cell[1,$i] = $(create_grid(v))) for (i,v) in enumerate(expr.args)]...)
|
||||
cell
|
||||
end)
|
||||
# :(let
|
||||
# $cellsym = GridLayout(1, $(length(expr.args)))
|
||||
# $([:($cellsym[1,$i] = $(create_grid(expr.args[i]))) for i=1:length(expr.args)]...)
|
||||
# $cellsym
|
||||
# end)
|
||||
|
||||
elseif expr.head == :curly
|
||||
create_grid_curly(expr)
|
||||
@@ -562,17 +575,14 @@ end
|
||||
function create_grid_vcat(expr::Expr)
|
||||
rowsizes = map(rowsize, expr.args)
|
||||
rmin, rmax = extrema(rowsizes)
|
||||
# @show rmin, rmax
|
||||
if rmin > 0 && rmin == rmax
|
||||
# we have a grid... build the whole thing
|
||||
# note: rmin is the number of columns
|
||||
nr = length(expr.args)
|
||||
nc = rmin
|
||||
# @show nr, nc
|
||||
body = Expr(:block)
|
||||
for r=1:nr
|
||||
arg = expr.args[r]
|
||||
# @show r, arg
|
||||
if isrow(arg)
|
||||
for (c,item) in enumerate(arg.args)
|
||||
push!(body.args, :(cell[$r,$c] = $(create_grid(item))))
|
||||
@@ -581,30 +591,16 @@ function create_grid_vcat(expr::Expr)
|
||||
push!(body.args, :(cell[$r,1] = $(create_grid(arg))))
|
||||
end
|
||||
end
|
||||
# @show body
|
||||
:(let cell = GridLayout($nr, $nc)
|
||||
$body
|
||||
cell
|
||||
end)
|
||||
# :(let cell = GridLayout($nr, $nc)
|
||||
# $([:(cell[$r,$c] = $(create_grid(expr.args[r], c))) for r=1:nr, c=1:nc]...)
|
||||
# for r=1:nr
|
||||
# layout = $(create_grid(expr.args[r])
|
||||
# cell[r,]
|
||||
# $([:($cellsym[$r,1] = $(create_grid(expr.args[r]))) for r=1:length(expr.args)]...)
|
||||
# $cellsym
|
||||
# end)
|
||||
else
|
||||
# otherwise just build one row at a time
|
||||
:(let cell = GridLayout($(length(expr.args)), 1)
|
||||
$([:(cell[$i,1] = $(create_grid(v))) for (i,v) in enumerate(expr.args)]...)
|
||||
cell
|
||||
end)
|
||||
# :(let
|
||||
# $cellsym = GridLayout($(length(expr.args)), 1)
|
||||
# $([:($cellsym[$i,1] = $(create_grid(expr.args[i]))) for i=1:length(expr.args)]...)
|
||||
# $cellsym
|
||||
# end)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -644,7 +640,9 @@ end
|
||||
function link_axes!(a::AbstractArray{AbstractLayout}, axissym::Symbol)
|
||||
subplots = filter(l -> isa(l, Subplot), a)
|
||||
axes = [sp.attr[axissym] for sp in subplots]
|
||||
link_axes!(axes...)
|
||||
if length(axes) > 0
|
||||
link_axes!(axes...)
|
||||
end
|
||||
end
|
||||
|
||||
# don't do anything for most layout types
|
||||
|
||||
@@ -151,6 +151,36 @@ for mime in keys(_mimeformats)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# A backup, if no PNG generation is defined, is to try to make a PDF and use FileIO to convert
|
||||
|
||||
if is_installed("FileIO")
|
||||
@eval begin
|
||||
import FileIO
|
||||
function _writemime(io::IO, ::MIME"image/png", plt::Plot)
|
||||
fn = tempname()
|
||||
|
||||
# first save a pdf file
|
||||
pdf(plt, fn)
|
||||
|
||||
# load that pdf into a FileIO Stream
|
||||
s = FileIO.load(fn * ".pdf")
|
||||
|
||||
# save a png
|
||||
pngfn = fn * ".png"
|
||||
FileIO.save(pngfn, s)
|
||||
|
||||
# now write from the file
|
||||
write(io, readall(open(pngfn)))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# function html_output_format(fmt)
|
||||
# if fmt == "png"
|
||||
# @eval function Base.writemime(io::IO, ::MIME"text/html", plt::Plot)
|
||||
|
||||
+113
-31
@@ -94,6 +94,9 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
for (idx, sp) in enumerate(plt.subplots)
|
||||
_initialize_subplot(plt, sp)
|
||||
serieslist = series_list(sp)
|
||||
if sp in sp.plt.inset_subplots
|
||||
push!(plt.inset_subplots, sp)
|
||||
end
|
||||
sp.plt = plt
|
||||
sp.attr[:subplot_index] = idx
|
||||
for series in serieslist
|
||||
@@ -102,6 +105,25 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
end
|
||||
end
|
||||
|
||||
# # just in case the backend needs to set up the plot (make it current or something)
|
||||
# _prepare_plot_object(plt)
|
||||
|
||||
# first apply any args for the subplots
|
||||
for (idx,sp) in enumerate(plt.subplots)
|
||||
_update_subplot_args(plt, sp, d, idx, remove_pair = false)
|
||||
end
|
||||
|
||||
# # now we can get rid of the axis keys without a letter
|
||||
# for k in keys(_axis_defaults)
|
||||
# delete!(d, k)
|
||||
# for letter in (:x,:y,:z)
|
||||
# delete!(d, Symbol(letter,k))
|
||||
# end
|
||||
# end
|
||||
|
||||
# do we need to link any axes together?
|
||||
link_axes!(plt.layout, plt[:link])
|
||||
|
||||
# finish up
|
||||
current(plt)
|
||||
if get(d, :show, default(:show))
|
||||
@@ -142,7 +164,7 @@ end
|
||||
function _apply_series_recipe(plt::Plot, d::KW)
|
||||
st = d[:seriestype]
|
||||
# @show st
|
||||
if st in supportedTypes()
|
||||
if st in supported_types()
|
||||
|
||||
# getting ready to add the series... last update to subplot from anything
|
||||
# that might have been added during series recipes
|
||||
@@ -173,7 +195,7 @@ function _apply_series_recipe(plt::Plot, d::KW)
|
||||
|
||||
|
||||
# add the series!
|
||||
warnOnUnsupportedArgs(plt.backend, d)
|
||||
warnOnUnsupported_args(plt.backend, d)
|
||||
warnOnUnsupported(plt.backend, d)
|
||||
series = Series(d)
|
||||
push!(plt.series_list, series)
|
||||
@@ -263,7 +285,7 @@ function _plot!(plt::Plot, d::KW, args...)
|
||||
kw[:series_plotindex] = plt.n
|
||||
|
||||
# check that the backend will support the command and add it to the list
|
||||
warnOnUnsupportedScales(plt.backend, kw)
|
||||
warnOnUnsupported_scales(plt.backend, kw)
|
||||
push!(kw_list, kw)
|
||||
|
||||
# handle error bars by creating new recipedata data... these will have
|
||||
@@ -305,17 +327,17 @@ function _plot!(plt::Plot, d::KW, args...)
|
||||
end
|
||||
end
|
||||
|
||||
# merge in anything meant for plot/subplot
|
||||
# merge in anything meant for plot/subplot/axis
|
||||
for kw in kw_list
|
||||
for (k,v) in kw
|
||||
for defdict in (_plot_defaults, _subplot_defaults)
|
||||
for defdict in (_plot_defaults,)
|
||||
# _subplot_defaults,
|
||||
# _axis_defaults,
|
||||
# _axis_defaults_byletter)
|
||||
if haskey(defdict, k)
|
||||
d[k] = pop!(kw, k)
|
||||
end
|
||||
end
|
||||
# if haskey(_plot_defaults, k) || haskey(_subplot_defaults, k)
|
||||
# d[k] = v
|
||||
# end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -323,6 +345,7 @@ function _plot!(plt::Plot, d::KW, args...)
|
||||
_update_plot_args(plt, d)
|
||||
if !plt.init
|
||||
plt.o = _create_backend_figure(plt)
|
||||
# DD(d)
|
||||
|
||||
# create the layout and subplots from the inputs
|
||||
plt.layout, plt.subplots, plt.spmap = build_layout(plt.attr)
|
||||
@@ -334,14 +357,71 @@ function _plot!(plt::Plot, d::KW, args...)
|
||||
plt.init = true
|
||||
end
|
||||
|
||||
# just in case the backend needs to set up the plot (make it current or something)
|
||||
_prepare_plot_object(plt)
|
||||
|
||||
# handle inset subplots
|
||||
insets = plt[:inset_subplots]
|
||||
if insets != nothing
|
||||
for inset in insets
|
||||
parent, bb = is_2tuple(inset) ? inset : (nothing, inset)
|
||||
P = typeof(parent)
|
||||
if P <: Integer
|
||||
parent = plt.subplots[parent]
|
||||
elseif P == Symbol
|
||||
parent = plt.spmap[parent]
|
||||
else
|
||||
parent = plt.layout
|
||||
end
|
||||
sp = Subplot(backend(), parent=parent)
|
||||
sp.plt = plt
|
||||
sp.attr[:relative_bbox] = bb
|
||||
push!(plt.subplots, sp)
|
||||
sp.attr[:subplot_index] = length(plt.subplots)
|
||||
push!(plt.inset_subplots, sp)
|
||||
end
|
||||
end
|
||||
|
||||
# we'll keep a map of subplot to an attribute override dict.
|
||||
# any series which belong to that subplot
|
||||
sp_attrs = Dict{Subplot,Any}()
|
||||
for (i,kw) in enumerate(kw_list)
|
||||
# get the Subplot object to which the series belongs
|
||||
sp = get(kw, :subplot, :auto)
|
||||
sp = if sp == :auto
|
||||
mod1(i,length(plt.subplots))
|
||||
else
|
||||
slice_arg(sp, i)
|
||||
end
|
||||
sp = kw[:subplot] = get_subplot(plt, sp)
|
||||
# idx = get_subplot_index(plt, sp)
|
||||
attr = KW()
|
||||
|
||||
for (k,v) in kw
|
||||
for defdict in (_subplot_defaults,
|
||||
_axis_defaults,
|
||||
_axis_defaults_byletter)
|
||||
if haskey(defdict, k)
|
||||
attr[k] = pop!(kw, k)
|
||||
end
|
||||
end
|
||||
end
|
||||
sp_attrs[sp] = attr
|
||||
end
|
||||
|
||||
|
||||
|
||||
# # just in case the backend needs to set up the plot (make it current or something)
|
||||
# _prepare_plot_object(plt)
|
||||
|
||||
# first apply any args for the subplots
|
||||
for (idx,sp) in enumerate(plt.subplots)
|
||||
_update_subplot_args(plt, sp, d, idx, remove_pair = false)
|
||||
# if we picked up any subplot-specific overrides, merge them here
|
||||
attr = merge(d, get(sp_attrs, sp, KW()))
|
||||
# DD(attr, "sp$idx")
|
||||
_update_subplot_args(plt, sp, attr, idx, remove_pair = false)
|
||||
end
|
||||
|
||||
|
||||
|
||||
# do we need to link any axes together?
|
||||
link_axes!(plt.layout, plt[:link])
|
||||
|
||||
@@ -351,19 +431,17 @@ function _plot!(plt::Plot, d::KW, args...)
|
||||
# this is it folks!
|
||||
# TODO: we probably shouldn't use i for tracking series index, but rather explicitly track it in recipes
|
||||
for (i,kw) in enumerate(kw_list)
|
||||
# if !(get(kw, :seriestype, :none) in (:xerror, :yerror))
|
||||
# plt.n += 1
|
||||
# end
|
||||
command_idx = kw[:series_plotindex] - kw_list[1][:series_plotindex] + 1
|
||||
|
||||
# get the Subplot object to which the series belongs
|
||||
sp = get(kw, :subplot, :auto)
|
||||
sp = if sp == :auto
|
||||
mod1(i,length(plt.subplots))
|
||||
else
|
||||
slice_arg(sp, i)
|
||||
end
|
||||
sp = kw[:subplot] = get_subplot(plt, sp)
|
||||
# # get the Subplot object to which the series belongs
|
||||
# sp = get(kw, :subplot, :auto)
|
||||
# sp = if sp == :auto
|
||||
# mod1(i,length(plt.subplots))
|
||||
# else
|
||||
# slice_arg(sp, i)
|
||||
# end
|
||||
# sp = kw[:subplot] = get_subplot(plt, sp)
|
||||
sp = kw[:subplot]
|
||||
idx = get_subplot_index(plt, sp)
|
||||
|
||||
# strip out series annotations (those which are based on series x/y coords)
|
||||
@@ -393,15 +471,6 @@ function _plot!(plt::Plot, d::KW, args...)
|
||||
_apply_series_recipe(plt, kw)
|
||||
end
|
||||
|
||||
# # everything is processed, time to compute the layout bounding boxes
|
||||
# _before_layout_calcs(plt)
|
||||
# w, h = plt.attr[:size]
|
||||
# plt.layout.bbox = BoundingBox(0mm, 0mm, w*px, h*px)
|
||||
# update_child_bboxes!(plt.layout)
|
||||
#
|
||||
# # TODO just need to pass plt... and we should do all non-series updates here
|
||||
# _update_plot_object(plt)
|
||||
|
||||
current(plt)
|
||||
|
||||
# note: lets ignore the show param and effectively use the semicolon at the end of the REPL statement
|
||||
@@ -429,8 +498,21 @@ function prepare_output(plt::Plot)
|
||||
|
||||
w, h = plt.attr[:size]
|
||||
plt.layout.bbox = BoundingBox(0mm, 0mm, w*px, h*px)
|
||||
|
||||
# One pass down and back up the tree to compute the minimum padding
|
||||
# of the children on the perimeter. This is an backend callback.
|
||||
_update_min_padding!(plt.layout)
|
||||
for sp in plt.inset_subplots
|
||||
_update_min_padding!(sp)
|
||||
end
|
||||
|
||||
# now another pass down, to update the bounding boxes
|
||||
update_child_bboxes!(plt.layout)
|
||||
|
||||
# update those bounding boxes of inset subplots
|
||||
update_inset_bboxes!(plt)
|
||||
|
||||
# the backend callback, to reposition subplots, etc
|
||||
_update_plot_object(plt)
|
||||
end
|
||||
|
||||
|
||||
+119
-39
@@ -53,7 +53,47 @@ end
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
|
||||
const _series_recipe_deps = Dict()
|
||||
|
||||
function series_recipe_dependencies(st::Symbol, deps::Symbol...)
|
||||
_series_recipe_deps[st] = deps
|
||||
end
|
||||
|
||||
function seriestype_supported(st::Symbol)
|
||||
seriestype_supported(backend(), st)
|
||||
end
|
||||
|
||||
# returns :no, :native, or :recipe depending on how it's supported
|
||||
function seriestype_supported(pkg::AbstractBackend, st::Symbol)
|
||||
# is it natively supported
|
||||
if st in supported_types(pkg)
|
||||
return :native
|
||||
end
|
||||
|
||||
haskey(_series_recipe_deps, st) || return :no
|
||||
|
||||
supported = true
|
||||
for dep in _series_recipe_deps[st]
|
||||
if seriestype_supported(pkg, dep) == :no
|
||||
supported = false
|
||||
end
|
||||
end
|
||||
supported ? :recipe : :no
|
||||
end
|
||||
|
||||
macro deps(st, args...)
|
||||
:(series_recipe_dependencies($(quot(st)), $(map(quot, args)...)))
|
||||
end
|
||||
|
||||
# get a list of all seriestypes
|
||||
function all_seriestypes()
|
||||
sts = Set{Symbol}(keys(_series_recipe_deps))
|
||||
for bsym in backends()
|
||||
btype = _backendType[bsym]
|
||||
sts = union(sts, Set{Symbol}(supported_types(btype())))
|
||||
end
|
||||
sort(collect(sts))
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
@@ -156,21 +196,23 @@ end
|
||||
seriestype := :path
|
||||
()
|
||||
end
|
||||
@deps line path
|
||||
|
||||
@recipe function f(::Type{Val{:sticks}}, x, y, z)
|
||||
nx = length(x)
|
||||
n = 3nx
|
||||
newx, newy = zeros(n), zeros(n)
|
||||
for i=1:nx
|
||||
rng = 3i-2:3i
|
||||
newx[rng] = x[i]
|
||||
newy[rng] = [0., y[i], 0.]
|
||||
end
|
||||
x := newx
|
||||
y := newy
|
||||
seriestype := :path
|
||||
()
|
||||
end
|
||||
# @recipe function f(::Type{Val{:sticks}}, x, y, z)
|
||||
# nx = length(x)
|
||||
# n = 3nx
|
||||
# newx, newy = zeros(n), zeros(n)
|
||||
# for i=1:nx
|
||||
# rng = 3i-2:3i
|
||||
# newx[rng] = x[i]
|
||||
# newy[rng] = [0., y[i], 0.]
|
||||
# end
|
||||
# x := newx
|
||||
# y := newy
|
||||
# seriestype := :path
|
||||
# ()
|
||||
# end
|
||||
# @deps sticks path
|
||||
|
||||
@recipe function f(::Type{Val{:hline}}, x, y, z)
|
||||
xmin, xmax = axis_limits(d[:subplot][:xaxis])
|
||||
@@ -182,6 +224,7 @@ end
|
||||
seriestype := :path
|
||||
()
|
||||
end
|
||||
@deps hline path
|
||||
|
||||
@recipe function f(::Type{Val{:vline}}, x, y, z)
|
||||
ymin, ymax = axis_limits(d[:subplot][:yaxis])
|
||||
@@ -193,6 +236,7 @@ end
|
||||
seriestype := :path
|
||||
()
|
||||
end
|
||||
@deps vline path
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# steps
|
||||
@@ -231,6 +275,7 @@ end
|
||||
end
|
||||
()
|
||||
end
|
||||
@deps steppre path scatter
|
||||
|
||||
# create a path from steps
|
||||
@recipe function f(::Type{Val{:steppost}}, x, y, z)
|
||||
@@ -251,6 +296,7 @@ end
|
||||
end
|
||||
()
|
||||
end
|
||||
@deps steppost path scatter
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -289,6 +335,7 @@ sticks_fillfrom(fr::AVec, i::Integer) = fr[mod1(i, length(fr))]
|
||||
end
|
||||
()
|
||||
end
|
||||
@deps sticks path scatter
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -350,6 +397,7 @@ end
|
||||
seriestype := :path
|
||||
()
|
||||
end
|
||||
@deps bar path
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Histograms
|
||||
@@ -402,6 +450,7 @@ end
|
||||
seriestype := :bar
|
||||
()
|
||||
end
|
||||
@deps histogram bar
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Histogram 2D
|
||||
@@ -443,6 +492,23 @@ centers(v::AVec) = v[1] + cumsum(diff(v))
|
||||
seriestype := :heatmap
|
||||
()
|
||||
end
|
||||
@deps histogram2d heatmap
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# scatter 3d
|
||||
|
||||
@recipe function f(::Type{Val{:scatter3d}}, x, y, z)
|
||||
seriestype := :path3d
|
||||
if d[:markershape] == :none
|
||||
markershape := :circle
|
||||
end
|
||||
linewidth := 0
|
||||
linealpha := 0
|
||||
()
|
||||
end
|
||||
|
||||
# note: don't add dependencies because this really isn't a drop-in replacement
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Box Plot
|
||||
@@ -540,7 +606,7 @@ notch_width(q2, q4, N) = 1.58 * (q4-q2)/sqrt(N)
|
||||
# Outliers
|
||||
@series begin
|
||||
seriestype := :scatter
|
||||
markershape := :ellipse
|
||||
markershape := :circle
|
||||
x := outliers_x
|
||||
y := outliers_y
|
||||
label := ""
|
||||
@@ -549,9 +615,8 @@ notch_width(q2, q4, N) = 1.58 * (q4-q2)/sqrt(N)
|
||||
end
|
||||
|
||||
() # expects a tuple returned
|
||||
|
||||
# KW[d]
|
||||
end
|
||||
@deps boxplot shape scatter
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Violin Plot
|
||||
@@ -560,13 +625,18 @@ end
|
||||
# otherwise, just use a histogram
|
||||
if is_installed("KernelDensity")
|
||||
@eval import KernelDensity
|
||||
@eval function violin_coords(y, bins = 30)
|
||||
kd = KernelDensity.kde(y, npoints = isa(bins, Integer) ? bins : 30)
|
||||
@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, bins = 30)
|
||||
edges, widths = hist(y, isa(bins, Integer) ? bins : 30)
|
||||
@eval function violin_coords(y; trim::Bool=false)
|
||||
edges, widths = hist(y, 30)
|
||||
centers = 0.5 * (edges[1:end-1] + edges[2:end])
|
||||
ymin, ymax = extrema(y)
|
||||
vcat(0.0, widths, 0.0), vcat(ymin, centers, ymax)
|
||||
@@ -575,7 +645,7 @@ end
|
||||
|
||||
|
||||
# function apply_series_recipe(d::KW, ::Type{Val{:violin}})
|
||||
@recipe function f(::Type{Val{:violin}}, x, y, z)
|
||||
@recipe function f(::Type{Val{:violin}}, x, y, z; trim=true)
|
||||
# dumpdict(d, "box before", true)
|
||||
# TODO: add scatter series with outliers
|
||||
|
||||
@@ -587,7 +657,7 @@ end
|
||||
|
||||
# get the edges and widths
|
||||
y = d[:y][groupby.groupIds[i]]
|
||||
widths, centers = violin_coords(y)
|
||||
widths, centers = violin_coords(y, trim=trim)
|
||||
|
||||
# normalize
|
||||
widths = _box_halfwidth * widths / maximum(widths)
|
||||
@@ -604,25 +674,32 @@ end
|
||||
# n = length(groupby.groupLabels)
|
||||
# xticks --> (linspace(0.5,n-0.5,n), groupby.groupLabels)
|
||||
|
||||
# clean up d
|
||||
pop!(d, :trim)
|
||||
|
||||
d[:x], d[:y] = shape_coords(shapes)
|
||||
()
|
||||
|
||||
# KW[d]
|
||||
end
|
||||
@deps violin shape
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# density
|
||||
|
||||
@recipe function f(::Type{Val{:density}}, x, y, z)
|
||||
newx, newy = violin_coords(y, d[:bins])
|
||||
@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
|
||||
|
||||
# clean up d
|
||||
pop!(d, :trim)
|
||||
|
||||
()
|
||||
end
|
||||
@deps density path
|
||||
|
||||
|
||||
|
||||
@@ -651,9 +728,9 @@ function error_coords(xorig, yorig, ebar)
|
||||
|
||||
# for each point, create a line segment from the bottom to the top of the errorbar
|
||||
for i = 1:max(length(xorig), length(yorig))
|
||||
xi = get_mod(xorig, i)
|
||||
yi = get_mod(yorig, i)
|
||||
ebi = get_mod(ebar, i)
|
||||
xi = cycle(xorig, i)
|
||||
yi = cycle(yorig, i)
|
||||
ebi = cycle(ebar, i)
|
||||
nanappend!(x, [xi, xi])
|
||||
e1, e2 = if istuple(ebi)
|
||||
first(ebi), last(ebi)
|
||||
@@ -675,6 +752,7 @@ end
|
||||
d[:x], d[:y] = error_coords(d[:x], d[:y], error_zipit(d[:yerror]))
|
||||
()
|
||||
end
|
||||
@deps yerror path
|
||||
|
||||
@recipe function f(::Type{Val{:xerror}}, x, y, z)
|
||||
error_style!(d)
|
||||
@@ -682,6 +760,7 @@ end
|
||||
d[:y], d[:x] = error_coords(d[:y], d[:x], error_zipit(d[:xerror]))
|
||||
()
|
||||
end
|
||||
@deps xerror path
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -702,11 +781,11 @@ function quiver_using_arrows(d::KW)
|
||||
x, y = zeros(0), zeros(0)
|
||||
for i = 1:max(length(xorig), length(yorig))
|
||||
# get the starting position
|
||||
xi = get_mod(xorig, i)
|
||||
yi = get_mod(yorig, i)
|
||||
xi = cycle(xorig, i)
|
||||
yi = cycle(yorig, i)
|
||||
|
||||
# get the velocity
|
||||
vi = get_mod(velocity, i)
|
||||
vi = cycle(velocity, i)
|
||||
vx, vy = if istuple(vi)
|
||||
first(vi), last(vi)
|
||||
elseif isscalar(vi)
|
||||
@@ -728,8 +807,8 @@ end
|
||||
|
||||
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
|
||||
function quiver_using_hack(d::KW)
|
||||
label := ""
|
||||
seriestype := :shape
|
||||
d[:label] = ""
|
||||
d[:seriestype] = :shape
|
||||
|
||||
velocity = error_zipit(d[:quiver])
|
||||
xorig, yorig = d[:x], d[:y]
|
||||
@@ -739,12 +818,12 @@ function quiver_using_hack(d::KW)
|
||||
for i = 1:max(length(xorig), length(yorig))
|
||||
|
||||
# get the starting position
|
||||
xi = get_mod(xorig, i)
|
||||
yi = get_mod(yorig, i)
|
||||
xi = cycle(xorig, i)
|
||||
yi = cycle(yorig, i)
|
||||
p = P2(xi, yi)
|
||||
|
||||
# get the velocity
|
||||
vi = get_mod(velocity, i)
|
||||
vi = cycle(velocity, i)
|
||||
vx, vy = if istuple(vi)
|
||||
first(vi), last(vi)
|
||||
elseif isscalar(vi)
|
||||
@@ -774,13 +853,14 @@ end
|
||||
|
||||
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
|
||||
@recipe function f(::Type{Val{:quiver}}, x, y, z)
|
||||
if :arrow in supportedArgs()
|
||||
if :arrow in supported_args()
|
||||
quiver_using_arrows(d)
|
||||
else
|
||||
quiver_using_hack(d)
|
||||
end
|
||||
()
|
||||
end
|
||||
@deps quiver shape path
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
+30
-6
@@ -17,8 +17,8 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
|
||||
plotIndex += 1
|
||||
end
|
||||
|
||||
aliasesAndAutopick(d, :linestyle, _styleAliases, supportedStyles(pkg), plotIndex)
|
||||
aliasesAndAutopick(d, :markershape, _markerAliases, supportedMarkers(pkg), plotIndex)
|
||||
aliasesAndAutopick(d, :linestyle, _styleAliases, supported_styles(pkg), plotIndex)
|
||||
aliasesAndAutopick(d, :markershape, _markerAliases, supported_markers(pkg), plotIndex)
|
||||
|
||||
# update color
|
||||
d[:seriescolor] = getSeriesRGBColor(d[:seriescolor], sp, plotIndex)
|
||||
@@ -46,17 +46,20 @@ function _add_defaults!(d::KW, plt::Plot, sp::Subplot, commandIndex::Int)
|
||||
d[:markerstrokecolor] = c
|
||||
|
||||
# update alphas
|
||||
for asym in (:linealpha, :markeralpha, :markerstrokealpha, :fillalpha)
|
||||
for asym in (:linealpha, :markeralpha, :fillalpha)
|
||||
if d[asym] == nothing
|
||||
d[asym] = d[:seriesalpha]
|
||||
end
|
||||
end
|
||||
if d[:markerstrokealpha] == nothing
|
||||
d[:markerstrokealpha] = d[:markeralpha]
|
||||
end
|
||||
|
||||
# scatter plots don't have a line, but must have a shape
|
||||
if d[:seriestype] in (:scatter, :scatter3d)
|
||||
d[:linewidth] = 0
|
||||
if d[:markershape] == :none
|
||||
d[:markershape] = :ellipse
|
||||
d[:markershape] = :circle
|
||||
end
|
||||
end
|
||||
|
||||
@@ -117,7 +120,10 @@ immutable SliceIt end
|
||||
end
|
||||
|
||||
# this is the default "type recipe"... just pass the object through
|
||||
@recipe f{T}(::Type{T}, v::T) = v
|
||||
@recipe f{T<:Any}(::Type{T}, v::T) = v
|
||||
|
||||
# this should catch unhandled "series recipes" and error with a nice message
|
||||
@recipe f{V<:Val}(::Type{V}, x, y, z) = error("The backend must not support the series type $V, and there isn't a series recipe defined.")
|
||||
|
||||
_apply_type_recipe(d, v) = RecipesBase.apply_recipe(d, typeof(v), v)[1].args[1]
|
||||
|
||||
@@ -156,6 +162,24 @@ end
|
||||
SliceIt, nothing, y, nothing
|
||||
end
|
||||
end
|
||||
|
||||
# if there's more than 3 inputs, it can't be passed directly to SliceIt
|
||||
# so we'll apply_type_recipe to all of them
|
||||
@recipe function f(v1, v2, v3, v4, vrest...)
|
||||
did_replace = false
|
||||
newargs = map(v -> begin
|
||||
newv = _apply_type_recipe(d, v)
|
||||
if newv !== v
|
||||
did_replace = true
|
||||
end
|
||||
newv
|
||||
end, (v1, v2, v3, v4, vrest...))
|
||||
if !did_replace
|
||||
error("Couldn't process recipe args: $(map(typeof, (v1, v2, v3, v4, vrest...)))")
|
||||
end
|
||||
newargs
|
||||
end
|
||||
|
||||
# @recipe f(x, y, z) = SliceIt, apply_recipe(typeof(x), x), apply_recipe(typeof(y), y), apply_recipe(typeof(z), z)
|
||||
# @recipe f(x, y) = SliceIt, apply_recipe(typeof(x), x), apply_recipe(typeof(y), y), nothing
|
||||
# @recipe f(y) = SliceIt, nothing, apply_recipe(typeof(y), y), nothing
|
||||
@@ -323,7 +347,7 @@ end
|
||||
@recipe function f(fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, u::AVec)
|
||||
mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u)
|
||||
end
|
||||
@recipe function f(fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, umin::Number, umax::Number, numPointsn = 200)
|
||||
@recipe function f(fx::FuncOrFuncs, fy::FuncOrFuncs, fz::FuncOrFuncs, umin::Number, umax::Number, numPoints = 200)
|
||||
fx, fy, fz, linspace(umin, umax, numPoints)
|
||||
end
|
||||
|
||||
|
||||
+6
-5
@@ -36,11 +36,12 @@ get_subplot_index(plt::Plot, sp::Subplot) = findfirst(_ -> _ === sp, plt.subplot
|
||||
series_list(sp::Subplot) = filter(series -> series.d[:subplot] === sp, sp.plt.series_list)
|
||||
|
||||
function should_add_to_legend(series::Series)
|
||||
!(series.d[:label] == "" || series.d[:seriestype] in (
|
||||
:hexbin,:histogram2d,:hline,:vline,
|
||||
:contour,:contour3d,:surface,:wireframe,
|
||||
:heatmap,:path3d,:scatter3d, :pie, :image
|
||||
))
|
||||
series.d[:primary] && series.d[:label] != "" &&
|
||||
!(series.d[:seriestype] in (
|
||||
:hexbin,:histogram2d,:hline,:vline,
|
||||
:contour,:contour3d,:surface,:wireframe,
|
||||
:heatmap, :pie, :image
|
||||
))
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
+3
-1
@@ -73,12 +73,14 @@ type Plot{T<:AbstractBackend} <: AbstractPlot{T}
|
||||
subplots::Vector{Subplot}
|
||||
spmap::SubplotMap # provide any label as a map to a subplot
|
||||
layout::AbstractLayout
|
||||
inset_subplots::Vector{Subplot} # list of inset subplots
|
||||
init::Bool
|
||||
end
|
||||
|
||||
function Plot()
|
||||
Plot(backend(), 0, KW(), KW(), Series[], nothing,
|
||||
Subplot[], SubplotMap(), EmptyLayout(), false)
|
||||
Subplot[], SubplotMap(), EmptyLayout(),
|
||||
Subplot[], false)
|
||||
end
|
||||
|
||||
# TODO: make a decision... should plt[1] return the first subplot or the first series??
|
||||
|
||||
+54
-7
@@ -131,7 +131,7 @@ function replace_image_with_heatmap{T<:Colorant}(z::Array{T})
|
||||
end
|
||||
|
||||
function imageHack(d::KW)
|
||||
:heatmap in supportedTypes() || error("Neither :image or :heatmap are supported!")
|
||||
:heatmap in supported_types() || error("Neither :image or :heatmap are supported!")
|
||||
d[:seriestype] = :heatmap
|
||||
d[:z], d[:fillcolor] = replace_image_with_heatmap(d[:z].surf)
|
||||
end
|
||||
@@ -142,9 +142,9 @@ end
|
||||
nop() = nothing
|
||||
notimpl() = error("This has not been implemented yet")
|
||||
|
||||
get_mod(v::AVec, idx::Int) = v[mod1(idx, length(v))]
|
||||
get_mod(v::AMat, idx::Int) = size(v,1) == 1 ? v[1, mod1(idx, size(v,2))] : v[:, mod1(idx, size(v,2))]
|
||||
get_mod(v, idx::Int) = v
|
||||
Base.cycle(v::AVec, idx::Int) = v[mod1(idx, length(v))]
|
||||
Base.cycle(v::AMat, idx::Int) = size(v,1) == 1 ? v[1, mod1(idx, size(v,2))] : v[:, mod1(idx, size(v,2))]
|
||||
Base.cycle(v, idx::Int) = v
|
||||
|
||||
makevec(v::AVec) = v
|
||||
makevec{T}(v::T) = T[v]
|
||||
@@ -232,6 +232,27 @@ function heatmap_edges(v::AVec)
|
||||
end
|
||||
|
||||
|
||||
function calc_r_extrema(x, y)
|
||||
xmin, xmax = extrema(x)
|
||||
ymin, ymax = extrema(y)
|
||||
r = 0.5 * min(xmax - xmin, ymax - ymin)
|
||||
extrema(r)
|
||||
end
|
||||
|
||||
function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y))
|
||||
rmin, rmax = r_extrema
|
||||
phi, r = x, y
|
||||
r = 0.5 * (r - rmin) / (rmax - rmin)
|
||||
n = max(length(phi), length(r))
|
||||
x = zeros(n)
|
||||
y = zeros(n)
|
||||
for i in 1:n
|
||||
x[i] = cycle(r,i) * cos(cycle(phi,i))
|
||||
y[i] = cycle(r,i) * sin(cycle(phi,i))
|
||||
end
|
||||
x, y
|
||||
end
|
||||
|
||||
function fakedata(sz...)
|
||||
y = zeros(sz...)
|
||||
for r in 2:size(y,1)
|
||||
@@ -260,6 +281,8 @@ ismatrix(::Any) = false
|
||||
isscalar(::Real) = true
|
||||
isscalar(::Any) = false
|
||||
|
||||
is_2tuple(v) = typeof(v) <: Tuple && length(v) == 2
|
||||
|
||||
|
||||
isvertical(d::KW) = get(d, :orientation, :vertical) in (:vertical, :v, :vert)
|
||||
|
||||
@@ -285,6 +308,30 @@ Base.merge(a::AbstractVector, b::AbstractVector) = sort(unique(vcat(a,b)))
|
||||
nanpush!(a::AbstractVector, b) = (push!(a, NaN); push!(a, b))
|
||||
nanappend!(a::AbstractVector, b) = (push!(a, NaN); append!(a, b))
|
||||
|
||||
function nansplit(v::AVec)
|
||||
vs = Vector{eltype(v)}[]
|
||||
while true
|
||||
idx = findfirst(isnan, v)
|
||||
if idx <= 0
|
||||
# no nans
|
||||
push!(vs, v)
|
||||
break
|
||||
elseif idx > 1
|
||||
push!(vs, v[1:idx-1])
|
||||
end
|
||||
v = v[idx+1:end]
|
||||
end
|
||||
vs
|
||||
end
|
||||
|
||||
function nanvcat(vs::AVec)
|
||||
v_out = zeros(0)
|
||||
for v in vs
|
||||
nanappend!(v_out, v)
|
||||
end
|
||||
v_out
|
||||
end
|
||||
|
||||
# given an array of discrete values, turn it into an array of indices of the unique values
|
||||
# returns the array of indices (znew) and a vector of unique values (vals)
|
||||
function indices_and_unique_values(z::AbstractArray)
|
||||
@@ -508,9 +555,9 @@ 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], xy[1])
|
||||
expand_extrema!(sp.attr[:yaxis], xy[2])
|
||||
expand_extrema!(sp.attr[:zaxis], xy[3])
|
||||
expand_extrema!(sp.attr[:xaxis], xyz[1])
|
||||
expand_extrema!(sp.attr[:yaxis], xyz[2])
|
||||
expand_extrema!(sp.attr[:zaxis], xyz[3])
|
||||
_series_updated(plt, series)
|
||||
end
|
||||
|
||||
|
||||
+8
-6
@@ -22,7 +22,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.7.0"
|
||||
const _current_plots_version = v"0.7.1"
|
||||
|
||||
|
||||
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
|
||||
@@ -45,17 +45,19 @@ function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = is
|
||||
# @show refdir fn G
|
||||
versions = map(fn -> VersionNumber(split(fn,"/")[end]), G)
|
||||
versions = reverse(sort(versions))
|
||||
versions = filter(v -> v <= _current_plots_version, versions)
|
||||
# @show refdir fn versions
|
||||
|
||||
reffn = nothing
|
||||
newdir = joinpath(refdir, string(_current_plots_version))
|
||||
newfn = joinpath(newdir, fn)
|
||||
|
||||
# figure out which reference file we should compare to, by finding the highest versioned file
|
||||
reffn = nothing
|
||||
for v in versions
|
||||
try
|
||||
tmpfn = joinpath(refdir, string(v), fn)
|
||||
# @show "trying", tmpfn
|
||||
f = open(tmpfn)
|
||||
tmpfn = joinpath(refdir, string(v), fn)
|
||||
if isfile(tmpfn)
|
||||
reffn = tmpfn
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user