Compare commits

..

52 Commits

Author SHA1 Message Date
Thomas Breloff f3544dc826 plotlyjs png fix; NEWS update for 0.7.2 2016-06-16 20:58:44 -04:00
Thomas Breloff b0bc68ae8a orientation aliases dir/direction; removed native support for sticks/hline/vline in pyplot; commented out arcdiagram 2016-06-16 17:31:10 -04:00
Thomas Breloff c38e947dc6 animation default file tempname; raised group warning to 100; check for empty vec in axis; use command_idx for slicing; move deletion of smooth outside loop 2016-06-16 10:03:01 -04:00
Thomas Breloff ec826fc8ce moved series_annotations into series recipe processing; change pyplot clf to fig clear 2016-06-16 00:48:35 -04:00
Thomas Breloff e5c4f782a5 anynan isfinite; error on reusing layout 2016-06-15 15:36:36 -04:00
Thomas Breloff a5ddebf44d curves fix 2016-06-15 13:02:31 -04:00
Thomas Breloff 38804898c5 iter_segments and curve series type 2016-06-15 12:52:36 -04:00
Thomas Breloff 2bd67f3519 pyplot 3d line segments 2016-06-15 02:15:51 -04:00
Thomas Breloff c8ed611c9c unicodeplots cleanup: ijulia output fixes, ascii canvas 2016-06-15 01:45:13 -04:00
Thomas Breloff 3d7d8caa82 moved pyplot methods _series_added and _initialize_subplot into the display pipeline 2016-06-14 18:02:44 -04:00
Thomas Breloff f64108523c line_z arg and pyplot implementation 2016-06-14 15:39:21 -04:00
Tom Breloff a7493504ed Merge pull request #334 from jheinen/dev
conserve user defined GR workstation type
2016-06-14 13:31:40 -04:00
Josef Heinen bc5293b5a4 conserve user defined GR workstation type 2016-06-14 18:03:03 +02:00
Thomas Breloff c4bdc5b856 NEWS.md 2016-06-14 00:27:22 -04:00
Thomas Breloff b5b4023056 axis link arg; change those subplot/axis args set in kwlist to apply just to its own subplot; markerstrokealpha matches markeralpha 2016-06-14 00:10:26 -04:00
Thomas Breloff 0e598cc51d resolve relative coords for inset subplots 2016-06-13 17:46:19 -04:00
Thomas Breloff 9fd09924eb _shape_keys for consistent shape ordering 2016-06-13 16:57:26 -04:00
Thomas Breloff 10d218089f working on glvisualize 2016-06-13 16:15:45 -04:00
Thomas Breloff 1ba0d198a7 rename ellipse to circle; cleanup glvisualize 2016-06-13 15:59:51 -04:00
Thomas Breloff c44132d29d merge_with_base_supported updates 2016-06-13 15:45:35 -04:00
Thomas Breloff a018a2c07a series type dependencies and cleanup; bbox anchors in construction; fix for insets 2016-06-13 14:53:28 -04:00
Thomas Breloff 266d2efde5 inset_subplots; GR log axes fix 2016-06-13 12:27:48 -04:00
Thomas Breloff 3b33b054d3 plotly hover and scattergl 2016-06-13 11:04:56 -04:00
Thomas Breloff 1140b51e91 PLOTS_DEFAULTS and removed pyplot finalizer 2016-06-13 09:42:50 -04:00
Thomas Breloff 9d25c8fcd4 added PLOTS_DEFAULTS env var; check isfinite in axis_limits 2016-06-13 09:27:49 -04:00
Thomas Breloff e8ade18d47 code and utils for plotly shapes 2016-06-13 01:45:53 -04:00
Thomas Breloff ed243f4e3e added hover attribute and desc; fixed plotly title location; already_warned check 2016-06-13 00:15:28 -04:00
Thomas Breloff e0af4b7925 pyplot log scale fix; plotly title as annotation, title_location, hover placeholder 2016-06-12 23:48:18 -04:00
Thomas Breloff 80e53adbd8 getting plotly/plotlyjs up to speed 2016-06-12 21:03:11 -04:00
Thomas Breloff 36a29357a3 only widen axis limits for identity scale; closes #326 2016-06-12 20:22:57 -04:00
Thomas Breloff 5bb9aceaac pyplot log scale threshold fix; imgcomp fix to filter out higher versions 2016-06-12 13:06:15 -04:00
Thomas Breloff 02d893b316 big cleanup: changed camelcase to underscores; removed supportedAxes; changed pyplot methods to be py_ which matches gr_/plotly_/etc convention 2016-06-12 12:34:41 -04:00
Thomas Breloff b1850e58f4 gr cleanup commented code; bump version in imgcomp 2016-06-12 11:35:24 -04:00
Thomas Breloff f1e566dddc fix scale aliases 2016-06-12 11:00:42 -04:00
Thomas Breloff 2f60da33b7 changed pyplot log scale to symlog; #326 2016-06-12 10:28:41 -04:00
Thomas Breloff b0456d155a allow nothing for colorbar; gr fixes: marker_z colors, check colorbar arg 2016-06-11 15:55:55 -04:00
Tom Breloff 5f57a48996 Merge pull request #322 from jheinen/dev
Fixed GR output problem
2016-06-11 15:54:00 -04:00
Josef Heinen bc9d137001 Fixed GR output problem 2016-06-11 11:11:57 +02:00
Thomas Breloff 483946787a big GR refactor: axes drawing and cleanup; convert_to_polar and GR polar fill; should_add_to_legend fix; rename get_mod to Base.cycle 2016-06-11 02:03:46 -04:00
Thomas Breloff b165f233a8 animation fix; gr transparency 2016-06-10 16:17:30 -04:00
Thomas Breloff 3b325b2482 pyplot figure finalizer; accept 2-len AVec for limits (#289); sleep/skip/only options in test_examples 2016-06-10 10:04:33 -04:00
Tom Breloff 2dd480a3a6 Merge pull request #313 from jheinen/dev
Improved GR output
2016-06-10 08:56:53 -04:00
Josef Heinen df33ed40d6 Improved GR output
- slightly reduced the nominal marker size
- use character height as line spacing criterion when plotting legends
- use GR surface function for filled contours
- avoid calling GR setwindow/adjust* functions with Inf arguments
- corrected bounding box for legend
2016-06-10 13:39:57 +02:00
Thomas Breloff cf4d78c87c added clims attribute and support it in pyplot 2016-06-10 01:25:34 -04:00
Thomas Breloff 8007d0dd6a smarter cleanup of dicts; layout fixes: split out update_min_padding and added minimum_perimeter logic; check for nonempty axes when linking; add subplot processing and linking when combining plots 2016-06-10 00:16:13 -04:00
Thomas Breloff d7098f77c2 pgfplots display popup 2016-06-09 17:31:06 -04:00
Thomas Breloff 514284e784 pyplot display fixes for #308; setxyz fix; generic png conversion from pdf; pgfplots pdf output 2016-06-09 17:13:16 -04:00
Thomas Breloff 2a3029edb4 add build.jl 2016-06-09 12:08:36 -04:00
Thomas Breloff 45a1ed69d4 removed plotly-latest.min.js and added build.jl which downloads it; fix for quiver_using_hack; working on pyplot display behavior 2016-06-09 11:44:05 -04:00
Thomas Breloff 7248d8d7ce several fixes for type recipes; collect/zmin fixes in pgfplots; scatter3d recipe 2016-06-09 01:48:43 -04:00
Tom Breloff fa84401866 Merge pull request #310 from diegozea/dev
Add trim kw arg to violin and density
2016-06-09 01:45:43 -04:00
Diego Javier Zea 910b94c5fd Add trim kw arg to violin and density 2016-06-09 02:38:19 -03:00
36 changed files with 2009 additions and 2302 deletions
+1
View File
@@ -4,3 +4,4 @@
.DS_Store
examples/.ipynb_checkpoints/*
examples/meetup/.ipynb_checkpoints/*
deps/plotly-latest.min.js
+44
View File
@@ -9,6 +9,50 @@
## 0.7 (current master/dev)
#### 0.7.2
- line_z arg for multicolored line segments
- pyplot
- line_z (2d and 3d)
- pushed all fig updates into display pipeline
- remove native sticks/hline/vline in favor of recipes
- unicodeplots cleanup, ijulia fixes, ascii canvas
- `curves` series type
- `iter_segments` iterator
- moved arcdiagram out and into PlotRecipes (thanks @diegozea)
- several other fixes/checks
#### 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/)
+8
View File
@@ -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
-41
View File
File diff suppressed because one or more lines are too long
+19 -115
View File
@@ -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,11 +108,8 @@ export
arcdiagram,
chorddiagram,
# @kw,
# @recipe,
# @plotrecipe,
test_examples,
iter_segments,
translate,
translate!,
@@ -178,9 +125,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 +156,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 +175,6 @@ end
@shorthands hline
@shorthands vline
@shorthands ohlc
# @shorthands pie
@shorthands contour
@shorthands contour3d
@shorthands surface
@@ -241,53 +184,12 @@ end
@shorthands boxplot
@shorthands violin
@shorthands quiver
@shorthands curves
# 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 +242,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
View File
@@ -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 = tempname()*".gif"; fps::Integer = 20)
fn = abspath(fn)
try
+5 -1
View File
@@ -27,7 +27,8 @@ const _arg_desc = KW(
:x => "Various. Input data. First Dimension",
:y => "Various. Input data. Second Dimension",
:z => "Various. Input data. Third Dimension. May be wrapped by a `Surface` for surface and heatmap types.",
:marker_z => "AbstractVector. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.",
:marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or nothing. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.",
:line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).",
:levels => "Integer, NTuple{2,Integer}. Number of levels (or x-levels/y-levels) for a contour type.",
:orientation => "Symbol. Horizontal or vertical orientation for bar types. Values `:h`, `:hor`, `:horizontal` correspond to horizontal (sideways, anchored to y-axis), and `:v`, `:vert`, and `:vertical` correspond to vertical (the default).",
:bar_position => "Symbol. Choose from `:overlay` (default), `:stack`. (warning: May not be implemented fully)",
@@ -45,6 +46,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 +61,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 +77,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.",
+102 -79
View File
@@ -11,6 +11,16 @@ function add_aliases(sym::Symbol, aliases::Symbol...)
end
end
function add_non_underscore_aliases!(aliases::KW)
for (k,v) in aliases
s = string(k)
if '_' in s
aliases[Symbol(replace(s, "_", ""))] = v
end
end
end
# ------------------------------------------------------------
const _allAxes = [:auto, :left, :right]
@@ -61,8 +71,12 @@ const _allTypes = vcat([
:imagesc => :image,
:hist => :histogram,
:hist2d => :histogram2d,
:bezier => :curves,
:bezier_curves => :curves,
)
add_non_underscore_aliases!(_typeAliases)
like_histogram(seriestype::Symbol) = seriestype in (:histogram, :density)
like_line(seriestype::Symbol) = seriestype in (:line, :path, :steppre, :steppost)
like_surface(seriestype::Symbol) = seriestype in (:contour, :contour3d, :heatmap, :surface, :wireframe, :image)
@@ -86,13 +100,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,
@@ -162,6 +177,7 @@ const _series_defaults = KW(
:y => nothing,
:z => nothing, # depth for contour, surface, etc
:marker_z => nothing, # value for color scale
:line_z => nothing,
:levels => 15,
:orientation => :vertical,
:bar_position => :overlay, # for bar plots and histograms: could also be stack (stack up) or dodge (side by side)
@@ -181,6 +197,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 +214,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 +233,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 +254,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 +275,7 @@ const _suppress_warnings = Set{Symbol}([
:plot_object,
:primary,
:smooth,
:relative_bbox,
])
# add defaults for the letter versions
@@ -266,6 +288,7 @@ for letter in (:x,:y,:z)
:scale,
:rotation,
:flip,
:link,
:tickfont,
:guidefont,
:foreground_color_axis,
@@ -289,10 +312,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())
# -----------------------------------------------------------------------------
@@ -367,7 +390,8 @@ add_aliases(:linestyle, :style, :s, :ls)
add_aliases(:marker, :m, :mark)
add_aliases(:markershape, :shape)
add_aliases(:markersize, :ms, :msize)
add_aliases(:marker_z, :markerz, :zcolor)
add_aliases(:marker_z, :markerz, :zcolor, :mz)
add_aliases(:line_z, :linez, :zline, :lz)
add_aliases(:fill, :f, :area)
add_aliases(:fillrange, :fillrng, :frange, :fillto, :fill_between)
add_aliases(:group, :g, :grouping)
@@ -388,14 +412,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)
@@ -408,6 +431,7 @@ add_aliases(:projection, :proj)
add_aliases(:title_location, :title_loc, :titleloc, :title_position, :title_pos, :titlepos, :titleposition, :title_align, :title_alignment)
add_aliases(:series_annotations, :series_ann, :seriesann, :series_anns, :seriesanns, :series_annotation)
add_aliases(:html_output_format, :format, :fmt, :html_format)
add_aliases(:orientation, :direction, :dir)
# add all pluralized forms to the _keyAliases dict
@@ -622,7 +646,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
@@ -689,7 +713,7 @@ end
function extractGroupArgs(v::AVec, args...)
groupLabels = sort(collect(unique(v)))
n = length(groupLabels)
if n > 20
if n > 100
warn("You created n=$n groups... Is that intended?")
end
groupIds = Vector{Int}[filter(i -> v[i] == glab, 1:length(v)) for glab in groupLabels]
@@ -723,37 +747,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 +804,7 @@ function convertLegendValue(val::Symbol)
end
end
convertLegendValue(val::Bool) = val ? :best : :none
convertLegendValue(val::Void) = :none
# -----------------------------------------------------------------------------
@@ -896,87 +930,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 +1005,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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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
+276 -747
View File
File diff suppressed because it is too large Load Diff
+6 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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
+14 -126
View File
@@ -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,55 +50,26 @@ 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"
tmpfn = tempname() * ".png"
PlotlyJS.savefig(plt.o, tmpfn)
write(io, read(open(tmpfn)))
end
function _display(plt::Plot{PlotlyJSBackend})
# plotlyjs_finalize(plt)
display(plt.o)
end
+348 -307
View File
File diff suppressed because it is too large Load Diff
+10 -33
View File
@@ -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
+3 -3
View File
@@ -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})
+64 -233
View File
@@ -1,86 +1,46 @@
# 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,
: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
# --------------------------------------------------------------------------------------
function _initialize_backend(::UnicodePlotsBackend; kw...)
@eval begin
import UnicodePlots
export UnicodePlots
end
@eval begin
import UnicodePlots
export UnicodePlots
end
end
# -------------------------------
# convert_size_from_pixels(sz) =
# do all the magic here... build it all at once, since we need to know about all the series at the very beginning
function rebuildUnicodePlot!(plt::Plot)
plt.o = []
for sp in plt.subplots
xaxis = sp[:xaxis]
yaxis = sp[:yaxis]
@@ -98,12 +58,14 @@ function rebuildUnicodePlot!(plt::Plot)
# create a plot window with xlim/ylim set, but the X/Y vectors are outside the bounds
width, height = plt[:size]
o = UnicodePlots.Plot(x, y;
canvas_type = isijulia() ? UnicodePlots.AsciiCanvas : UnicodePlots.BrailleCanvas
o = UnicodePlots.Plot(x, y, canvas_type;
width = width,
height = height,
title = sp[:title],
xlim = xlim,
ylim = ylim
ylim = ylim,
border = isijulia() ? :ascii : :solid
)
# set the axis labels
@@ -120,213 +82,82 @@ function rebuildUnicodePlot!(plt::Plot)
end
end
# # do all the magic here... build it all at once, since we need to know about all the series at the very beginning
# function rebuildUnicodePlot!(plt::Plot)
#
# # figure out the plotting area xlim = [xmin, xmax] and ylim = [ymin, ymax]
# sargs = plt.seriesargs
# iargs = plt.attr
#
# # get the x/y limits
# if get(iargs, :xlims, :auto) == :auto
# xlim = [Inf, -Inf]
# for d in sargs
# _expand_limits(xlim, d[:x])
# end
# else
# xmin, xmax = iargs[:xlims]
# xlim = [xmin, xmax]
# end
#
# if get(iargs, :ylims, :auto) == :auto
# ylim = [Inf, -Inf]
# for d in sargs
# _expand_limits(ylim, d[:y])
# end
# else
# ymin, ymax = iargs[:ylims]
# ylim = [ymin, ymax]
# end
#
# # we set x/y to have a single point, since we need to create the plot with some data.
# # since this point is at the bottom left corner of the plot, it shouldn't actually be shown
# x = Float64[xlim[1]]
# y = Float64[ylim[1]]
#
# # create a plot window with xlim/ylim set, but the X/Y vectors are outside the bounds
# width, height = iargs[:size]
# o = UnicodePlots.Plot(x, y; width = width,
# height = height,
# title = iargs[:title],
# # labels = iargs[:legend],
# xlim = xlim,
# ylim = ylim)
#
# # set the axis labels
# UnicodePlots.xlabel!(o, iargs[:xguide])
# UnicodePlots.ylabel!(o, iargs[:yguide])
#
# # now use the ! functions to add to the plot
# for d in sargs
# addUnicodeSeries!(o, d, iargs[:legend] != :none, xlim, ylim)
# end
#
# # save the object
# plt.o = o
# end
# add a single series
function addUnicodeSeries!(o, d::KW, addlegend::Bool, xlim, ylim)
# get the function, or special handling for step/bar/hist
st = d[:seriestype]
# handle hline/vline separately
if st in (:hline,:vline)
for yi in d[:y]
if st == :hline
UnicodePlots.lineplot!(o, xlim, [yi,yi])
else
UnicodePlots.lineplot!(o, [yi,yi], ylim)
end
end
return
# elseif st == :bar
# UnicodePlots.barplot!(o, d[:x], d[:y])
# return
# elseif st == :histogram
# UnicodePlots.histogram!(o, d[:y], bins = d[:bins])
# return
elseif st == :histogram2d
if st == :histogram2d
UnicodePlots.densityplot!(o, d[:x], d[:y])
return
end
stepstyle = :post
if st == :path
func = UnicodePlots.lineplot!
elseif st == :scatter || d[:markershape] != :none
func = UnicodePlots.scatterplot!
elseif st == :steppost
func = UnicodePlots.stairs!
elseif st == :steppre
func = UnicodePlots.stairs!
stepstyle = :pre
else
error("Linestyle $st not supported by UnicodePlots")
end
if st == :path
func = UnicodePlots.lineplot!
elseif st == :scatter || d[:markershape] != :none
func = UnicodePlots.scatterplot!
else
error("Linestyle $st not supported by UnicodePlots")
end
# get the series data and label
x, y = [collect(float(d[s])) for s in (:x, :y)]
label = addlegend ? d[:label] : ""
# get the series data and label
x, y = [collect(float(d[s])) for s in (:x, :y)]
label = addlegend ? d[:label] : ""
# if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide
color = d[:linecolor] in UnicodePlots.color_cycle ? d[:linecolor] : :auto
# if we happen to pass in allowed color symbols, great... otherwise let UnicodePlots decide
color = d[:linecolor] in UnicodePlots.color_cycle ? d[:linecolor] : :auto
# add the series
func(o, x, y; color = color, name = label, style = stepstyle)
# add the series
func(o, x, y; color = color, name = label)
end
# function handlePlotColors(::UnicodePlotsBackend, d::KW)
# # TODO: something special for unicodeplots, since it doesn't take kindly to people messing with its color palette
# d[:color_palette] = [RGB(0,0,0)]
# end
# -------------------------------
# function _create_plot(pkg::UnicodePlotsBackend, d::KW)
# plt = Plot(nothing, pkg, 0, d, KW[])
function _create_backend_figure(plt::Plot{UnicodePlotsBackend})
# do we want to give a new default size?
# if !haskey(plt.attr, :size) || plt.attr[:size] == default(:size)
# plt.attr[:size] = (60,20)
# end
w, h = plt[:size]
plt.attr[:size] = div(w, 10), div(h, 20)
plt.attr[:color_palette] = [RGB(0,0,0)]
nothing
# plt
end
# function _series_added(plt::Plot{UnicodePlotsBackend}, series::Series)
# d = series.d
# # TODO don't need these once the "bar" series recipe is done
# if d[:seriestype] in (:sticks, :bar)
# d = barHack(; d...)
# elseif d[:seriestype] == :histogram
# d = barHack(; histogramHack(; d...)...)
# end
# # push!(plt.seriesargs, d)
# # plt
# end
#
#
# function _update_plot_object(plt::Plot{UnicodePlotsBackend}, d::KW)
# for k in (:title, :xguide, :yguide, :xlims, :ylims)
# if haskey(d, k)
# plt.attr[k] = d[k]
# end
# end
# end
# -------------------------------
# since this is such a hack, it's only callable using `png`... should error during normal `writemime`
function png(plt::AbstractPlot{UnicodePlotsBackend}, fn::AbstractString)
fn = addExtension(fn, "png")
fn = addExtension(fn, "png")
# make some whitespace and show the plot
println("\n\n\n\n\n\n")
gui(plt)
# make some whitespace and show the plot
println("\n\n\n\n\n\n")
gui(plt)
# @osx_only begin
@compat @static if is_apple()
# BEGIN HACK
# @osx_only begin
@compat @static if is_apple()
# BEGIN HACK
# wait while the plot gets drawn
sleep(0.5)
# wait while the plot gets drawn
sleep(0.5)
# use osx screen capture when my terminal is maximized and cursor starts at the bottom (I know, right?)
# TODO: compute size of plot to adjust these numbers (or maybe implement something good??)
run(`screencapture -R50,600,700,420 $fn`)
# use osx screen capture when my terminal is maximized and cursor starts at the bottom (I know, right?)
# TODO: compute size of plot to adjust these numbers (or maybe implement something good??)
run(`screencapture -R50,600,700,420 $fn`)
# END HACK (phew)
return
end
# END HACK (phew)
return
end
error("Can only savepng on osx with UnicodePlots (though even then I wouldn't do it)")
error("Can only savepng on osx with UnicodePlots (though even then I wouldn't do it)")
end
# -------------------------------
# we don't do very much for subplots... just stack them vertically
# function _create_subplot(subplt::Subplot{UnicodePlotsBackend}, isbefore::Bool)
# isbefore && return false
# true
# end
function _display(plt::Plot{UnicodePlotsBackend})
function _update_plot_object(plt::Plot{UnicodePlotsBackend})
w, h = plt[:size]
plt.attr[:size] = div(w, 10), div(h, 20)
plt.attr[:color_palette] = [RGB(0,0,0)]
rebuildUnicodePlot!(plt)
end
function _writemime(io::IO, ::MIME"text/plain", plt::Plot{UnicodePlotsBackend})
map(show, plt.o)
nothing
end
function _display(plt::Plot{UnicodePlotsBackend})
map(show, plt.o)
nothing
end
# function Base.display(::PlotsDisplay, subplt::Subplot{UnicodePlotsBackend})
# for plt in subplt.plts
# gui(plt)
# end
# end
+10 -45
View File
@@ -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
+7
View File
@@ -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
View File
@@ -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
View File
@@ -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
+99 -99
View File
@@ -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[]
@@ -435,6 +479,8 @@ function build_layout(layout::GridLayout, n::Integer)
append!(subplots, sps)
merge!(spmap, m)
i += length(sps)
elseif isa(l, Subplot)
error("Subplot exists. Cannot re-use existing layout. Please make a new one.")
end
i >= n && break # only add n subplots
end
@@ -512,44 +558,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 +577,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 +593,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 +642,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
+35 -1
View File
@@ -119,11 +119,13 @@ const _mimeformats = Dict(
"application/pdf" => "pdf",
"image/png" => "png",
"application/postscript" => "ps",
"image/svg+xml" => "svg"
"image/svg+xml" => "svg",
"text/plain" => "txt",
)
const _best_html_output_type = KW(
:pyplot => :png,
:unicodeplots => :txt,
)
# a backup for html... passes to svg or png depending on the html_output_format arg
@@ -138,6 +140,8 @@ function Base.writemime(io::IO, ::MIME"text/html", plt::Plot)
elseif output_type == :svg
# info("writing svg to html output")
writemime(io, MIME("image/svg+xml"), plt)
elseif output_type == :txt
writemime(io, MIME("text/plain"), plt)
else
error("only png or svg allowed. got: $output_type")
end
@@ -151,6 +155,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)
+153 -47
View File
@@ -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
@@ -150,6 +172,11 @@ function _apply_series_recipe(plt::Plot, d::KW)
sp_idx = get_subplot_index(plt, sp)
_update_subplot_args(plt, sp, d, sp_idx)
# do we want to override the series type?
if !is3d(st) && d[:z] != nothing && (size(d[:x]) == size(d[:y]) == size(d[:z]))
st = d[:seriestype] = (st == :scatter ? :scatter3d : :path3d)
end
# change to a 3d projection for this subplot?
if is3d(st)
sp.attr[:projection] = "3d"
@@ -161,6 +188,18 @@ function _apply_series_recipe(plt::Plot, d::KW)
sp.attr[:init] = true
end
# strip out series annotations (those which are based on series x/y coords)
# and add them to the subplot attr
sp_anns = annotations(sp[:annotations])
anns = annotations(pop!(d, :series_annotations, []))
if length(anns) > 0
x, y = d[:x], d[:y]
nx, ny, na = map(length, (x,y,anns))
n = max(nx, ny, na)
anns = [(x[mod1(i,nx)], y[mod1(i,ny)], text(anns[mod1(i,na)])) for i=1:n]
end
sp.attr[:annotations] = vcat(sp_anns, anns)
# adjust extrema and discrete info
if st == :image
w, h = size(d[:z])
@@ -173,7 +212,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)
@@ -250,7 +289,12 @@ function _plot!(plt::Plot, d::KW, args...)
# map marker_z if it's a Function
if isa(get(kw, :marker_z, nothing), Function)
# TODO: should this take y and/or z as arguments?
kw[:marker_z] = map(kw[:marker_z], kw[:x])
kw[:marker_z] = map(kw[:marker_z], kw[:x], kw[:y], kw[:z])
end
# map line_z if it's a Function
if isa(get(kw, :line_z, nothing), Function)
kw[:line_z] = map(kw[:line_z], kw[:x], kw[:y], kw[:z])
end
# convert a ribbon into a fillrange
@@ -263,7 +307,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
@@ -293,9 +337,6 @@ function _plot!(plt::Plot, d::KW, args...)
:label => "",
:primary => false,
)))
# don't allow something else to handle it
d[:smooth] = false
end
else
@@ -305,17 +346,20 @@ function _plot!(plt::Plot, d::KW, args...)
end
end
# merge in anything meant for plot/subplot
# don't allow something else to handle it
d[:smooth] = false
# 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 +367,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 +379,73 @@ 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 kw in kw_list
# get the Subplot object to which the series belongs
sp = get(kw, :subplot, :auto)
command_idx = kw[:series_plotindex] - kw_list[1][:series_plotindex] + 1
sp = if sp == :auto
cycle(plt.subplots, command_idx)
# mod1(command_idx, length(plt.subplots))
else
slice_arg(sp, command_idx)
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])
@@ -350,33 +454,31 @@ 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
for kw in kw_list
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)
# and add them to the subplot attr
sp_anns = annotations(sp[:annotations])
anns = annotations(pop!(kw, :series_annotations, []))
if length(anns) > 0
x, y = kw[:x], kw[:y]
nx, ny, na = map(length, (x,y,anns))
n = max(nx, ny, na)
anns = [(x[mod1(i,nx)], y[mod1(i,ny)], text(anns[mod1(i,na)])) for i=1:n]
end
sp.attr[:annotations] = vcat(sp_anns, anns)
# # strip out series annotations (those which are based on series x/y coords)
# # and add them to the subplot attr
# sp_anns = annotations(sp[:annotations])
# anns = annotations(pop!(kw, :series_annotations, []))
# if length(anns) > 0
# x, y = kw[:x], kw[:y]
# nx, ny, na = map(length, (x,y,anns))
# n = max(nx, ny, na)
# anns = [(x[mod1(i,nx)], y[mod1(i,ny)], text(anns[mod1(i,na)])) for i=1:n]
# end
# sp.attr[:annotations] = vcat(sp_anns, anns)
# we update subplot args in case something like the color palatte is part of the recipe
_update_subplot_args(plt, sp, kw, idx)
@@ -393,15 +495,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 +522,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
+226 -75
View File
@@ -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,8 +335,77 @@ sticks_fillfrom(fr::AVec, i::Integer) = fr[mod1(i, length(fr))]
end
()
end
@deps sticks path scatter
# ---------------------------------------------------------------------------
# bezier curves
# get the value of the curve point at position t
function bezier_value(pts::AVec, t::Real)
val = 0.0
n = length(pts)-1
for (i,p) in enumerate(pts)
val += p * binomial(n, i-1) * (1-t)^(n-i+1) * t^(i-1)
end
val
end
# create segmented bezier curves in place of line segments
@recipe function f(::Type{Val{:curves}}, x, y, z)
args = z != nothing ? (x,y,z) : (x,y)
newx, newy = zeros(0), zeros(0)
fr = d[:fillrange]
newfr = fr != nothing ? zeros(0) : nothing
newz = z != nothing ? zeros(0) : nothing
lz = d[:line_z]
newlz = lz != nothing ? zeros(0) : nothing
npoints = pop!(d, :npoints, 30)
# for each line segment (point series with no NaNs), convert it into a bezier curve
# where the points are the control points of the curve
for rng in iter_segments(args...)
length(rng) < 2 && continue
ts = linspace(0, 1, npoints)
nanappend!(newx, map(t -> bezier_value(cycle(x,rng), t), ts))
nanappend!(newy, map(t -> bezier_value(cycle(y,rng), t), ts))
if z != nothing
nanappend!(newz, map(t -> bezier_value(cycle(z,rng), t), ts))
end
if fr != nothing
nanappend!(newfr, map(t -> bezier_value(cycle(fr,rng), t), ts))
end
if lz != nothing
lzrng = cycle(lz, rng) # the line_z's for this segment
# @show lzrng, sizeof(lzrng) map(t -> 1+floor(Int, t * (length(rng)-1)), ts)
# choose the line_z value of the control point just before this t
push!(newlz, 0.0)
append!(newlz, map(t -> lzrng[1+floor(Int, t * (length(rng)-1))], ts))
# lzrng = vcat()
# nanappend!(newlz, #map(t -> bezier_value(cycle(lz,rng), t), ts))
end
end
x := newx
y := newy
if z == nothing
seriestype := :path
else
seriestype := :path3d
z := newz
end
if fr != nothing
fillrange := newfr
end
if lz != nothing
line_z := newlz
linecolor := (isa(d[:linecolor], ColorGradient) ? d[:linecolor] : default_gradient())
end
# Plots.DD(d)
()
end
@deps curves path
# ---------------------------------------------------------------------------
# create a bar plot as a filled step function
@@ -350,6 +465,7 @@ end
seriestype := :path
()
end
@deps bar path
# ---------------------------------------------------------------------------
# Histograms
@@ -402,6 +518,7 @@ end
seriestype := :bar
()
end
@deps histogram bar
# ---------------------------------------------------------------------------
# Histogram 2D
@@ -443,6 +560,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 +674,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 +683,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 +693,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 +713,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 +725,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 +742,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 +796,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 +820,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 +828,7 @@ end
d[:y], d[:x] = error_coords(d[:y], d[:x], error_zipit(d[:xerror]))
()
end
@deps xerror path
# ---------------------------------------------------------------------------
@@ -702,11 +849,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 +875,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 +886,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 +921,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
# ---------------------------------------------------------------------------
@@ -891,6 +1039,9 @@ end
# -------------------------------------------------
# TODO: everything below here should be either changed to a
# series recipe or moved to PlotRecipes
"Sparsity plot... heatmap of non-zero values of a matrix"
function spy{T<:Real}(z::AMat{T}; kw...)
@@ -952,56 +1103,56 @@ end
curvecolor(value, min, max, grad) = getColorZ(grad, (value-min)/(max-min))
"Plots a clockwise arc, from source to destiny, colored by weight"
function arc!(source, destiny, weight, min, max, grad)
radius = (destiny - source) / 2
arc = Plots.partialcircle(0, π, 30, radius)
x, y = Plots.unzip(arc)
plot!(x .+ radius .+ source, y, line = (curvecolor(weight, min, max, grad), 0.5, 2), legend=false)
end
# "Plots a clockwise arc, from source to destiny, colored by weight"
# function arc!(source, destiny, weight, min, max, grad)
# radius = (destiny - source) / 2
# arc = Plots.partialcircle(0, π, 30, radius)
# x, y = Plots.unzip(arc)
# plot!(x .+ radius .+ source, y, line = (curvecolor(weight, min, max, grad), 0.5, 2), legend=false)
# end
"""
`arcdiagram(source, destiny, weight[, grad])`
# """
# `arcdiagram(source, destiny, weight[, grad])`
Plots an arc diagram, form `source` to `destiny` (clockwise), using `weight` to determine the colors.
"""
function arcdiagram(source, destiny, weight; kargs...)
# Plots an arc diagram, form `source` to `destiny` (clockwise), using `weight` to determine the colors.
# """
# function arcdiagram(source, destiny, weight; kargs...)
args = KW(kargs)
grad = pop!(args, :grad, ColorGradient([colorant"darkred", colorant"darkblue"]))
# args = KW(kargs)
# grad = pop!(args, :grad, ColorGradient([colorant"darkred", colorant"darkblue"]))
if length(source) == length(destiny) == length(weight)
# if length(source) == length(destiny) == length(weight)
vertices = unique(vcat(source, destiny))
sort!(vertices)
# vertices = unique(vcat(source, destiny))
# sort!(vertices)
xmin, xmax = extrema(vertices)
plot(xlim=(xmin - 0.5, xmax + 0.5), legend=false)
# xmin, xmax = extrema(vertices)
# plot(xlim=(xmin - 0.5, xmax + 0.5), legend=false)
wmin,wmax = extrema(weight)
# wmin,wmax = extrema(weight)
for (i, j, value) in zip(source,destiny,weight)
arc!(i, j, value, wmin, wmax, grad)
end
# for (i, j, value) in zip(source,destiny,weight)
# arc!(i, j, value, wmin, wmax, grad)
# end
scatter!(vertices, zeros(length(vertices)); legend=false, args...)
# scatter!(vertices, zeros(length(vertices)); legend=false, args...)
else
# else
throw(ArgumentError("source, destiny and weight should have the same length"))
# throw(ArgumentError("source, destiny and weight should have the same length"))
end
end
# end
# end
"""
`arcdiagram(mat[, grad])`
# """
# `arcdiagram(mat[, grad])`
Plots an arc diagram from an adjacency matrix, form rows to columns (clockwise),
using the values on the matrix as weights to determine the colors.
Doesn't show edges with value zero if the input is sparse.
For simmetric matrices, only the upper triangular values are used.
"""
arcdiagram{T}(mat::AbstractArray{T,2}; kargs...) = arcdiagram(mat2list(mat)...; kargs...)
# Plots an arc diagram from an adjacency matrix, form rows to columns (clockwise),
# using the values on the matrix as weights to determine the colors.
# Doesn't show edges with value zero if the input is sparse.
# For simmetric matrices, only the upper triangular values are used.
# """
# arcdiagram{T}(mat::AbstractArray{T,2}; kargs...) = arcdiagram(mat2list(mat)...; kargs...)
# ---------------------------------------------------------------------------
# Chord diagram
+42 -18
View File
@@ -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
@@ -268,22 +292,22 @@ end
# # 3d line or scatter
@recipe function f(x::AVec, y::AVec, z::AVec)
st = get(d, :seriestype, :none)
if st == :scatter
d[:seriestype] = :scatter3d
elseif !is3d(st)
d[:seriestype] = :path3d
end
# st = get(d, :seriestype, :none)
# if st == :scatter
# d[:seriestype] = :scatter3d
# elseif !is3d(st)
# d[:seriestype] = :path3d
# end
SliceIt, x, y, z
end
@recipe function f(x::AMat, y::AMat, z::AMat)
st = get(d, :seriestype, :none)
if size(x) == size(y) == size(z)
if !is3d(st)
seriestype := :path3d
end
end
# st = get(d, :seriestype, :none)
# if size(x) == size(y) == size(z)
# if !is3d(st)
# seriestype := :path3d
# end
# end
SliceIt, x, y, z
end
@@ -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
View File
@@ -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
View File
@@ -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??
+105 -7
View File
@@ -131,20 +131,71 @@ 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
# ---------------------------------------------------------------
# -----------------------------------------------------
# helper to manage NaN-separated segments
type SegmentsIterator
args::Tuple
nextidx::Int
n::Int
end
function iter_segments(args...)
tup = Plots.wraptuple(args)
n = maximum(map(length, tup))
SegmentsIterator(tup, 0, n)
end
# helpers to figure out if there are NaN values in a list of array types
anynan(i::Int, args...) = any(a -> !isfinite(cycle(a,i)), args)
anynan(istart::Int, iend::Int, args...) = any(i -> anynan(i, args...), istart:iend)
allnan(istart::Int, iend::Int, args...) = all(i -> anynan(i, args...), istart:iend)
Base.start(itr::SegmentsIterator) = (itr.nextidx = 1) #resets
Base.done(itr::SegmentsIterator, unused::Int) = itr.nextidx > itr.n
function Base.next(itr::SegmentsIterator, unused::Int)
i = istart = iend = itr.nextidx
# find the next NaN, and iend is the one before
while i <= itr.n + 1
if i > itr.n || anynan(i, itr.args...)
# done... array end or found NaN
iend = i-1
break
end
i += 1
end
# find the next non-NaN, and set itr.nextidx
while i <= itr.n
if !anynan(i, itr.args...)
break
end
i += 1
end
itr.nextidx = i
istart:iend, 0
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
Base.cycle(v::AVec, indices::AVec{Int}) = map(i -> cycle(v,i), indices)
Base.cycle(v::AMat, indices::AVec{Int}) = map(i -> cycle(v,i), indices)
Base.cycle(v, idx::AVec{Int}) = v
makevec(v::AVec) = v
makevec{T}(v::T) = T[v]
@@ -232,6 +283,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 +332,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 +359,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 +606,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
View File
@@ -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.2"
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