Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f3544dc826 | |||
| b0bc68ae8a | |||
| c38e947dc6 | |||
| ec826fc8ce | |||
| e5c4f782a5 | |||
| a5ddebf44d | |||
| 38804898c5 | |||
| 2bd67f3519 | |||
| c8ed611c9c | |||
| 3d7d8caa82 | |||
| f64108523c | |||
| a7493504ed | |||
| bc5293b5a4 | |||
| c4bdc5b856 | |||
| b5b4023056 | |||
| 0e598cc51d | |||
| 9fd09924eb | |||
| 10d218089f | |||
| 1ba0d198a7 | |||
| c44132d29d | |||
| a018a2c07a | |||
| 266d2efde5 | |||
| 3b33b054d3 | |||
| 1140b51e91 | |||
| 9d25c8fcd4 | |||
| e8ade18d47 | |||
| ed243f4e3e | |||
| e0af4b7925 | |||
| 80e53adbd8 | |||
| 36a29357a3 | |||
| 5bb9aceaac | |||
| 02d893b316 | |||
| b1850e58f4 | |||
| f1e566dddc | |||
| 2f60da33b7 | |||
| b0456d155a | |||
| 5f57a48996 | |||
| bc9d137001 | |||
| 483946787a | |||
| b165f233a8 | |||
| 3b325b2482 | |||
| 2dd480a3a6 | |||
| df33ed40d6 | |||
| cf4d78c87c | |||
| 8007d0dd6a | |||
| d7098f77c2 | |||
| 514284e784 | |||
| 2a3029edb4 | |||
| 45a1ed69d4 | |||
| 7248d8d7ce | |||
| fa84401866 | |||
| 910b94c5fd |
@@ -4,3 +4,4 @@
|
||||
.DS_Store
|
||||
examples/.ipynb_checkpoints/*
|
||||
examples/meetup/.ipynb_checkpoints/*
|
||||
deps/plotly-latest.min.js
|
||||
|
||||
@@ -9,6 +9,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/)
|
||||
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
|
||||
#TODO: download https://cdn.plot.ly/plotly-latest.min.js to deps/ if it doesn't exist
|
||||
|
||||
local_fn = joinpath(dirname(@__FILE__), "plotly-latest.min.js")
|
||||
if !isfile(local_fn)
|
||||
info("Cannot find deps/plotly-latest.min.js... downloading latest version.")
|
||||
download("https://cdn.plot.ly/plotly-latest.min.js", local_fn)
|
||||
end
|
||||
Vendored
-41
File diff suppressed because one or more lines are too long
+19
-115
@@ -19,14 +19,12 @@ export
|
||||
GridLayout,
|
||||
grid,
|
||||
EmptyLayout,
|
||||
bbox,
|
||||
plotarea,
|
||||
@layout,
|
||||
# RowsLayout,
|
||||
# FlexLayout,
|
||||
AVec,
|
||||
AMat,
|
||||
KW,
|
||||
# attr,
|
||||
# attr!,
|
||||
|
||||
wrap,
|
||||
set_theme,
|
||||
@@ -34,8 +32,6 @@ export
|
||||
|
||||
plot,
|
||||
plot!,
|
||||
# subplot,
|
||||
# subplot!,
|
||||
|
||||
current,
|
||||
default,
|
||||
@@ -43,53 +39,11 @@ export
|
||||
|
||||
@userplot,
|
||||
@shorthands,
|
||||
# scatter,
|
||||
# scatter!,
|
||||
# bar,
|
||||
# bar!,
|
||||
# barh,
|
||||
# barh!,
|
||||
# histogram,
|
||||
# histogram!,
|
||||
# histogram2d,
|
||||
# histogram2d!,
|
||||
# density,
|
||||
# density!,
|
||||
# heatmap,
|
||||
# heatmap!,
|
||||
# hexbin,
|
||||
# hexbin!,
|
||||
# sticks,
|
||||
# sticks!,
|
||||
# hline,
|
||||
# hline!,
|
||||
# vline,
|
||||
# vline!,
|
||||
# ohlc,
|
||||
# ohlc!,
|
||||
|
||||
pie,
|
||||
pie!,
|
||||
# contour,
|
||||
# contour!,
|
||||
# contour3d,
|
||||
# contour3d!,
|
||||
# surface,
|
||||
# surface!,
|
||||
# wireframe,
|
||||
# wireframe!,
|
||||
# path3d,
|
||||
# path3d!,
|
||||
plot3d,
|
||||
plot3d!,
|
||||
# scatter3d,
|
||||
# scatter3d!,
|
||||
# abline!,
|
||||
# boxplot,
|
||||
# boxplot!,
|
||||
# violin,
|
||||
# violin!,
|
||||
# quiver,
|
||||
# quiver!,
|
||||
|
||||
title!,
|
||||
xlabel!,
|
||||
@@ -119,9 +73,6 @@ export
|
||||
text,
|
||||
font,
|
||||
Axis,
|
||||
# xaxis,
|
||||
# yaxis,
|
||||
# zaxis,
|
||||
stroke,
|
||||
brush,
|
||||
Surface,
|
||||
@@ -140,12 +91,11 @@ export
|
||||
|
||||
debugplots,
|
||||
|
||||
supportedArgs,
|
||||
supportedAxes,
|
||||
supportedTypes,
|
||||
supportedStyles,
|
||||
supportedMarkers,
|
||||
subplotSupported,
|
||||
supported_args,
|
||||
supported_types,
|
||||
supported_styles,
|
||||
supported_markers,
|
||||
is_subplot_supported,
|
||||
|
||||
Animation,
|
||||
frame,
|
||||
@@ -158,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
@@ -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
@@ -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
@@ -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
@@ -32,6 +32,15 @@ function Axis(sp::Subplot, letter::Symbol, args...; kw...)
|
||||
update!(Axis(sp, d), args...; kw...)
|
||||
end
|
||||
|
||||
function get_axis(sp::Subplot, letter::Symbol)
|
||||
axissym = Symbol(letter, :axis)
|
||||
if haskey(sp.attr, axissym)
|
||||
sp.attr[axissym]
|
||||
else
|
||||
sp.attr[axissym] = Axis(sp, letter)
|
||||
end
|
||||
end
|
||||
|
||||
function process_axis_arg!(d::KW, arg, letter = "")
|
||||
T = typeof(arg)
|
||||
arg = get(_scaleAliases, arg, arg)
|
||||
@@ -91,6 +100,12 @@ function update!(axis::Axis, args...; kw...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# replace scale aliases
|
||||
if haskey(_scaleAliases, d[:scale])
|
||||
d[:scale] = _scaleAliases[d[:scale]]
|
||||
end
|
||||
|
||||
axis
|
||||
end
|
||||
|
||||
@@ -213,12 +228,15 @@ function widen(lmin, lmax)
|
||||
lmin-eps, lmax+eps
|
||||
end
|
||||
|
||||
# figure out if widening is a good idea
|
||||
# figure out if widening is a good idea. if there's a scale set it's too tricky,
|
||||
# so lazy out and don't widen
|
||||
function default_should_widen(axis::Axis)
|
||||
should_widen = false
|
||||
for series in series_list(axis.sp)
|
||||
if series.d[:seriestype] in (:scatter,) || series.d[:markershape] != :none
|
||||
should_widen = true
|
||||
if axis[:scale] == :identity
|
||||
for series in series_list(axis.sp)
|
||||
if series.d[:seriestype] in (:scatter,) || series.d[:markershape] != :none
|
||||
should_widen = true
|
||||
end
|
||||
end
|
||||
end
|
||||
should_widen
|
||||
@@ -229,7 +247,7 @@ function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis)
|
||||
ex = axis[:extrema]
|
||||
amin, amax = ex.emin, ex.emax
|
||||
lims = axis[:lims]
|
||||
if isa(lims, Tuple) && length(lims) == 2
|
||||
if (isa(lims, Tuple) || isa(lims, AVec)) && length(lims) == 2
|
||||
if isfinite(lims[1])
|
||||
amin = lims[1]
|
||||
end
|
||||
@@ -237,7 +255,7 @@ function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis)
|
||||
amax = lims[2]
|
||||
end
|
||||
end
|
||||
if amax <= amin
|
||||
if amax <= amin && isfinite(amin)
|
||||
amax = amin + 1.0
|
||||
end
|
||||
if should_widen
|
||||
|
||||
+54
-15
@@ -169,22 +169,61 @@ end
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
supportedAxes(::AbstractBackend) = [:left]
|
||||
supportedTypes(::AbstractBackend) = []
|
||||
supportedStyles(::AbstractBackend) = [:solid]
|
||||
supportedMarkers(::AbstractBackend) = [:none]
|
||||
supportedScales(::AbstractBackend) = [:identity]
|
||||
subplotSupported(::AbstractBackend) = false
|
||||
stringsSupported(::AbstractBackend) = false
|
||||
nativeImagesSupported(b::AbstractBackend) = :image in supportedTypes(b)
|
||||
supported_types(::AbstractBackend) = []
|
||||
supported_styles(::AbstractBackend) = [:solid]
|
||||
supported_markers(::AbstractBackend) = [:none]
|
||||
supported_scales(::AbstractBackend) = [:identity]
|
||||
is_subplot_supported(::AbstractBackend) = false
|
||||
is_string_supported(::AbstractBackend) = false
|
||||
nativeImagesSupported(b::AbstractBackend) = :image in supported_types(b)
|
||||
|
||||
supportedAxes() = supportedAxes(backend())
|
||||
supportedTypes() = supportedTypes(backend())
|
||||
supportedStyles() = supportedStyles(backend())
|
||||
supportedMarkers() = supportedMarkers(backend())
|
||||
supportedScales() = supportedScales(backend())
|
||||
subplotSupported() = subplotSupported(backend())
|
||||
stringsSupported() = stringsSupported(backend())
|
||||
supported_types() = supported_types(backend())
|
||||
supported_styles() = supported_styles(backend())
|
||||
supported_markers() = supported_markers(backend())
|
||||
supported_scales() = supported_scales(backend())
|
||||
is_subplot_supported() = is_subplot_supported(backend())
|
||||
is_string_supported() = is_string_supported(backend())
|
||||
nativeImagesSupported() = nativeImagesSupported(backend())
|
||||
|
||||
# ---------------------------------------------------------
|
||||
|
||||
# these are args which every backend supports because they're not used in the backend code
|
||||
const _base_supported_args = [
|
||||
:color_palette,
|
||||
:background_color, :background_color_subplot,
|
||||
:foreground_color, :foreground_color_subplot,
|
||||
:group,
|
||||
:seriestype,
|
||||
:seriescolor, :seriesalpha,
|
||||
:smooth,
|
||||
:xerror, :yerror,
|
||||
:subplot,
|
||||
:x, :y, :z,
|
||||
:show, :size,
|
||||
:margin,
|
||||
:left_margin,
|
||||
:right_margin,
|
||||
:top_margin,
|
||||
:bottom_margin,
|
||||
:html_output_format,
|
||||
:layout,
|
||||
:link,
|
||||
:primary,
|
||||
:series_annotations,
|
||||
:subplot_index,
|
||||
:discrete_values,
|
||||
:projection,
|
||||
|
||||
]
|
||||
|
||||
function merge_with_base_supported(v::AVec)
|
||||
v = vcat(v, _base_supported_args)
|
||||
for vi in v
|
||||
if haskey(_axis_defaults, vi)
|
||||
for letter in (:x,:y,:z)
|
||||
push!(v, Symbol(letter,vi))
|
||||
end
|
||||
end
|
||||
end
|
||||
v
|
||||
end
|
||||
|
||||
+9
-10
@@ -2,7 +2,7 @@
|
||||
# https://github.com/bokeh/Bokeh.jl
|
||||
|
||||
|
||||
supportedArgs(::BokehBackend) = [
|
||||
supported_args(::BokehBackend) = merge_with_base_supported([
|
||||
# :annotations,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
@@ -58,13 +58,12 @@ supportedArgs(::BokehBackend) = [
|
||||
# :grid,
|
||||
# :surface,
|
||||
# :levels,
|
||||
]
|
||||
supportedAxes(::BokehBackend) = [:auto, :left]
|
||||
supportedTypes(::BokehBackend) = [:none, :path, :scatter] #,:steppre, :steppost, :sticks, :histogram2d, :hexbin, :histogram, :bar, :hline, :vline, :contour]
|
||||
supportedStyles(::BokehBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::BokehBackend) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::BokehBackend) = [:identity, :ln] #, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::BokehBackend) = false
|
||||
])
|
||||
supported_types(::BokehBackend) = [:path, :scatter]
|
||||
supported_styles(::BokehBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supported_markers(::BokehBackend) = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
|
||||
supported_scales(::BokehBackend) = [:identity, :ln]
|
||||
is_subplot_supported(::BokehBackend) = false
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
@@ -81,7 +80,7 @@ end
|
||||
|
||||
|
||||
const _glyphtypes = KW(
|
||||
:ellipse => :Circle,
|
||||
:circle => :Circle,
|
||||
:rect => :Square,
|
||||
:diamond => :Diamond,
|
||||
:utriangle => :Triangle,
|
||||
@@ -100,7 +99,7 @@ function bokeh_glyph_type(d::KW)
|
||||
st = d[:seriestype]
|
||||
mt = d[:markershape]
|
||||
if st == :scatter && mt == :none
|
||||
mt = :ellipse
|
||||
mt = :circle
|
||||
end
|
||||
|
||||
# if we have a marker, use that
|
||||
|
||||
+12
-14
@@ -2,7 +2,7 @@
|
||||
# https://github.com/dcjones/Gadfly.jl
|
||||
|
||||
|
||||
supportedArgs(::GadflyBackend) = [
|
||||
supported_args(::GadflyBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color, :foreground_color, :color_palette,
|
||||
:group, :label, :seriestype,
|
||||
@@ -15,7 +15,6 @@ supportedArgs(::GadflyBackend) = [
|
||||
:title, :window_title, :show, :size,
|
||||
:x, :xguide, :xlims, :xticks, :xscale, :xflip,
|
||||
:y, :yguide, :ylims, :yticks, :yscale, :yflip,
|
||||
# :z, :zguide, :zlims, :zticks, :zscale, :zflip,
|
||||
:z,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, :colorbar,
|
||||
@@ -23,18 +22,17 @@ supportedArgs(::GadflyBackend) = [
|
||||
:xerror, :yerror,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
]
|
||||
supportedAxes(::GadflyBackend) = [:auto, :left]
|
||||
supportedTypes(::GadflyBackend) = [
|
||||
:none, :line, :path, :steppre, :steppost, :sticks,
|
||||
:scatter, :histogram2d, :hexbin, :histogram,
|
||||
:bar, #:box, :violin, :quiver,
|
||||
:hline, :vline, :contour, :shape
|
||||
])
|
||||
supported_types(::GadflyBackend) = [
|
||||
:path,
|
||||
:scatter, :hexbin,
|
||||
:bar,
|
||||
:contour, :shape
|
||||
]
|
||||
supportedStyles(::GadflyBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::GadflyBackend) = vcat(_allMarkers, Shape)
|
||||
supportedScales(::GadflyBackend) = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::GadflyBackend) = true
|
||||
supported_styles(::GadflyBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supported_markers(::GadflyBackend) = vcat(_allMarkers, Shape)
|
||||
supported_scales(::GadflyBackend) = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
is_subplot_supported(::GadflyBackend) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
@@ -303,7 +301,7 @@ function addGadflySeries!(plt::Plot, d::KW)
|
||||
if st in (:histogram2d, :hexbin) && (isa(d[:fillcolor], ColorGradient) || isa(d[:fillcolor], ColorFunction))
|
||||
push!(gplt.scales, Gadfly.Scale.ContinuousColorScale(p -> RGB(getColorZ(d[:fillcolor], p))))
|
||||
elseif st == :scatter && d[:markershape] == :none
|
||||
d[:markershape] = :ellipse
|
||||
d[:markershape] = :circle
|
||||
end
|
||||
|
||||
# markers
|
||||
|
||||
@@ -84,7 +84,7 @@ function make_polygon(geom::ShapeGeometry, xs::AbstractArray, ys::AbstractArray,
|
||||
x = Compose.x_measure(xs[mod1(i, length(xs))])
|
||||
y = Compose.y_measure(ys[mod1(i, length(ys))])
|
||||
r = rs[mod1(i, length(rs))]
|
||||
polys[i] = T[(x + r * sx, y + r * sy) for (sx,sy) in get_mod(geom.vertices, i)]
|
||||
polys[i] = T[(x + r * sx, y + r * sy) for (sx,sy) in cycle(geom.vertices, i)]
|
||||
end
|
||||
Gadfly.polygon(polys, geom.tag)
|
||||
end
|
||||
|
||||
+66
-106
@@ -2,78 +2,47 @@
|
||||
|
||||
# [WEBSITE]
|
||||
|
||||
supportedArgs(::GLVisualizeBackend) = [
|
||||
supported_args(::GLVisualizeBackend) = merge_with_base_supported([
|
||||
# :annotations,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
# :color_palette,
|
||||
# :fillrange,
|
||||
# :fillcolor,
|
||||
# :fillalpha,
|
||||
# :foreground_color,
|
||||
# :group,
|
||||
# :background_color_legend, :background_color_inside, :background_color_outside,
|
||||
# :foreground_color_grid, :foreground_color_legend, :foreground_color_title,
|
||||
# :foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
|
||||
# :label,
|
||||
# :layout,
|
||||
# :legend,
|
||||
# :linecolor,
|
||||
# :linestyle,
|
||||
:seriestype
|
||||
# :seriescolor, :seriesalpha,
|
||||
# :linewidth,
|
||||
# :linealpha,
|
||||
# :markershape,
|
||||
# :markercolor,
|
||||
# :markersize,
|
||||
# :markeralpha,
|
||||
# :markerstrokewidth,
|
||||
# :markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
# :n,
|
||||
# :bins,
|
||||
# :nc,
|
||||
# :nr,
|
||||
# :pos,
|
||||
# :smooth,
|
||||
# :show,
|
||||
# :size,
|
||||
# :title,
|
||||
# :linecolor, :linestyle, :linewidth, :linealpha,
|
||||
# :markershape, :markercolor, :markersize, :markeralpha,
|
||||
# :markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
# :fillrange, :fillcolor, :fillalpha,
|
||||
# :bins, :bar_width, :bar_edges, :bar_position,
|
||||
# :title, :title_location, :titlefont,
|
||||
# :window_title,
|
||||
# :x,
|
||||
# :xguide,
|
||||
# :xlims,
|
||||
# :xticks,
|
||||
# :y,
|
||||
# :yguide,
|
||||
# :ylims,
|
||||
# :yrightlabel,
|
||||
# :yticks,
|
||||
# :xscale,
|
||||
# :yscale,
|
||||
# :xflip,
|
||||
# :yflip,
|
||||
# :z,
|
||||
# :tickfont,
|
||||
# :guidefont,
|
||||
# :legendfont,
|
||||
# :grid,
|
||||
# :surface
|
||||
# :levels,
|
||||
]
|
||||
supportedAxes(::GLVisualizeBackend) = [:auto, :left]
|
||||
supportedTypes(::GLVisualizeBackend) = [:surface] #, :path, :scatter ,:steppre, :steppost, :sticks, :heatmap, :hexbin, :histogram, :bar, :hline, :vline, :contour]
|
||||
supportedStyles(::GLVisualizeBackend) = [:auto, :solid] #, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::GLVisualizeBackend) = [:none, :auto, :ellipse] #, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::GLVisualizeBackend) = [:identity] #, :log, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::GLVisualizeBackend) = false
|
||||
# :guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
# :tickfont, :guidefont, :legendfont,
|
||||
# :grid, :legend, :colorbar,
|
||||
# :marker_z, :levels,
|
||||
# :ribbon, :quiver, :arrow,
|
||||
# :orientation,
|
||||
# :overwrite_figure,
|
||||
# :polar,
|
||||
# :normalize, :weights,
|
||||
# :contours, :aspect_ratio,
|
||||
# :match_dimensions,
|
||||
# :clims,
|
||||
# :inset_subplots,
|
||||
])
|
||||
supported_types(::GLVisualizeBackend) = [:surface]
|
||||
supported_styles(::GLVisualizeBackend) = [:auto, :solid]
|
||||
supported_markers(::GLVisualizeBackend) = [:none, :auto, :circle]
|
||||
supported_scales(::GLVisualizeBackend) = [:identity]
|
||||
is_subplot_supported(::GLVisualizeBackend) = false
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function _initialize_backend(::GLVisualizeBackend; kw...)
|
||||
@eval begin
|
||||
import GLVisualize
|
||||
export GLVisualize
|
||||
end
|
||||
@eval begin
|
||||
import GLVisualize
|
||||
export GLVisualize
|
||||
end
|
||||
end
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -82,55 +51,46 @@ immutable GLScreenWrapper
|
||||
window
|
||||
end
|
||||
|
||||
# function _create_plot(pkg::GLVisualizeBackend, d::KW)
|
||||
function _create_backend_figure(plt::Plot{GLVisualizeBackend})
|
||||
# TODO: create the window/canvas/context that is the plot within the backend
|
||||
# TODO: initialize the plot... title, xlabel, bgcolor, etc
|
||||
# init a window
|
||||
window = GLVisualize.glscreen()
|
||||
@async GLVisualize.renderloop(window)
|
||||
window
|
||||
end
|
||||
|
||||
# TODO: this should be moved to the display method?
|
||||
w=GLVisualize.glscreen()
|
||||
@async GLVisualize.renderloop(w)
|
||||
GLScreenWrapper(w)
|
||||
# Plot(GLScreenWrapper(w), pkg, 0, d, KW[])
|
||||
function gl_display(plt::Plot{GLVisualizeBackend})
|
||||
for sp in plt.subplots
|
||||
# TODO: setup subplot
|
||||
|
||||
for series in series_list(sp)
|
||||
# TODO: setup series
|
||||
d = series.d
|
||||
st = d[:seriestype]
|
||||
x, y, z = map(Float32, d[:x]), map(Float32, d[:y]), d[:z]
|
||||
|
||||
if st == :surface
|
||||
ismatrix(x) || (x = repmat(x', length(y), 1))
|
||||
ismatrix(y) || (y = repmat(y, 1, length(x)))
|
||||
z = transpose_z(d, map(Float32, z.surf), false)
|
||||
viz = GLVisualize.visualize((x, y, z), :surface)
|
||||
GLVisualize.view(viz, plt.o)
|
||||
return
|
||||
|
||||
else
|
||||
error("Series type $st not supported by GLVisualize")
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _series_added(plt::Plot{GLVisualizeBackend}, series::Series)
|
||||
# TODO: add one series to the underlying package
|
||||
# TODO: this should be moved to the display method?
|
||||
x, y, z = map(Float32, series.d[:x]), map(Float32, series.d[:y]), map(Float32, series.d[:z].surf)
|
||||
GLVisualize.view(GLVisualize.visualize((x*ones(y)', ones(x)*y', z), :surface), plt.o.window)
|
||||
# plt
|
||||
end
|
||||
|
||||
|
||||
# When series data is added/changed, this callback can do dynamic updates to the backend object.
|
||||
# note: if the backend rebuilds the plot from scratch on display, then you might not do anything here.
|
||||
function _series_updated(plt::Plot{GLVisualizeBackend}, series::Series)
|
||||
# TODO
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
|
||||
# Override this to update plot items (title, xlabel, etc), and add annotations (d[:annotations])
|
||||
function _update_plot_object(plt::Plot{GLVisualizeBackend})
|
||||
# TODO
|
||||
end
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{GLVisualizeBackend})
|
||||
# TODO: write a png to io
|
||||
end
|
||||
# function _writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{GLVisualizeBackend})
|
||||
# # TODO: write a png to io
|
||||
# end
|
||||
|
||||
function _display(plt::Plot{GLVisualizeBackend})
|
||||
# TODO: display/show the plot
|
||||
|
||||
# NOTE: I think maybe this should be empty? We can start with the assumption that creating
|
||||
# and adding to a plot will automatically open a window and draw to it, then the display
|
||||
# wouldn't actually need to do anything
|
||||
gl_display(plt)
|
||||
end
|
||||
|
||||
+276
-747
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,12 @@
|
||||
|
||||
# https://github.com/JuliaGraphics/Immerse.jl
|
||||
|
||||
supportedArgs(::ImmerseBackend) = supportedArgs(GadflyBackend())
|
||||
supportedAxes(::ImmerseBackend) = supportedAxes(GadflyBackend())
|
||||
supportedTypes(::ImmerseBackend) = supportedTypes(GadflyBackend())
|
||||
supportedStyles(::ImmerseBackend) = supportedStyles(GadflyBackend())
|
||||
supportedMarkers(::ImmerseBackend) = supportedMarkers(GadflyBackend())
|
||||
supportedScales(::ImmerseBackend) = supportedScales(GadflyBackend())
|
||||
subplotSupported(::ImmerseBackend) = true
|
||||
supported_args(::ImmerseBackend) = supported_args(GadflyBackend())
|
||||
supported_types(::ImmerseBackend) = supported_types(GadflyBackend())
|
||||
supported_styles(::ImmerseBackend) = supported_styles(GadflyBackend())
|
||||
supported_markers(::ImmerseBackend) = supported_markers(GadflyBackend())
|
||||
supported_scales(::ImmerseBackend) = supported_scales(GadflyBackend())
|
||||
is_subplot_supported(::ImmerseBackend) = true
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
+62
-37
@@ -2,39 +2,28 @@
|
||||
|
||||
# significant contributions by: @pkofod
|
||||
|
||||
supportedArgs(::PGFPlotsBackend) = [
|
||||
supported_args(::PGFPlotsBackend) = merge_with_base_supported([
|
||||
# :annotations,
|
||||
:background_color, :foreground_color,
|
||||
:color_palette,
|
||||
# :background_color_legend,
|
||||
:background_color_inside,
|
||||
# :background_color_outside,
|
||||
# :foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
|
||||
# :foreground_color_text, :foreground_color_border,
|
||||
:group,
|
||||
:label,
|
||||
:seriestype,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins,
|
||||
# :bar_width, :bar_edges,
|
||||
# :n, :nc, :nr,
|
||||
:layout,
|
||||
# :smooth,
|
||||
:title,
|
||||
# :window_title,
|
||||
:show, :size,
|
||||
:x, :xguide, :xlims, :xticks, :xscale, :xflip, :xrotation,
|
||||
:y, :yguide, :ylims, :yticks, :yscale, :yflip, :yrotation,
|
||||
:z, :zguide, :zlims, :zticks, :zscale, :zflip, :zrotation,
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend,
|
||||
# :colorbar,
|
||||
# :marker_z, :levels,
|
||||
# :xerror, :yerror,
|
||||
# :ribbon, :quiver, :arrow,
|
||||
# :orientation,
|
||||
# :overwrite_figure,
|
||||
@@ -42,23 +31,22 @@ supportedArgs(::PGFPlotsBackend) = [
|
||||
# :normalize, :weights, :contours,
|
||||
:aspect_ratio,
|
||||
# :match_dimensions,
|
||||
]
|
||||
supportedAxes(::PGFPlotsBackend) = [:auto, :left]
|
||||
supportedTypes(::PGFPlotsBackend) = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour]
|
||||
supportedStyles(::PGFPlotsBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supportedMarkers(::PGFPlotsBackend) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::PGFPlotsBackend) = [:identity, :ln, :log2, :log10] # :asinh, :sqrt]
|
||||
subplotSupported(::PGFPlotsBackend) = false
|
||||
])
|
||||
supported_types(::PGFPlotsBackend) = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour]
|
||||
supported_styles(::PGFPlotsBackend) = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
|
||||
supported_markers(::PGFPlotsBackend) = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon] #vcat(_allMarkers, Shape)
|
||||
supported_scales(::PGFPlotsBackend) = [:identity, :ln, :log2, :log10]
|
||||
is_subplot_supported(::PGFPlotsBackend) = false
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function _initialize_backend(::PGFPlotsBackend; kw...)
|
||||
@eval begin
|
||||
import PGFPlots
|
||||
export PGFPlots
|
||||
end
|
||||
@eval begin
|
||||
import PGFPlots
|
||||
export PGFPlots
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -78,7 +66,7 @@ const _pgfplots_markers = KW(
|
||||
:xcross => "x",
|
||||
:utriangle => "triangle*",
|
||||
:dtriangle => "triangle*",
|
||||
:ellipse => "*",
|
||||
:circle => "*",
|
||||
:rect => "square*",
|
||||
:star5 => "star",
|
||||
:star6 => "asterisk",
|
||||
@@ -145,7 +133,6 @@ end
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
function pgf_series(sp::Subplot, series::Series)
|
||||
d = series.d
|
||||
st = d[:seriestype]
|
||||
@@ -173,6 +160,18 @@ function pgf_series(sp::Subplot, series::Series)
|
||||
d[:x], d[:y]
|
||||
end
|
||||
|
||||
# PGFPlots can't handle non-Vector?
|
||||
args = map(a -> if typeof(a) <: AbstractVector && typeof(a) != Vector
|
||||
collect(a)
|
||||
else
|
||||
a
|
||||
end, args)
|
||||
# for (i,a) in enumerate(args)
|
||||
# if typeof(a) <: AbstractVector && typeof(a) != Vector
|
||||
# args[i] = collect(a)
|
||||
# end
|
||||
# end
|
||||
|
||||
# include additional style, then add to the kw
|
||||
if haskey(_pgf_series_extrastyle, st)
|
||||
push!(style, _pgf_series_extrastyle[st])
|
||||
@@ -216,9 +215,12 @@ function pgf_axis(sp::Subplot, letter)
|
||||
end
|
||||
|
||||
# limits
|
||||
lims = axis_limits(axis)
|
||||
kw[Symbol(letter,:min)] = lims[1]
|
||||
kw[Symbol(letter,:max)] = lims[2]
|
||||
# TODO: support zlims
|
||||
if letter != :z
|
||||
lims = axis_limits(axis)
|
||||
kw[Symbol(letter,:min)] = lims[1]
|
||||
kw[Symbol(letter,:max)] = lims[2]
|
||||
end
|
||||
|
||||
# return the style list and KW args
|
||||
style, kw
|
||||
@@ -281,16 +283,39 @@ end
|
||||
|
||||
|
||||
function _writemime(io::IO, mime::MIME"image/svg+xml", plt::Plot{PGFPlotsBackend})
|
||||
_make_pgf_plot!(plt)
|
||||
writemime(io, mime, plt.o)
|
||||
_make_pgf_plot!(plt)
|
||||
writemime(io, mime, plt.o)
|
||||
end
|
||||
|
||||
function _writemime(io::IO, mime::MIME"image/png", plt::Plot{PGFPlotsBackend})
|
||||
_make_pgf_plot!(plt)
|
||||
writemime(io, mime, plt.o)
|
||||
function _writemime(io::IO, mime::MIME"application/pdf", plt::Plot{PGFPlotsBackend})
|
||||
_make_pgf_plot!(plt)
|
||||
|
||||
# prepare the object
|
||||
pgfplt = PGFPlots.plot(plt.o)
|
||||
|
||||
# save a pdf
|
||||
fn = tempname()*".pdf"
|
||||
PGFPlots.save(PGFPlots.PDF(fn), pgfplt)
|
||||
|
||||
# read it into io
|
||||
write(io, readall(open(fn)))
|
||||
|
||||
# cleanup
|
||||
PGFPlots.cleanup(plt.o)
|
||||
end
|
||||
|
||||
function _display(plt::Plot{PGFPlotsBackend})
|
||||
_make_pgf_plot!(plt)
|
||||
display(plt.o)
|
||||
# prepare the object
|
||||
_make_pgf_plot!(plt)
|
||||
pgfplt = PGFPlots.plot(plt.o)
|
||||
|
||||
# save an svg
|
||||
fn = string(tempname(), ".svg")
|
||||
PGFPlots.save(PGFPlots.SVG(fn), pgfplt)
|
||||
|
||||
# show it
|
||||
open_browser_window(fn)
|
||||
|
||||
# cleanup
|
||||
PGFPlots.cleanup(plt.o)
|
||||
end
|
||||
|
||||
+133
-106
@@ -1,49 +1,48 @@
|
||||
|
||||
# https://plot.ly/javascript/getting-started
|
||||
|
||||
supportedArgs(::PlotlyBackend) = [
|
||||
supported_args(::PlotlyBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:background_color, :foreground_color, :color_palette,
|
||||
# :background_color_legend, :background_color_inside, :background_color_outside,
|
||||
# :foreground_color_legend, :foreground_color_grid, :foreground_color_axis,
|
||||
# :foreground_color_text, :foreground_color_border,
|
||||
:group,
|
||||
:background_color_legend, :background_color_inside, :background_color_outside,
|
||||
:foreground_color_legend, :foreground_color_guide,
|
||||
# :foreground_color_grid, :foreground_color_axis,
|
||||
:foreground_color_text, :foreground_color_border,
|
||||
:foreground_color_title,
|
||||
:label,
|
||||
:seriestype,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linecolor, :linestyle, :linewidth, :linealpha,
|
||||
:markershape, :markercolor, :markersize, :markeralpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
|
||||
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
|
||||
:fillrange, :fillcolor, :fillalpha,
|
||||
:bins,
|
||||
:n, :nc, :nr, :layout,
|
||||
# :smooth,
|
||||
:title, :window_title, :show, :size,
|
||||
:x, :xguide, :xlims, :xticks, :xscale, :xflip, :xrotation,
|
||||
:y, :yguide, :ylims, :yticks, :yscale, :yflip, :yrotation,
|
||||
:z, :zguide, :zlims, :zticks, :zscale, :zflip, :zrotation,
|
||||
:z,
|
||||
:title, :title_location, :titlefont,
|
||||
:window_title,
|
||||
:guide, :lims, :ticks, :scale, :flip, :rotation,
|
||||
:tickfont, :guidefont, :legendfont,
|
||||
:grid, :legend, :colorbar,
|
||||
:marker_z, :levels,
|
||||
:xerror, :yerror,
|
||||
:ribbon, :quiver,
|
||||
:orientation,
|
||||
# :overwrite_figure,
|
||||
:polar,
|
||||
# :normalize, :weights, :contours, :aspect_ratio
|
||||
]
|
||||
:normalize, :weights,
|
||||
# :contours, :aspect_ratio,
|
||||
:hover,
|
||||
:inset_subplots,
|
||||
])
|
||||
|
||||
supportedAxes(::PlotlyBackend) = [:auto, :left]
|
||||
supportedTypes(::PlotlyBackend) = [:none, :line, :path, :scatter, :steppre, :steppost,
|
||||
:histogram2d, :histogram, :density, :bar, :contour, :surface, :path3d, :scatter3d,
|
||||
:pie, :heatmap] #,, :sticks, :hexbin, :hline, :vline]
|
||||
supportedStyles(::PlotlyBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supportedMarkers(::PlotlyBackend) = [:none, :auto, :ellipse, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross,
|
||||
:pentagon, :hexagon, :octagon, :vline, :hline] #vcat(_allMarkers, Shape)
|
||||
supportedScales(::PlotlyBackend) = [:identity, :log10] #, :ln, :log2, :log10, :asinh, :sqrt]
|
||||
subplotSupported(::PlotlyBackend) = true
|
||||
stringsSupported(::PlotlyBackend) = true
|
||||
supported_types(::PlotlyBackend) = [
|
||||
:path, :scatter, :bar, :pie, :heatmap,
|
||||
:contour, :surface, :path3d, :scatter3d, :shape, :scattergl,
|
||||
]
|
||||
supported_styles(::PlotlyBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supported_markers(::PlotlyBackend) = [
|
||||
:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle,
|
||||
:cross, :xcross, :pentagon, :hexagon, :octagon, :vline, :hline
|
||||
]
|
||||
supported_scales(::PlotlyBackend) = [:identity, :log10]
|
||||
is_subplot_supported(::PlotlyBackend) = true
|
||||
is_string_supported(::PlotlyBackend) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
@@ -85,7 +84,7 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function plotlyfont(font::Font, color = font.color)
|
||||
function plotly_font(font::Font, color = font.color)
|
||||
KW(
|
||||
:family => font.family,
|
||||
:size => round(Int, font.pointsize*1.4),
|
||||
@@ -93,20 +92,20 @@ function plotlyfont(font::Font, color = font.color)
|
||||
)
|
||||
end
|
||||
|
||||
function get_annotation_dict(x, y, val)
|
||||
function plotly_annotation_dict(x, y, val; xref="paper", yref="paper")
|
||||
KW(
|
||||
:text => val,
|
||||
:xref => "x",
|
||||
:xref => xref,
|
||||
:x => x,
|
||||
:yref => "y",
|
||||
:yref => xref,
|
||||
:y => y,
|
||||
:showarrow => false,
|
||||
)
|
||||
end
|
||||
|
||||
function get_annotation_dict(x, y, ptxt::PlotText)
|
||||
merge(get_annotation_dict(x, y, ptxt.str), KW(
|
||||
:font => plotlyfont(ptxt.font),
|
||||
function plotly_annotation_dict(x, y, ptxt::PlotText; xref="paper", yref="paper")
|
||||
merge(plotly_annotation_dict(x, y, ptxt.str; xref=xref, yref=yref), KW(
|
||||
:font => plotly_font(ptxt.font),
|
||||
:xanchor => ptxt.font.halign == :hcenter ? :center : ptxt.font.halign,
|
||||
:yanchor => ptxt.font.valign == :vcenter ? :middle : ptxt.font.valign,
|
||||
:rotation => ptxt.font.rotation,
|
||||
@@ -136,7 +135,7 @@ end
|
||||
# )
|
||||
# end
|
||||
|
||||
function plotlyscale(scale::Symbol)
|
||||
function plotly_scale(scale::Symbol)
|
||||
if scale == :log10
|
||||
"log"
|
||||
else
|
||||
@@ -144,7 +143,6 @@ function plotlyscale(scale::Symbol)
|
||||
end
|
||||
end
|
||||
|
||||
use_axis_field(ticks) = !(ticks in (nothing, :none))
|
||||
|
||||
# this method gets the start/end in percentage of the canvas for this axis direction
|
||||
function plotly_domain(sp::Subplot, letter)
|
||||
@@ -157,19 +155,12 @@ end
|
||||
|
||||
function plotly_axis(axis::Axis, sp::Subplot)
|
||||
letter = axis[:letter]
|
||||
# d = axis.d
|
||||
ax = KW(
|
||||
:title => axis[:guide],
|
||||
:showgrid => sp[:grid],
|
||||
:zeroline => false,
|
||||
)
|
||||
|
||||
# fgcolor = webcolor(axis[:foreground_color])
|
||||
# tsym = tickssym(letter)
|
||||
|
||||
# spidx = sp[:subplot_index]
|
||||
# d_out[:xaxis] = "x$spidx"
|
||||
# d_out[:yaxis] = "y$spidx"
|
||||
if letter in (:x,:y)
|
||||
ax[:domain] = plotly_domain(sp, letter)
|
||||
ax[:anchor] = "$(letter==:x ? :y : :x)$(plotly_subplot_index(sp))"
|
||||
@@ -180,10 +171,10 @@ function plotly_axis(axis::Axis, sp::Subplot)
|
||||
ax[:tickangle] = rot
|
||||
end
|
||||
|
||||
if use_axis_field(axis[:ticks])
|
||||
ax[:titlefont] = plotlyfont(axis[:guidefont], webcolor(axis[:foreground_color_guide]))
|
||||
ax[:type] = plotlyscale(axis[:scale])
|
||||
ax[:tickfont] = plotlyfont(axis[:tickfont], webcolor(axis[:foreground_color_text]))
|
||||
if !(axis[:ticks] in (nothing, :none))
|
||||
ax[:titlefont] = plotly_font(axis[:guidefont], axis[:foreground_color_guide])
|
||||
ax[:type] = plotly_scale(axis[:scale])
|
||||
ax[:tickfont] = plotly_font(axis[:tickfont], axis[:foreground_color_text])
|
||||
ax[:tickcolor] = webcolor(axis[:foreground_color_border])
|
||||
ax[:linecolor] = webcolor(axis[:foreground_color_border])
|
||||
|
||||
@@ -218,32 +209,35 @@ function plotly_axis(axis::Axis, sp::Subplot)
|
||||
ax
|
||||
end
|
||||
|
||||
# function plotly_layout_json(plt::Plot{PlotlyBackend})
|
||||
# d = plt
|
||||
# function plotly_layout(d::KW, seriesargs::AVec{KW})
|
||||
function plotly_layout(plt::Plot)
|
||||
d_out = KW()
|
||||
|
||||
# # for now, we only support 1 subplot
|
||||
# if length(plt.subplots) > 1
|
||||
# warn("Subplots not supported yet")
|
||||
# end
|
||||
# sp = plt.subplots[1]
|
||||
|
||||
d_out[:width], d_out[:height] = plt[:size]
|
||||
w, h = plt[:size]
|
||||
d_out[:width], d_out[:height] = w, h
|
||||
d_out[:paper_bgcolor] = webcolor(plt[:background_color_outside])
|
||||
d_out[:margin] = KW(:l=>0, :b=>0, :r=>0, :t=>20)
|
||||
|
||||
d_out[:annotations] = KW[]
|
||||
|
||||
for sp in plt.subplots
|
||||
sp_out = KW()
|
||||
spidx = plotly_subplot_index(sp)
|
||||
|
||||
# set the fields for the plot
|
||||
d_out[:title] = sp[:title]
|
||||
d_out[:titlefont] = plotlyfont(sp[:titlefont], webcolor(sp[:foreground_color_title]))
|
||||
|
||||
# # TODO: use subplot positioning logic
|
||||
# d_out[:margin] = KW(:l=>35, :b=>30, :r=>8, :t=>20)
|
||||
d_out[:margin] = KW(:l=>0, :b=>0, :r=>0, :t=>30)
|
||||
# add an annotation for the title... positioned horizontally relative to plotarea,
|
||||
# but vertically just below the top of the subplot bounding box
|
||||
if sp[:title] != ""
|
||||
bb = plotarea(sp)
|
||||
tpos = sp[:title_location]
|
||||
xmm = if tpos == :left
|
||||
left(bb)
|
||||
elseif tpos == :right
|
||||
right(bb)
|
||||
else
|
||||
0.5 * (left(bb) + right(bb))
|
||||
end
|
||||
titlex, titley = xy_mm_to_pcts(xmm, top(bbox(sp)), w*px, h*px)
|
||||
titlefont = font(sp[:titlefont], :top, sp[:foreground_color_title])
|
||||
push!(d_out[:annotations], plotly_annotation_dict(titlex, titley, text(sp[:title], titlefont)))
|
||||
end
|
||||
|
||||
d_out[:plot_bgcolor] = webcolor(sp[:background_color_inside])
|
||||
|
||||
@@ -267,17 +261,12 @@ function plotly_layout(plt::Plot)
|
||||
d_out[:legend] = KW(
|
||||
:bgcolor => webcolor(sp[:background_color_legend]),
|
||||
:bordercolor => webcolor(sp[:foreground_color_legend]),
|
||||
:font => plotlyfont(sp[:legendfont]),
|
||||
:font => plotly_font(sp[:legendfont], sp[:foreground_color_legend]),
|
||||
)
|
||||
end
|
||||
|
||||
# annotations
|
||||
anns = sp[:annotations]
|
||||
d_out[:annotations] = if isempty(anns)
|
||||
KW[]
|
||||
else
|
||||
KW[get_annotation_dict(ann...) for ann in anns]
|
||||
end
|
||||
append!(d_out[:annotations], KW[plotly_annotation_dict(ann...; xref = "x$spidx", yref = "y$spidx") for ann in sp[:annotations]])
|
||||
|
||||
# # arrows
|
||||
# for sargs in seriesargs
|
||||
@@ -288,8 +277,6 @@ function plotly_layout(plt::Plot)
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# dumpdict(d_out,"",true)
|
||||
# @show d_out[:annotations]
|
||||
|
||||
if ispolar(sp)
|
||||
d_out[:direction] = "counterclockwise"
|
||||
@@ -298,6 +285,11 @@ function plotly_layout(plt::Plot)
|
||||
d_out
|
||||
end
|
||||
|
||||
# turn off hover if nothing's using it
|
||||
if all(series -> series.d[:hover] in (false,:none), plt.series_list)
|
||||
d_out[:hovermode] = "none"
|
||||
end
|
||||
|
||||
d_out
|
||||
end
|
||||
|
||||
@@ -327,6 +319,17 @@ function plotly_subplot_index(sp::Subplot)
|
||||
end
|
||||
|
||||
|
||||
# the Shape contructor will automatically close the shape. since we need it closed,
|
||||
# we split by NaNs and then construct/destruct the shapes to get the closed coords
|
||||
function plotly_close_shapes(x, y)
|
||||
xs, ys = nansplit(x), nansplit(y)
|
||||
for i=1:length(xs)
|
||||
shape = Shape(xs[i], ys[i])
|
||||
xs[i], ys[i] = shape_coords(shape)
|
||||
end
|
||||
nanvcat(xs), nanvcat(ys)
|
||||
end
|
||||
|
||||
# get a dictionary representing the series params (d is the Plots-dict, d_out is the Plotly-dict)
|
||||
function plotly_series(plt::Plot, series::Series)
|
||||
d = series.d
|
||||
@@ -337,17 +340,19 @@ function plotly_series(plt::Plot, series::Series)
|
||||
spidx = plotly_subplot_index(sp)
|
||||
d_out[:xaxis] = "x$spidx"
|
||||
d_out[:yaxis] = "y$spidx"
|
||||
d_out[:showlegend] = should_add_to_legend(series)
|
||||
|
||||
x, y = collect(d[:x]), collect(d[:y])
|
||||
d_out[:name] = d[:label]
|
||||
st = d[:seriestype]
|
||||
isscatter = st in (:scatter, :scatter3d)
|
||||
isscatter = st in (:scatter, :scatter3d, :scattergl)
|
||||
hasmarker = isscatter || d[:markershape] != :none
|
||||
hasline = !isscatter
|
||||
# hasline = !isscatter
|
||||
hasline = st in (:path, :path3d)
|
||||
|
||||
# set the "type"
|
||||
if st in (:line, :path, :scatter, :steppre, :steppost)
|
||||
d_out[:type] = "scatter"
|
||||
if st in (:path, :scatter, :scattergl)
|
||||
d_out[:type] = st==:scattergl ? "scattergl" : "scatter"
|
||||
d_out[:mode] = if hasmarker
|
||||
hasline ? "lines+markers" : "markers"
|
||||
else
|
||||
@@ -361,42 +366,58 @@ function plotly_series(plt::Plot, series::Series)
|
||||
end
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
|
||||
elseif st == :shape
|
||||
# to draw polygons, we actually draw lines with fill
|
||||
d_out[:type] = "scatter"
|
||||
d_out[:mode] = "lines"
|
||||
d_out[:x], d_out[:y] = plotly_close_shapes(x, y)
|
||||
# @show map(length, (x,y,d_out[:x],d_out[:y]))
|
||||
# @show d_out[:x] d_out[:y]
|
||||
d_out[:fill] = "tozeroy"
|
||||
d_out[:fillcolor] = webcolor(d[:markercolor], d[:markeralpha])
|
||||
if d[:markerstrokewidth] > 0
|
||||
d_out[:line] = KW(
|
||||
:color => webcolor(d[:markerstrokecolor], d[:markerstrokealpha]),
|
||||
:width => d[:markerstrokewidth],
|
||||
:dash => string(d[:markerstrokestyle]),
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
|
||||
elseif st == :bar
|
||||
d_out[:type] = "bar"
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
d_out[:orientation] = isvertical(d) ? "v" : "h"
|
||||
|
||||
elseif st == :histogram2d
|
||||
d_out[:type] = "histogram2d"
|
||||
d_out[:x], d_out[:y] = x, y
|
||||
if isa(d[:bins], Tuple)
|
||||
xbins, ybins = d[:bins]
|
||||
else
|
||||
xbins = ybins = d[:bins]
|
||||
end
|
||||
d_out[:nbinsx] = xbins
|
||||
d_out[:nbinsy] = ybins
|
||||
d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha])
|
||||
# elseif st == :histogram2d
|
||||
# d_out[:type] = "histogram2d"
|
||||
# d_out[:x], d_out[:y] = x, y
|
||||
# if isa(d[:bins], Tuple)
|
||||
# xbins, ybins = d[:bins]
|
||||
# else
|
||||
# xbins = ybins = d[:bins]
|
||||
# end
|
||||
# d_out[:nbinsx] = xbins
|
||||
# d_out[:nbinsy] = ybins
|
||||
# d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha])
|
||||
|
||||
elseif st in (:histogram, :density)
|
||||
d_out[:type] = "histogram"
|
||||
isvert = isvertical(d)
|
||||
d_out[isvert ? :x : :y] = y
|
||||
d_out[isvert ? :nbinsx : :nbinsy] = d[:bins]
|
||||
if st == :density
|
||||
d_out[:histogramnorm] = "probability density"
|
||||
end
|
||||
# elseif st in (:histogram, :density)
|
||||
# d_out[:type] = "histogram"
|
||||
# isvert = isvertical(d)
|
||||
# d_out[isvert ? :x : :y] = y
|
||||
# d_out[isvert ? :nbinsx : :nbinsy] = d[:bins]
|
||||
# if st == :density
|
||||
# d_out[:histogramnorm] = "probability density"
|
||||
# end
|
||||
|
||||
elseif st == :heatmap
|
||||
d_out[:type] = "heatmap"
|
||||
# d_out[:x], d_out[:y] = x, y
|
||||
# d_out[:z] = d[:z].surf
|
||||
d_out[:x], d_out[:y], d_out[:z] = d[:x], d[:y], transpose_z(d, d[:z].surf, false)
|
||||
d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha])
|
||||
|
||||
elseif st == :contour
|
||||
d_out[:type] = "contour"
|
||||
# d_out[:x], d_out[:y] = x, y
|
||||
# d_out[:z] = d[:z].surf
|
||||
d_out[:x], d_out[:y], d_out[:z] = d[:x], d[:y], transpose_z(d, d[:z].surf, false)
|
||||
# d_out[:showscale] = d[:colorbar] != :none
|
||||
d_out[:ncontours] = d[:levels]
|
||||
@@ -405,8 +426,6 @@ function plotly_series(plt::Plot, series::Series)
|
||||
|
||||
elseif st in (:surface, :wireframe)
|
||||
d_out[:type] = "surface"
|
||||
# d_out[:x], d_out[:y] = x, y
|
||||
# d_out[:z] = d[:z].surf
|
||||
d_out[:x], d_out[:y], d_out[:z] = d[:x], d[:y], transpose_z(d, d[:z].surf, false)
|
||||
d_out[:colorscale] = plotly_colorscale(d[:fillcolor], d[:fillalpha])
|
||||
|
||||
@@ -478,6 +497,15 @@ function plotly_series(plt::Plot, series::Series)
|
||||
d_out[:r] = pop!(d_out, :y)
|
||||
end
|
||||
|
||||
# hover text
|
||||
hover = d[:hover]
|
||||
if hover in (:none, false)
|
||||
d_out[:hoverinfo] = "none"
|
||||
elseif hover != nothing
|
||||
d_out[:hoverinfo] = "text"
|
||||
d_out[:text] = hover
|
||||
end
|
||||
|
||||
d_out
|
||||
end
|
||||
|
||||
@@ -523,11 +551,10 @@ function _writemime(io::IO, ::MIME"image/png", plt::Plot{PlotlyBackend})
|
||||
writemime_png_from_html(io, plt)
|
||||
end
|
||||
|
||||
function _writemime(io::IO, ::MIME"text/html", plt::Plot{PlotlyBackend})
|
||||
function _writemime(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyBackend})
|
||||
write(io, html_head(plt) * html_body(plt))
|
||||
end
|
||||
|
||||
# function Base.display(::PlotsDisplay, plt::Plot{PlotlyBackend})
|
||||
function _display(plt::Plot{PlotlyBackend})
|
||||
standalone_html_window(plt)
|
||||
end
|
||||
|
||||
+14
-126
@@ -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
File diff suppressed because it is too large
Load Diff
+10
-33
@@ -2,52 +2,29 @@
|
||||
# https://github.com/tbreloff/Qwt.jl
|
||||
|
||||
|
||||
supportedArgs(::QwtBackend) = [
|
||||
supported_args(::QwtBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
:axis,
|
||||
:background_color,
|
||||
:linecolor,
|
||||
:color_palette,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
:foreground_color,
|
||||
:group,
|
||||
:label,
|
||||
:layout,
|
||||
:legend,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linestyle,
|
||||
:seriestype,
|
||||
:linewidth,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
:n,
|
||||
:bins,
|
||||
:nc,
|
||||
:nr,
|
||||
:pos,
|
||||
:smooth,
|
||||
:show,
|
||||
:size,
|
||||
:title,
|
||||
:window_title,
|
||||
:x,
|
||||
:xguide,
|
||||
:xlims,
|
||||
:xticks,
|
||||
:y,
|
||||
:yguide,
|
||||
:ylims,
|
||||
:yrightlabel,
|
||||
:yticks,
|
||||
:xscale,
|
||||
:yscale,
|
||||
]
|
||||
supportedTypes(::QwtBackend) = [:none, :line, :path, :steppre, :steppost, :sticks, :scatter, :histogram2d, :hexbin, :histogram, :bar, :hline, :vline]
|
||||
supportedMarkers(::QwtBackend) = [:none, :auto, :rect, :ellipse, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :star8, :hexagon]
|
||||
supportedScales(::QwtBackend) = [:identity, :log10]
|
||||
subplotSupported(::QwtBackend) = true
|
||||
:guide, :lims, :ticks, :scale,
|
||||
])
|
||||
supported_types(::QwtBackend) = [:path, :scatter, :hexbin, :bar]
|
||||
supported_markers(::QwtBackend) = [:none, :auto, :rect, :circle, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :star8, :hexagon]
|
||||
supported_scales(::QwtBackend) = [:identity, :log10]
|
||||
is_subplot_supported(::QwtBackend) = true
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
@@ -95,13 +72,13 @@ function adjustQwtKeywords(plt::Plot{QwtBackend}, iscreating::Bool; kw...)
|
||||
if st == :scatter
|
||||
d[:seriestype] = :none
|
||||
if d[:markershape] == :none
|
||||
d[:markershape] = :ellipse
|
||||
d[:markershape] = :circle
|
||||
end
|
||||
|
||||
elseif st in (:hline, :vline)
|
||||
addLineMarker(plt, d)
|
||||
d[:seriestype] = :none
|
||||
d[:markershape] = :ellipse
|
||||
d[:markershape] = :circle
|
||||
d[:markersize] = 1
|
||||
if st == :vline
|
||||
d[:x], d[:y] = d[:y], d[:x]
|
||||
@@ -184,7 +161,7 @@ function updateLimsAndTicks(plt::Plot{QwtBackend}, d::KW, isx::Bool)
|
||||
# scaletype == :log && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(e))
|
||||
# scaletype == :log2 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLogScaleEngine(2))
|
||||
scaletype == :log10 && w[:setAxisScaleEngine](axisid, Qwt.QWT.QwtLog10ScaleEngine())
|
||||
scaletype in supportedScales() || warn("Unsupported scale type: ", scaletype)
|
||||
scaletype in supported_scales() || warn("Unsupported scale type: ", scaletype)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -19,9 +19,9 @@ function _create_backend_figure(plt::Plot{[PkgName]Backend})
|
||||
nothing
|
||||
end
|
||||
|
||||
# this is called early in the pipeline, use it to make the plot current or something
|
||||
function _prepare_plot_object(plt::Plot{[PkgName]Backend})
|
||||
end
|
||||
# # this is called early in the pipeline, use it to make the plot current or something
|
||||
# function _prepare_plot_object(plt::Plot{[PkgName]Backend})
|
||||
# end
|
||||
|
||||
# Set up the subplot within the backend object.
|
||||
function _initialize_subplot(plt::Plot{[PkgName]Backend}, sp::Subplot{[PkgName]Backend})
|
||||
|
||||
+64
-233
@@ -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
@@ -3,64 +3,29 @@
|
||||
|
||||
# credit goes to https://github.com/jverzani for contributing to the first draft of this backend implementation
|
||||
|
||||
supportedArgs(::WinstonBackend) = [
|
||||
supported_args(::WinstonBackend) = merge_with_base_supported([
|
||||
:annotations,
|
||||
# :args,
|
||||
# :axis,
|
||||
# :background_color,
|
||||
:linecolor,
|
||||
:color_palette,
|
||||
:fillrange,
|
||||
:fillcolor,
|
||||
# :foreground_color,
|
||||
:group,
|
||||
# :heatmap_c,
|
||||
# :kwargs,
|
||||
:label,
|
||||
# :layout,
|
||||
:legend,
|
||||
:seriescolor, :seriesalpha,
|
||||
:linestyle,
|
||||
:seriestype,
|
||||
:linewidth,
|
||||
:markershape,
|
||||
:markercolor,
|
||||
:markersize,
|
||||
# :markerstrokewidth,
|
||||
# :markerstrokecolor,
|
||||
# :markerstrokestyle,
|
||||
# :n,
|
||||
:bins,
|
||||
# :nc,
|
||||
# :nr,
|
||||
# :pos,
|
||||
:smooth,
|
||||
# :ribbon,
|
||||
:show,
|
||||
:size,
|
||||
:title,
|
||||
:window_title,
|
||||
:x,
|
||||
:xguide,
|
||||
:xlims,
|
||||
# :xticks,
|
||||
:y,
|
||||
:yguide,
|
||||
:ylims,
|
||||
# :yrightlabel,
|
||||
# :yticks,
|
||||
:xscale,
|
||||
:yscale,
|
||||
# :xflip,
|
||||
# :yflip,
|
||||
# :z,
|
||||
]
|
||||
supportedAxes(::WinstonBackend) = [:auto, :left]
|
||||
supportedTypes(::WinstonBackend) = [:none, :line, :path, :sticks, :scatter, :histogram, :bar]
|
||||
supportedStyles(::WinstonBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supportedMarkers(::WinstonBackend) = [:none, :auto, :rect, :ellipse, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
|
||||
supportedScales(::WinstonBackend) = [:identity, :log10]
|
||||
subplotSupported(::WinstonBackend) = false
|
||||
:guide, :lims, :scale,
|
||||
])
|
||||
supported_types(::WinstonBackend) = [:path, :scatter, :bar]
|
||||
supported_styles(::WinstonBackend) = [:auto, :solid, :dash, :dot, :dashdot]
|
||||
supported_markers(::WinstonBackend) = [:none, :auto, :rect, :circle, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5]
|
||||
supported_scales(::WinstonBackend) = [:identity, :log10]
|
||||
is_subplot_supported(::WinstonBackend) = false
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------------------
|
||||
@@ -87,7 +52,7 @@ end
|
||||
|
||||
@compat const winston_marker = KW(:none=>".",
|
||||
:rect => "square",
|
||||
:ellipse=>"circle",
|
||||
:circle=>"circle",
|
||||
:diamond=>"diamond",
|
||||
:utriangle=>"triangle",
|
||||
:dtriangle=>"down-triangle",
|
||||
@@ -170,7 +135,7 @@ function _series_added(plt::Plot{WinstonBackend}, series::Series)
|
||||
|
||||
elseif d[:seriestype] == :scatter
|
||||
if d[:markershape] == :none
|
||||
d[:markershape] = :ellipse
|
||||
d[:markershape] = :circle
|
||||
end
|
||||
|
||||
# elseif d[:seriestype] == :step
|
||||
|
||||
@@ -23,6 +23,8 @@ convertColor(c::Symbol) = parse(Colorant, string(c))
|
||||
convertColor(c::Colorant) = c
|
||||
convertColor(cvec::AbstractVector) = map(convertColor, cvec)
|
||||
convertColor(c::ColorScheme) = c
|
||||
convertColor(v::Void) = RGBA(0,0,0,0)
|
||||
convertColor(b::Bool) = b ? RGBA(0,0,0,1) : RGBA(0,0,0,0)
|
||||
|
||||
function convertColor(c, α::Real)
|
||||
c = convertColor(c)
|
||||
@@ -119,6 +121,11 @@ function ColorGradient(grad::ColorGradient; alpha = nothing)
|
||||
ColorGradient(convertColor(grad.colors, alpha), grad.values)
|
||||
end
|
||||
|
||||
# anything else just gets the default gradient
|
||||
function ColorGradient(cw; alpha=nothing)
|
||||
ColorGradient(default_gradient(), alpha=alpha)
|
||||
end
|
||||
|
||||
getColor(gradient::ColorGradient, idx::Int) = gradient.colors[mod1(idx, length(gradient.colors))]
|
||||
|
||||
function getColorZ(gradient::ColorGradient, z::Real)
|
||||
|
||||
+40
-4
@@ -12,8 +12,15 @@ compute_angle(v::P2) = (angle = atan2(v[2], v[1]); angle < 0 ? 2π - angle : ang
|
||||
# -------------------------------------------------------------
|
||||
|
||||
immutable Shape
|
||||
x::AVec
|
||||
y::AVec
|
||||
x::Vector{Float64}
|
||||
y::Vector{Float64}
|
||||
function Shape(x::AVec, y::AVec)
|
||||
if x[1] != x[end] || y[1] != y[end]
|
||||
new(vcat(x, x[1]), vcat(y, y[1]))
|
||||
else
|
||||
new(x, y)
|
||||
end
|
||||
end
|
||||
end
|
||||
Shape(verts::AVec) = Shape(unzip(verts)...)
|
||||
|
||||
@@ -93,8 +100,29 @@ function makearrowhead(angle; h = 2.0, w = 0.4)
|
||||
from_polar(angle + 0.5π, w) - tip, (0,0)])
|
||||
end
|
||||
|
||||
const _shape_keys = Symbol[
|
||||
:circle,
|
||||
:rect,
|
||||
:star5,
|
||||
:diamond,
|
||||
:hexagon,
|
||||
:cross,
|
||||
:xcross,
|
||||
:utriangle,
|
||||
:dtriangle,
|
||||
:pentagon,
|
||||
:heptagon,
|
||||
:octagon,
|
||||
:star4,
|
||||
:star6,
|
||||
:star7,
|
||||
:star8,
|
||||
:vline,
|
||||
:hline,
|
||||
]
|
||||
|
||||
const _shapes = KW(
|
||||
:ellipse => makeshape(20),
|
||||
:circle => makeshape(20),
|
||||
:rect => makeshape(4, offset=-0.25),
|
||||
:diamond => makeshape(4),
|
||||
:utriangle => makeshape(3),
|
||||
@@ -218,7 +246,14 @@ function font(args...)
|
||||
for arg in args
|
||||
T = typeof(arg)
|
||||
|
||||
if arg == :center
|
||||
if T == Font
|
||||
family = arg.family
|
||||
pointsize = arg.pointsize
|
||||
halign = arg.halign
|
||||
valign = arg.valign
|
||||
rotation = arg.rotation
|
||||
color = arg.color
|
||||
elseif arg == :center
|
||||
halign = :hcenter
|
||||
valign = :vcenter
|
||||
elseif arg in (:hcenter, :left, :right)
|
||||
@@ -253,6 +288,7 @@ end
|
||||
PlotText(str) = PlotText(string(str), font())
|
||||
|
||||
text(t::PlotText) = t
|
||||
text(str::AbstractString, f::Font) = PlotText(str, f)
|
||||
function text(str, args...)
|
||||
PlotText(string(str), font(args...))
|
||||
end
|
||||
|
||||
+13
-6
@@ -115,15 +115,17 @@ PlotExample("Line types",
|
||||
PlotExample("Line styles",
|
||||
"",
|
||||
[:(begin
|
||||
styles = setdiff(supportedStyles(), [:auto])'
|
||||
plot(cumsum(randn(20,length(styles)),1), style=:auto, label=map(string,styles), w=5)
|
||||
styles = filter(s -> s in supported_styles(), [:solid, :dash, :dot, :dashdot, :dashdotdot])'
|
||||
n = length(styles)
|
||||
y = cumsum(randn(20,n),1)
|
||||
plot(y, line = (5, styles), label = map(string,styles))
|
||||
end)]
|
||||
),
|
||||
|
||||
PlotExample("Marker types",
|
||||
"",
|
||||
[:(begin
|
||||
markers = setdiff(supportedMarkers(), [:none,:auto,Shape])'
|
||||
markers = filter(m -> m in supported_markers(), Plots._shape_keys)'
|
||||
n = length(markers)
|
||||
x = linspace(0,10,n+2)[2:end-1]
|
||||
y = repmat(reverse(x)', n, 1)
|
||||
@@ -264,7 +266,7 @@ PlotExample("Groups and Subplots",
|
||||
"",
|
||||
[:(begin
|
||||
group = rand(map(i->"group $i",1:4),100)
|
||||
plot(rand(100), layout=@layout([a b;c]), group=group, n=3, linetype=[:bar :scatter :steppre])
|
||||
plot(rand(100), layout=@layout([a b;c]), group=group, linetype=[:bar :scatter :steppre])
|
||||
end)]
|
||||
),
|
||||
|
||||
@@ -325,11 +327,13 @@ function test_examples(pkgname::Symbol, idx::Int; debug = false, disp = true)
|
||||
end
|
||||
|
||||
# generate all plots and create a dict mapping idx --> plt
|
||||
function test_examples(pkgname::Symbol; debug = false, disp = true)
|
||||
function test_examples(pkgname::Symbol; debug = false, disp = true, sleep = nothing,
|
||||
skip = [], only = nothing)
|
||||
Plots._debugMode.on = debug
|
||||
plts = Dict()
|
||||
for i in 1:length(_examples)
|
||||
|
||||
only != nothing && !(i in only) && continue
|
||||
i in skip && continue
|
||||
try
|
||||
plt = test_examples(pkgname, i, debug=debug, disp=disp)
|
||||
plts[i] = plt
|
||||
@@ -337,6 +341,9 @@ function test_examples(pkgname::Symbol; debug = false, disp = true)
|
||||
# TODO: put error info into markdown?
|
||||
warn("Example $pkgname:$i:$(_examples[i].header) failed with: $ex")
|
||||
end
|
||||
if sleep != nothing
|
||||
Base.sleep(sleep)
|
||||
end
|
||||
end
|
||||
plts
|
||||
end
|
||||
|
||||
+99
-99
@@ -5,6 +5,8 @@
|
||||
const px = AbsoluteLength(0.254)
|
||||
const pct = Length{:pct, Float64}(1.0)
|
||||
|
||||
to_pixels(m::AbsoluteLength) = m.value / 0.254
|
||||
|
||||
const _cbar_width = 5mm
|
||||
|
||||
@compat Base.:.*(m::Measure, n::Number) = m * n
|
||||
@@ -70,6 +72,16 @@ function crop(parent::BoundingBox, child::BoundingBox)
|
||||
BoundingBox(l, t, w, h)
|
||||
end
|
||||
|
||||
# convert x,y coordinates from absolute coords to percentages...
|
||||
# returns x_pct, y_pct
|
||||
function xy_mm_to_pcts(x::AbsoluteLength, y::AbsoluteLength, figw, figh, flipy = true)
|
||||
xmm, ymm = x.value, y.value
|
||||
if flipy
|
||||
ymm = figh.value - ymm # flip y when origin in bottom-left
|
||||
end
|
||||
xmm / figw.value, ymm / figh.value
|
||||
end
|
||||
|
||||
# convert a bounding box from absolute coords to percentages...
|
||||
# returns an array of percentages of figure size: [left, bottom, width, height]
|
||||
function bbox_to_pcts(bb::BoundingBox, figw, figh, flipy = true)
|
||||
@@ -89,6 +101,21 @@ end
|
||||
|
||||
Base.show(io::IO, layout::AbstractLayout) = print(io, "$(typeof(layout))$(size(layout))")
|
||||
|
||||
# create a new bbox
|
||||
function bbox(x, y, w, h; h_anchor = :left, v_anchor = :top)
|
||||
left = if h_anchor == :left
|
||||
x
|
||||
else
|
||||
x - w * (h_anchor == :right ? 1.0 : 0.5)
|
||||
end
|
||||
top = if v_anchor == :top
|
||||
y
|
||||
else
|
||||
y - h * (v_anchor == :bottom ? 1.0 : 0.5)
|
||||
end
|
||||
BoundingBox(left, top, w, h)
|
||||
end
|
||||
|
||||
# this is the available area for drawing everything in this layout... as percentages of total canvas
|
||||
bbox(layout::AbstractLayout) = layout.bbox
|
||||
bbox!(layout::AbstractLayout, bb::BoundingBox) = (layout.bbox = bb)
|
||||
@@ -97,25 +124,23 @@ bbox!(layout::AbstractLayout, bb::BoundingBox) = (layout.bbox = bb)
|
||||
Base.parent(layout::AbstractLayout) = layout.parent
|
||||
parent_bbox(layout::AbstractLayout) = bbox(parent(layout))
|
||||
|
||||
# NOTE: these should be implemented for subplots in each backend!
|
||||
# they represent the minimum size of the axes and guides
|
||||
min_padding_left(layout::AbstractLayout) = 0mm
|
||||
min_padding_top(layout::AbstractLayout) = 0mm
|
||||
min_padding_right(layout::AbstractLayout) = 0mm
|
||||
min_padding_bottom(layout::AbstractLayout) = 0mm
|
||||
# padding_w(layout::AbstractLayout) = left_padding(layout) + right_padding(layout)
|
||||
# padding_h(layout::AbstractLayout) = bottom_padding(layout) + top_padding(layout)
|
||||
# padding(layout::AbstractLayout) = (padding_w(layout), padding_h(layout))
|
||||
|
||||
padding_w(layout::AbstractLayout) = left_padding(layout) + right_padding(layout)
|
||||
padding_h(layout::AbstractLayout) = bottom_padding(layout) + top_padding(layout)
|
||||
padding(layout::AbstractLayout) = (padding_w(layout), padding_h(layout))
|
||||
update_position!(layout::AbstractLayout) = nothing
|
||||
update_child_bboxes!(layout::AbstractLayout, minimum_perimeter = [0mm,0mm,0mm,0mm]) = nothing
|
||||
|
||||
_update_position!(layout::AbstractLayout) = nothing
|
||||
update_child_bboxes!(layout::AbstractLayout) = nothing
|
||||
left(layout::AbstractLayout) = left(bbox(layout))
|
||||
top(layout::AbstractLayout) = top(bbox(layout))
|
||||
right(layout::AbstractLayout) = right(bbox(layout))
|
||||
bottom(layout::AbstractLayout) = bottom(bbox(layout))
|
||||
width(layout::AbstractLayout) = width(bbox(layout))
|
||||
height(layout::AbstractLayout) = height(bbox(layout))
|
||||
|
||||
width(layout::AbstractLayout) = width(layout.bbox)
|
||||
height(layout::AbstractLayout) = height(layout.bbox)
|
||||
|
||||
plotarea(layout::AbstractLayout) = defaultbox
|
||||
plotarea!(layout::AbstractLayout, bbox::BoundingBox) = nothing
|
||||
# pass these through to the bbox methods if there's no plotarea
|
||||
plotarea(layout::AbstractLayout) = bbox(layout)
|
||||
plotarea!(layout::AbstractLayout, bb::BoundingBox) = bbox!(layout, bb)
|
||||
|
||||
attr(layout::AbstractLayout, k::Symbol) = layout.attr[k]
|
||||
attr(layout::AbstractLayout, k::Symbol, v) = get(layout.attr, k, v)
|
||||
@@ -204,6 +229,12 @@ rightpad(layout::GridLayout) = layout.minpad[3]
|
||||
bottompad(layout::GridLayout) = layout.minpad[4]
|
||||
|
||||
|
||||
# here's how this works... first we recursively "update the minimum padding" (which
|
||||
# means to calculate the minimum size needed from the edge of the subplot to plot area)
|
||||
# for the whole layout tree. then we can compute the "padding borders" of this
|
||||
# layout as the biggest padding of the children on the perimeter. then we need to
|
||||
# recursively pass those borders back down the tree, one side at a time, but ONLY
|
||||
# to those perimeter children.
|
||||
|
||||
# leftpad, toppad, rightpad, bottompad
|
||||
function _update_min_padding!(layout::GridLayout)
|
||||
@@ -217,10 +248,11 @@ function _update_min_padding!(layout::GridLayout)
|
||||
end
|
||||
|
||||
|
||||
function _update_position!(layout::GridLayout)
|
||||
map(_update_position!, layout.grid)
|
||||
function update_position!(layout::GridLayout)
|
||||
map(update_position!, layout.grid)
|
||||
end
|
||||
|
||||
# some lengths are fixed... we have to split up the free space among the list v
|
||||
function recompute_lengths(v)
|
||||
# dump(v)
|
||||
tot = 0pct
|
||||
@@ -242,11 +274,11 @@ function recompute_lengths(v)
|
||||
end
|
||||
|
||||
# recursively compute the bounding boxes for the layout and plotarea (relative to canvas!)
|
||||
function update_child_bboxes!(layout::GridLayout)
|
||||
function update_child_bboxes!(layout::GridLayout, minimum_perimeter = [0mm,0mm,0mm,0mm])
|
||||
nr, nc = size(layout)
|
||||
|
||||
# create a matrix for each minimum padding direction
|
||||
_update_min_padding!(layout)
|
||||
# # create a matrix for each minimum padding direction
|
||||
# _update_min_padding!(layout)
|
||||
|
||||
minpad_left = map(leftpad, layout.grid)
|
||||
minpad_top = map(toppad, layout.grid)
|
||||
@@ -263,6 +295,12 @@ function update_child_bboxes!(layout::GridLayout)
|
||||
pad_bottom = maximum(minpad_bottom, 2)
|
||||
# @show pad_left pad_top pad_right pad_bottom
|
||||
|
||||
# make sure the perimeter match the parent
|
||||
pad_left[1] = max(pad_left[1], minimum_perimeter[1])
|
||||
pad_top[1] = max(pad_top[1], minimum_perimeter[2])
|
||||
pad_right[end] = max(pad_right[end], minimum_perimeter[3])
|
||||
pad_bottom[end] = max(pad_bottom[end], minimum_perimeter[4])
|
||||
|
||||
# scale this up to the total padding in each direction
|
||||
total_pad_horizontal = sum(pad_left + pad_right)
|
||||
total_pad_vertical = sum(pad_top + pad_bottom)
|
||||
@@ -303,11 +341,36 @@ function update_child_bboxes!(layout::GridLayout)
|
||||
child_height = pad_top[r] + plotarea_height + pad_bottom[r]
|
||||
bbox!(child, BoundingBox(child_left, child_top, child_width, child_height))
|
||||
|
||||
# this is the minimum perimeter as decided by this child's parent, so that
|
||||
# all children on this border have the same value
|
||||
min_child_perimeter = [
|
||||
c == 1 ? layout.minpad[1] : 0mm,
|
||||
r == 1 ? layout.minpad[2] : 0mm,
|
||||
c == nc ? layout.minpad[3] : 0mm,
|
||||
r == nr ? layout.minpad[4] : 0mm
|
||||
]
|
||||
|
||||
# recursively update the child's children
|
||||
update_child_bboxes!(child)
|
||||
update_child_bboxes!(child, min_child_perimeter)
|
||||
end
|
||||
end
|
||||
|
||||
# for each inset (floating) subplot, resolve the relative position
|
||||
# to absolute canvas coordinates, relative to the parent's plotarea
|
||||
function update_inset_bboxes!(plt::Plot)
|
||||
for sp in plt.inset_subplots
|
||||
p_area = Measures.resolve(plotarea(sp.parent), sp[:relative_bbox])
|
||||
# @show bbox(sp.parent) sp[:relative_bbox] p_area
|
||||
plotarea!(sp, p_area)
|
||||
|
||||
bbox!(sp, bbox(
|
||||
left(p_area) - leftpad(sp),
|
||||
top(p_area) - toppad(sp),
|
||||
width(p_area) + leftpad(sp) + rightpad(sp),
|
||||
height(p_area) + toppad(sp) + bottompad(sp)
|
||||
))
|
||||
end
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
@@ -376,40 +439,21 @@ end
|
||||
|
||||
layout_args(huh) = error("unhandled layout type $(typeof(huh)): $huh")
|
||||
|
||||
# # pass the layout arg through
|
||||
# function build_layout(d::KW)
|
||||
# build_layout(get(d, :layout, default(:layout)))
|
||||
# end
|
||||
#
|
||||
# function build_layout(n::Integer)
|
||||
# nr, nc = compute_gridsize(n, -1, -1)
|
||||
# build_layout(GridLayout(nr, nc), n)
|
||||
# end
|
||||
#
|
||||
# function build_layout{I<:Integer}(sztup::NTuple{2,I})
|
||||
# nr, nc = sztup
|
||||
# build_layout(GridLayout(nr, nc))
|
||||
# end
|
||||
#
|
||||
# function build_layout{I<:Integer}(sztup::NTuple{3,I})
|
||||
# n, nr, nc = sztup
|
||||
# nr, nc = compute_gridsize(n, nr, nc)
|
||||
# build_layout(GridLayout(nr, nc), n)
|
||||
# end
|
||||
#
|
||||
# # compute number of subplots
|
||||
# function build_layout(layout::GridLayout)
|
||||
# # recursively get the size of the grid
|
||||
# n = calc_num_subplots(layout)
|
||||
# build_layout(layout, n)
|
||||
# end
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
|
||||
function build_layout(args...)
|
||||
layout, n = layout_args(args...)
|
||||
build_layout(layout, n)
|
||||
end
|
||||
|
||||
# n is the number of subplots
|
||||
# # just a single subplot
|
||||
# function build_layout(sp::Subplot, n::Integer)
|
||||
# sp, Subplot[sp], SubplotMap(gensym() => sp)
|
||||
# end
|
||||
|
||||
# n is the number of subplots... build a grid and initialize the inner subplots recursively
|
||||
function build_layout(layout::GridLayout, n::Integer)
|
||||
nr, nc = size(layout)
|
||||
subplots = Subplot[]
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -36,11 +36,12 @@ get_subplot_index(plt::Plot, sp::Subplot) = findfirst(_ -> _ === sp, plt.subplot
|
||||
series_list(sp::Subplot) = filter(series -> series.d[:subplot] === sp, sp.plt.series_list)
|
||||
|
||||
function should_add_to_legend(series::Series)
|
||||
!(series.d[:label] == "" || series.d[:seriestype] in (
|
||||
:hexbin,:histogram2d,:hline,:vline,
|
||||
:contour,:contour3d,:surface,:wireframe,
|
||||
:heatmap,:path3d,:scatter3d, :pie, :image
|
||||
))
|
||||
series.d[:primary] && series.d[:label] != "" &&
|
||||
!(series.d[:seriestype] in (
|
||||
:hexbin,:histogram2d,:hline,:vline,
|
||||
:contour,:contour3d,:surface,:wireframe,
|
||||
:heatmap, :pie, :image
|
||||
))
|
||||
end
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
+3
-1
@@ -73,12 +73,14 @@ type Plot{T<:AbstractBackend} <: AbstractPlot{T}
|
||||
subplots::Vector{Subplot}
|
||||
spmap::SubplotMap # provide any label as a map to a subplot
|
||||
layout::AbstractLayout
|
||||
inset_subplots::Vector{Subplot} # list of inset subplots
|
||||
init::Bool
|
||||
end
|
||||
|
||||
function Plot()
|
||||
Plot(backend(), 0, KW(), KW(), Series[], nothing,
|
||||
Subplot[], SubplotMap(), EmptyLayout(), false)
|
||||
Subplot[], SubplotMap(), EmptyLayout(),
|
||||
Subplot[], false)
|
||||
end
|
||||
|
||||
# TODO: make a decision... should plt[1] return the first subplot or the first series??
|
||||
|
||||
+105
-7
@@ -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
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user