Merge branch 'master' into master

This commit is contained in:
Jack Devine 2017-12-04 22:42:26 +13:00 committed by GitHub
commit f0e4f4dc9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 1089 additions and 586 deletions

View File

@ -11,6 +11,11 @@
--- ---
## (current master) ## (current master)
## 0.13.1
- fix a bug when passing a vector of functions with no bounds (e.g. `plot([sin, cos])`)
- export `pct` and `px` from Plots.PlotMeasures
## 0.13.0 ## 0.13.0
- support `plotattributes` rather than `d` in recipes - support `plotattributes` rather than `d` in recipes
@ -100,7 +105,7 @@
#### 0.11.0 #### 0.11.0
- julia 0.6 compatibility - julia 0.6 compatibility
- matplotlib 0.2.0 compatibility - matplotlib 2.0 compatibility
- add inspectdr backend - add inspectdr backend
- improved histogram functionality: - improved histogram functionality:
- added a `:stephist` and `:scatterhist` series type as well as ``:barhist` (the default) - added a `:stephist` and `:scatterhist` series type as well as ``:barhist` (the default)

View File

@ -1,7 +1,7 @@
# Plots # Plots
[![Build Status](https://travis-ci.org/JuliaPlots/Plots.jl.svg?branch=master)](https://travis-ci.org/JuliaPlots/Plots.jl) [![Build Status](https://travis-ci.org/JuliaPlots/Plots.jl.svg?branch=master)](https://travis-ci.org/JuliaPlots/Plots.jl)
[![Build status](https://ci.appveyor.com/api/projects/status/github/tbreloff/plots.jl?branch=master&svg=true)](https://ci.appveyor.com/project/tbreloff/plots-jl) [![Build status](https://ci.appveyor.com/api/projects/status/github/juliaplots/plots.jl?branch=master&svg=true)](https://ci.appveyor.com/project/mkborregaard/plots-jl)
[![Join the chat at https://gitter.im/tbreloff/Plots.jl](https://badges.gitter.im/tbreloff/Plots.jl.svg)](https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/tbreloff/Plots.jl](https://badges.gitter.im/tbreloff/Plots.jl.svg)](https://gitter.im/tbreloff/Plots.jl?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.3.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.3) --> <!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.3.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.3) -->
<!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.4.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.4) --> <!-- [![Plots](http://pkg.julialang.org/badges/Plots_0.4.svg)](http://pkg.julialang.org/?pkg=Plots&ver=0.4) -->
@ -20,4 +20,4 @@ Plots is a plotting API and toolset. My goals with the package are:
- **Lightweight**. Very few dependencies. - **Lightweight**. Very few dependencies.
- **Smart**. Attempts to figure out what you **want** it to do... not just what you **tell** it. - **Smart**. Attempts to figure out what you **want** it to do... not just what you **tell** it.
View the [full documentation](http://juliaplots.github.io). View the [full documentation](http://docs.juliaplots.org/latest).

View File

@ -15,6 +15,8 @@ using Base.Meta
import Showoff import Showoff
import StatsBase import StatsBase
using Requires
export export
grid, grid,
bbox, bbox,
@ -110,13 +112,13 @@ export
# --------------------------------------------------------- # ---------------------------------------------------------
import NaNMath # define functions that ignores NaNs. To overcome the destructive effects of https://github.com/JuliaLang/julia/pull/12563 import NaNMath # define functions that ignores NaNs. To overcome the destructive effects of https://github.com/JuliaLang/julia/pull/12563
ignorenan_minimum{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.minimum(x) ignorenan_minimum(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.minimum(x)
ignorenan_minimum(x) = Base.minimum(x) ignorenan_minimum(x) = Base.minimum(x)
ignorenan_maximum{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.maximum(x) ignorenan_maximum(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.maximum(x)
ignorenan_maximum(x) = Base.maximum(x) ignorenan_maximum(x) = Base.maximum(x)
ignorenan_mean{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.mean(x) ignorenan_mean(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.mean(x)
ignorenan_mean(x) = Base.mean(x) ignorenan_mean(x) = Base.mean(x)
ignorenan_extrema{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.extrema(x) ignorenan_extrema(x::AbstractArray{F}) where {F<:AbstractFloat} = NaNMath.extrema(x)
ignorenan_extrema(x) = Base.extrema(x) ignorenan_extrema(x) = Base.extrema(x)
# --------------------------------------------------------- # ---------------------------------------------------------
@ -138,12 +140,15 @@ module PlotMeasures
import Measures import Measures
import Measures: Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height, w, h import Measures: Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height, w, h
const BBox = Measures.Absolute2DBox const BBox = Measures.Absolute2DBox
export BBox, BoundingBox, mm, cm, inch, pt, px, pct, w, h
# allow pixels and percentages
const px = AbsoluteLength(0.254)
const pct = Length{:pct, Float64}(1.0)
export BBox, BoundingBox, mm, cm, inch, px, pct, pt, w, h
end end
using .PlotMeasures using .PlotMeasures
import .PlotMeasures: Length, AbsoluteLength, Measure, width, height import .PlotMeasures: Length, AbsoluteLength, Measure, width, height
export BBox, BoundingBox
# --------------------------------------------------------- # ---------------------------------------------------------
include("types.jl") include("types.jl")
@ -212,13 +217,13 @@ xlabel!(s::AbstractString; kw...) = plot!(; xlabel = s, kw...)
ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...) ylabel!(s::AbstractString; kw...) = plot!(; ylabel = s, kw...)
"Set xlims for an existing plot" "Set xlims for an existing plot"
xlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; xlims = lims, kw...) xlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; xlims = lims, kw...)
"Set ylims for an existing plot" "Set ylims for an existing plot"
ylims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; ylims = lims, kw...) ylims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; ylims = lims, kw...)
"Set zlims for an existing plot" "Set zlims for an existing plot"
zlims!{T<:Real,S<:Real}(lims::Tuple{T,S}; kw...) = plot!(; zlims = lims, kw...) zlims!(lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(; zlims = lims, kw...)
xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...) xlims!(xmin::Real, xmax::Real; kw...) = plot!(; xlims = (xmin,xmax), kw...)
ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...) ylims!(ymin::Real, ymax::Real; kw...) = plot!(; ylims = (ymin,ymax), kw...)
@ -226,19 +231,19 @@ zlims!(zmin::Real, zmax::Real; kw...) = plot!(; zlims = (zmi
"Set xticks for an existing plot" "Set xticks for an existing plot"
xticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; xticks = v, kw...) xticks!(v::AVec{T}; kw...) where {T<:Real} = plot!(; xticks = v, kw...)
"Set yticks for an existing plot" "Set yticks for an existing plot"
yticks!{T<:Real}(v::AVec{T}; kw...) = plot!(; yticks = v, kw...) yticks!(v::AVec{T}; kw...) where {T<:Real} = plot!(; yticks = v, kw...)
xticks!{T<:Real,S<:AbstractString}( xticks!(
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; xticks = (ticks,labels), kw...) ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; xticks = (ticks,labels), kw...)
yticks!{T<:Real,S<:AbstractString}( yticks!(
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(; yticks = (ticks,labels), kw...) ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(; yticks = (ticks,labels), kw...)
"Add annotations to an existing plot" "Add annotations to an existing plot"
annotate!(anns...; kw...) = plot!(; annotation = anns, kw...) annotate!(anns...; kw...) = plot!(; annotation = anns, kw...)
annotate!{T<:Tuple}(anns::AVec{T}; kw...) = plot!(; annotation = anns, kw...) annotate!(anns::AVec{T}; kw...) where {T<:Tuple} = plot!(; annotation = anns, kw...)
"Flip the current plots' x axis" "Flip the current plots' x axis"
xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...) xflip!(flip::Bool = true; kw...) = plot!(; xflip = flip, kw...)
@ -258,22 +263,22 @@ let PlotOrSubplot = Union{Plot, Subplot}
title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...) title!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; title = s, kw...)
xlabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...) xlabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; xlabel = s, kw...)
ylabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...) ylabel!(plt::PlotOrSubplot, s::AbstractString; kw...) = plot!(plt; ylabel = s, kw...)
xlims!{T<:Real,S<:Real}(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) = plot!(plt; xlims = lims, kw...) xlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; xlims = lims, kw...)
ylims!{T<:Real,S<:Real}(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) = plot!(plt; ylims = lims, kw...) ylims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; ylims = lims, kw...)
zlims!{T<:Real,S<:Real}(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) = plot!(plt; zlims = lims, kw...) zlims!(plt::PlotOrSubplot, lims::Tuple{T,S}; kw...) where {T<:Real,S<:Real} = plot!(plt; zlims = lims, kw...)
xlims!(plt::PlotOrSubplot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...) xlims!(plt::PlotOrSubplot, xmin::Real, xmax::Real; kw...) = plot!(plt; xlims = (xmin,xmax), kw...)
ylims!(plt::PlotOrSubplot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...) ylims!(plt::PlotOrSubplot, ymin::Real, ymax::Real; kw...) = plot!(plt; ylims = (ymin,ymax), kw...)
zlims!(plt::PlotOrSubplot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...) zlims!(plt::PlotOrSubplot, zmin::Real, zmax::Real; kw...) = plot!(plt; zlims = (zmin,zmax), kw...)
xticks!{T<:Real}(plt::PlotOrSubplot, ticks::AVec{T}; kw...) = plot!(plt; xticks = ticks, kw...) xticks!(plt::PlotOrSubplot, ticks::AVec{T}; kw...) where {T<:Real} = plot!(plt; xticks = ticks, kw...)
yticks!{T<:Real}(plt::PlotOrSubplot, ticks::AVec{T}; kw...) = plot!(plt; yticks = ticks, kw...) yticks!(plt::PlotOrSubplot, ticks::AVec{T}; kw...) where {T<:Real} = plot!(plt; yticks = ticks, kw...)
xticks!{T<:Real,S<:AbstractString}(plt::PlotOrSubplot, xticks!(plt::PlotOrSubplot,
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; xticks = (ticks,labels), kw...) ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; xticks = (ticks,labels), kw...)
yticks!{T<:Real,S<:AbstractString}(plt::PlotOrSubplot, yticks!(plt::PlotOrSubplot,
ticks::AVec{T}, labels::AVec{S}; kw...) = plot!(plt; yticks = (ticks,labels), kw...) ticks::AVec{T}, labels::AVec{S}; kw...) where {T<:Real,S<:AbstractString} = plot!(plt; yticks = (ticks,labels), kw...)
xgrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xgrid = args, kw...) xgrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xgrid = args, kw...)
ygrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; ygrid = args, kw...) ygrid!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; ygrid = args, kw...)
annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...) annotate!(plt::PlotOrSubplot, anns...; kw...) = plot!(plt; annotation = anns, kw...)
annotate!{T<:Tuple}(plt::PlotOrSubplot, anns::AVec{T}; kw...) = plot!(plt; annotation = anns, kw...) annotate!(plt::PlotOrSubplot, anns::AVec{T}; kw...) where {T<:Tuple} = plot!(plt; annotation = anns, kw...)
xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...) xflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; xflip = flip, kw...)
yflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; yflip = flip, kw...) yflip!(plt::PlotOrSubplot, flip::Bool = true; kw...) = plot!(plt; yflip = flip, kw...)
xaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xaxis = args, kw...) xaxis!(plt::PlotOrSubplot, args...; kw...) = plot!(plt; xaxis = args, kw...)

View File

@ -1,5 +1,5 @@
"Represents an animation object" "Represents an animation object"
immutable Animation struct Animation
dir::String dir::String
frames::Vector{String} frames::Vector{String}
end end
@ -14,7 +14,7 @@ end
Add a plot (the current plot if not specified) to an existing animation Add a plot (the current plot if not specified) to an existing animation
""" """
function frame{P<:AbstractPlot}(anim::Animation, plt::P=current()) function frame(anim::Animation, plt::P=current()) where P<:AbstractPlot
i = length(anim.frames) + 1 i = length(anim.frames) + 1
filename = @sprintf("%06d.png", i) filename = @sprintf("%06d.png", i)
png(plt, joinpath(anim.dir, filename)) png(plt, joinpath(anim.dir, filename))
@ -25,7 +25,7 @@ giffn() = (isijulia() ? "tmp.gif" : tempname()*".gif")
movfn() = (isijulia() ? "tmp.mov" : tempname()*".mov") movfn() = (isijulia() ? "tmp.mov" : tempname()*".mov")
mp4fn() = (isijulia() ? "tmp.mp4" : tempname()*".mp4") mp4fn() = (isijulia() ? "tmp.mp4" : tempname()*".mp4")
type FrameIterator mutable struct FrameIterator
itr itr
every::Int every::Int
kw kw
@ -54,44 +54,36 @@ end
# ----------------------------------------------- # -----------------------------------------------
"Wraps the location of an animated gif so that it can be displayed" "Wraps the location of an animated gif so that it can be displayed"
immutable AnimatedGif struct AnimatedGif
filename::String filename::String
end end
file_extension(fn) = Base.Filesystem.splitext(fn)[2][2:end] file_extension(fn) = Base.Filesystem.splitext(fn)[2][2:end]
gif(anim::Animation, fn = giffn(); kw...) = buildanimation(anim.dir, fn; kw...) gif(anim::Animation, fn = giffn(); kw...) = buildanimation(anim.dir, fn; kw...)
mov(anim::Animation, fn = movfn(); kw...) = buildanimation(anim.dir, fn; kw...) mov(anim::Animation, fn = movfn(); kw...) = buildanimation(anim.dir, fn, false; kw...)
mp4(anim::Animation, fn = mp4fn(); kw...) = buildanimation(anim.dir, fn; kw...) mp4(anim::Animation, fn = mp4fn(); kw...) = buildanimation(anim.dir, fn, false; kw...)
const _imagemagick_initialized = Ref(false)
function buildanimation(animdir::AbstractString, fn::AbstractString; function buildanimation(animdir::AbstractString, fn::AbstractString,
fps::Integer = 20, loop::Integer = 0) is_animated_gif::Bool=true;
fps::Integer = 20, loop::Integer = 0,
variable_palette::Bool=false)
fn = abspath(fn) fn = abspath(fn)
try
if !_imagemagick_initialized[] if is_animated_gif
file = joinpath(Pkg.dir("ImageMagick"), "deps","deps.jl") if variable_palette
if isfile(file) && !haskey(ENV, "MAGICK_CONFIGURE_PATH") # generate a colorpalette for each frame for highest quality, but larger filesize
include(file) palette="palettegen=stats_mode=single[pal],[0:v][pal]paletteuse=new=1"
end run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -lavfi "$palette" -y $fn`)
_imagemagick_initialized[] = true else
# generate a colorpalette first so ffmpeg does not have to guess it
run(`ffmpeg -v 0 -i $(animdir)/%06d.png -vf "palettegen=stats_mode=diff" -y "$(animdir)/palette.bmp"`)
# then apply the palette to get better results
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -i "$(animdir)/palette.bmp" -lavfi "paletteuse=dither=sierra2_4a" -y $fn`)
end end
else
# prefix = get(ENV, "MAGICK_CONFIGURE_PATH", "") run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -pix_fmt yuv420p -y $fn`)
# high quality
speed = round(Int, 100 / fps)
run(`convert -delay $speed -loop $loop $(joinpath(animdir, "*.png")) -alpha off $fn`)
catch err
warn("""Tried to create gif using convert (ImageMagick), but got error: $err
ImageMagick can be installed by executing `Pkg.add("ImageMagick")`.
You may also need to install the imagemagick c++ library through your operating system.
Will try ffmpeg, but it's lower quality...)""")
# low quality
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -y $fn`)
# run(`ffmpeg -v warning -i "fps=$fps,scale=320:-1:flags=lanczos"`)
end end
info("Saved animation to ", fn) info("Saved animation to ", fn)

View File

@ -66,11 +66,17 @@ const _arg_desc = KW(
:dpi => "Number. Dots Per Inch of output figures", :dpi => "Number. Dots Per Inch of output figures",
:display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.", :display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.",
:extra_kwargs => "KW (Dict{Symbol,Any}). Pass a map of extra keyword args which may be specific to a backend.", :extra_kwargs => "KW (Dict{Symbol,Any}). Pass a map of extra keyword args which may be specific to a backend.",
:fontfamily => "String or Symbol. Default font family for title, legend entries, tick labels and guides",
# subplot args # subplot args
:title => "String. Subplot title.", :title => "String. Subplot title.",
:title_location => "Symbol. Position of subplot title. Values: `:left`, `:center`, `:right`", :title_location => "Symbol. Position of subplot title. Values: `:left`, `:center`, `:right`",
:titlefont => "Font. Font of subplot title.", :titlefontfamily => "String or Symbol. Font family of subplot title.",
:titlefontsize => "Integer. Font pointsize of subplot title.",
:titlefonthalign => "Symbol. Font horizontal alignment of subplot title: :hcenter, :left, :right or :center",
:titlefontvalign => "Symbol. Font vertical alignment of subplot title: :vcenter, :top, :bottom or :center",
:titlefontrotation => "Real. Font rotation of subplot title",
:titlefontcolor => "Color Type. Font color of subplot title",
:background_color_subplot => "Color Type or `:match` (matches `:background_color`). Base background color of the subplot.", :background_color_subplot => "Color Type or `:match` (matches `:background_color`). Base background color of the subplot.",
:background_color_legend => "Color Type or `:match` (matches `:background_color_subplot`). Background color of the legend.", :background_color_legend => "Color Type or `:match` (matches `:background_color_subplot`). Background color of the legend.",
:background_color_inside => "Color Type or `:match` (matches `:background_color_subplot`). Background color inside the plot area (under the grid).", :background_color_inside => "Color Type or `:match` (matches `:background_color_subplot`). Background color inside the plot area (under the grid).",
@ -79,7 +85,12 @@ const _arg_desc = KW(
:foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.", :foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.",
: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.", :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)", :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)",
:legendtitle => "String or nothing (default). Sets the legend title.", :legendfontfamily => "String or Symbol. Font family of legend entries.",
:legendfontsize => "Integer. Font pointsize of legend entries.",
:legendfonthalign => "Symbol. Font horizontal alignment of legend entries: :hcenter, :left, :right or :center",
:legendfontvalign => "Symbol. Font vertical alignment of legend entries: :vcenter, :top, :bottom or :center",
:legendfontrotation => "Real. Font rotation of legend entries",
:legendfontcolor => "Color Type. Font color of legend entries",
: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)", :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.", :clims => "`:auto` or NTuple{2,Number}. Fixes the limits of the colorbar.",
:legendfont => "Font. Font of legend items.", :legendfont => "Font. Font of legend items.",
@ -94,6 +105,7 @@ const _arg_desc = KW(
:subplot_index => "Integer. Internal (not set by user). Specifies the index of this subplot in the Plot's `plt.subplot` list.", :subplot_index => "Integer. Internal (not set by user). Specifies the index of this subplot in the Plot's `plt.subplot` list.",
:colorbar_title => "String. Title of colorbar.", :colorbar_title => "String. Title of colorbar.",
:framestyle => "Symbol. Style of the axes frame. Choose from $(_allFramestyles)", :framestyle => "Symbol. Style of the axes frame. Choose from $(_allFramestyles)",
:camera => "NTuple{2, Real}. Sets the view angle (azimuthal, elevation) for 3D plots",
# axis args # axis args
:guide => "String. Axis guide (label).", :guide => "String. Axis guide (label).",
@ -103,17 +115,28 @@ const _arg_desc = KW(
:rotation => "Number. Degrees rotation of tick labels.", :rotation => "Number. Degrees rotation of tick labels.",
:flip => "Bool. Should we flip (reverse) the axis?", :flip => "Bool. Should we flip (reverse) the axis?",
:formatter => "Function, :scientific, or :auto. A method which converts a number to a string for tick labeling.", :formatter => "Function, :scientific, or :auto. A method which converts a number to a string for tick labeling.",
:tickfont => "Font. Font of axis tick labels.", :tickfontfamily => "String or Symbol. Font family of tick labels.",
:guidefont => "Font. Font of axis guide (label).", :tickfontsize => "Integer. Font pointsize of tick labels.",
:tickfonthalign => "Symbol. Font horizontal alignment of tick labels: :hcenter, :left, :right or :center",
:tickfontvalign => "Symbol. Font vertical alignment of tick labels: :vcenter, :top, :bottom or :center",
:tickfontrotation => "Real. Font rotation of tick labels",
:tickfontcolor => "Color Type. Font color of tick labels",
:guidefontfamily => "String or Symbol. Font family of axes guides.",
:guidefontsize => "Integer. Font pointsize of axes guides.",
:guidefonthalign => "Symbol. Font horizontal alignment of axes guides: :hcenter, :left, :right or :center",
:guidefontvalign => "Symbol. Font vertical alignment of axes guides: :vcenter, :top, :bottom or :center",
:guidefontrotation => "Real. Font rotation of axes guides",
:guidefontcolor => "Color Type. Font color of axes guides",
:foreground_color_axis => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis ticks.", :foreground_color_axis => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis ticks.",
:foreground_color_border => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of plot area border (spines).", :foreground_color_border => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of plot area border (spines).",
:foreground_color_text => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of tick labels.", :foreground_color_text => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of tick labels.",
:foreground_color_guide => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis guides (axis labels).", :foreground_color_guide => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis guides (axis labels).",
:mirror => "Bool. Switch the side of the tick labels (right or top).", :mirror => "Bool. Switch the side of the tick labels (right or top).",
:grid => "Bool, Symbol, String or `nothing`. Show the grid lines? `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:none`, `:off`", :grid => "Bool, Symbol, String or `nothing`. Show the grid lines? `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:none`, `:off`",
:foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.", :foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.",
:gridalpha => "Number in [0,1]. The alpha/opacity override for the grid lines.", :gridalpha => "Number in [0,1]. The alpha/opacity override for the grid lines.",
:gridstyle => "Symbol. Style of the grid lines. Choose from $(_allStyles)", :gridstyle => "Symbol. Style of the grid lines. Choose from $(_allStyles)",
:gridlinewidth => "Number. Width of the grid lines (in pixels)", :gridlinewidth => "Number. Width of the grid lines (in pixels)",
:tick_direction => "Symbol. Direction of the ticks. `:in` or `:out`" :tick_direction => "Symbol. Direction of the ticks. `:in` or `:out`",
:showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`"
) )

View File

@ -170,8 +170,8 @@ const _scaleAliases = Dict{Symbol,Symbol}(
const _allGridSyms = [:x, :y, :z, const _allGridSyms = [:x, :y, :z,
:xy, :xz, :yx, :yz, :zx, :zy, :xy, :xz, :yx, :yz, :zx, :zy,
:xyz, :xzy, :yxz, :yzx, :zxy, :zyx, :xyz, :xzy, :yxz, :yzx, :zxy, :zyx,
:all, :both, :on, :all, :both, :on, :yes, :show,
:none, :off,] :none, :off, :no, :hide]
const _allGridArgs = [_allGridSyms; string.(_allGridSyms); nothing] const _allGridArgs = [_allGridSyms; string.(_allGridSyms); nothing]
hasgrid(arg::Void, letter) = false hasgrid(arg::Void, letter) = false
hasgrid(arg::Bool, letter) = arg hasgrid(arg::Bool, letter) = arg
@ -185,6 +185,24 @@ function hasgrid(arg::Symbol, letter)
end end
hasgrid(arg::AbstractString, letter) = hasgrid(Symbol(arg), letter) hasgrid(arg::AbstractString, letter) = hasgrid(Symbol(arg), letter)
const _allShowaxisSyms = [:x, :y, :z,
:xy, :xz, :yx, :yz, :zx, :zy,
:xyz, :xzy, :yxz, :yzx, :zxy, :zyx,
:all, :both, :on, :yes, :show,
:off, :no, :hide]
const _allShowaxisArgs = [_allGridSyms; string.(_allGridSyms)]
showaxis(arg::Void, letter) = false
showaxis(arg::Bool, letter) = arg
function showaxis(arg::Symbol, letter)
if arg in _allGridSyms
arg in (:all, :both, :on, :yes) || contains(string(arg), string(letter))
else
warn("Unknown showaxis argument $arg; $(Symbol(letter, :showaxis)) was set to `true` instead.")
true
end
end
showaxis(arg::AbstractString, letter) = hasgrid(Symbol(arg), letter)
const _allFramestyles = [:box, :semi, :axes, :origin, :zerolines, :grid, :none] const _allFramestyles = [:box, :semi, :axes, :origin, :zerolines, :grid, :none]
const _framestyleAliases = Dict{Symbol, Symbol}( const _framestyleAliases = Dict{Symbol, Symbol}(
:frame => :box, :frame => :box,
@ -255,6 +273,7 @@ const _plot_defaults = KW(
:background_color => colorant"white", # default for all backgrounds, :background_color => colorant"white", # default for all backgrounds,
:background_color_outside => :match, # background outside grid, :background_color_outside => :match, # background outside grid,
:foreground_color => :auto, # default for all foregrounds, and title color, :foreground_color => :auto, # default for all foregrounds, and title color,
:fontfamily => "sans-serif",
:size => (600,400), :size => (600,400),
:pos => (0,0), :pos => (0,0),
:window_title => "Plots.jl", :window_title => "Plots.jl",
@ -274,7 +293,13 @@ const _plot_defaults = KW(
const _subplot_defaults = KW( const _subplot_defaults = KW(
:title => "", :title => "",
:title_location => :center, # also :left or :right :title_location => :center, # also :left or :right
:titlefont => font(14), :fontfamily_subplot => :match,
:titlefontfamily => :match,
:titlefontsize => 14,
:titlefonthalign => :hcenter,
:titlefontvalign => :vcenter,
:titlefontrotation => 0.0,
:titlefontcolor => :match,
:background_color_subplot => :match, # default for other bg colors... match takes plot default :background_color_subplot => :match, # default for other bg colors... match takes plot default
:background_color_legend => :match, # background of legend :background_color_legend => :match, # background of legend
:background_color_inside => :match, # background inside grid :background_color_inside => :match, # background inside grid
@ -286,7 +311,12 @@ const _subplot_defaults = KW(
:legendtitle => nothing, :legendtitle => nothing,
:colorbar => :legend, :colorbar => :legend,
:clims => :auto, :clims => :auto,
:legendfont => font(8), :legendfontfamily => :match,
:legendfontsize => 8,
:legendfonthalign => :hcenter,
:legendfontvalign => :vcenter,
:legendfontrotation => 0.0,
:legendfontcolor => :match,
:annotations => [], # annotation tuples... list of (x,y,annotation) :annotations => [], # annotation tuples... list of (x,y,annotation)
:projection => :none, # can also be :polar or :3d :projection => :none, # can also be :polar or :3d
:aspect_ratio => :none, # choose from :none or :equal :aspect_ratio => :none, # choose from :none or :equal
@ -298,6 +328,7 @@ const _subplot_defaults = KW(
:subplot_index => -1, :subplot_index => -1,
:colorbar_title => "", :colorbar_title => "",
:framestyle => :axes, :framestyle => :axes,
:camera => (30,30),
) )
const _axis_defaults = KW( const _axis_defaults = KW(
@ -308,8 +339,18 @@ const _axis_defaults = KW(
:rotation => 0, :rotation => 0,
:flip => false, :flip => false,
:link => [], :link => [],
:tickfont => font(8), :tickfontfamily => :match,
:guidefont => font(11), :tickfontsize => 8,
:tickfonthalign => :hcenter,
:tickfontvalign => :vcenter,
:tickfontrotation => 0.0,
:tickfontcolor => :match,
:guidefontfamily => :match,
:guidefontsize => 11,
:guidefonthalign => :hcenter,
:guidefontvalign => :vcenter,
:guidefontrotation => 0.0,
:guidefontcolor => :match,
:foreground_color_axis => :match, # axis border/tick colors, :foreground_color_axis => :match, # axis border/tick colors,
:foreground_color_border => :match, # plot area border/spines, :foreground_color_border => :match, # plot area border/spines,
:foreground_color_text => :match, # tick text color, :foreground_color_text => :match, # tick text color,
@ -322,7 +363,8 @@ const _axis_defaults = KW(
:gridalpha => 0.1, :gridalpha => 0.1,
:gridstyle => :solid, :gridstyle => :solid,
:gridlinewidth => 0.5, :gridlinewidth => 0.5,
:tick_direction => :in, :tick_direction => :in,
:showaxis => true,
) )
const _suppress_warnings = Set{Symbol}([ const _suppress_warnings = Set{Symbol}([
@ -374,11 +416,13 @@ const _all_defaults = KW[
_axis_defaults_byletter _axis_defaults_byletter
] ]
const _initial_defaults = deepcopy(_all_defaults)
# to be able to reset font sizes to initial values # to be able to reset font sizes to initial values
const _initial_fontsizes = Dict(:titlefont => _subplot_defaults[:titlefont].pointsize, const _initial_fontsizes = Dict(:titlefont => _subplot_defaults[:titlefontsize],
:legendfont => _subplot_defaults[:legendfont].pointsize, :legendfont => _subplot_defaults[:legendfontsize],
:tickfont => _axis_defaults[:tickfont].pointsize, :tickfont => _axis_defaults[:tickfontsize],
:guidefont => _axis_defaults[:guidefont].pointsize) :guidefont => _axis_defaults[:guidefontsize])
const _all_args = sort(collect(union(map(keys, _all_defaults)...))) const _all_args = sort(collect(union(map(keys, _all_defaults)...)))
@ -513,6 +557,7 @@ add_aliases(:gridlinewidth, :gridwidth, :grid_linewidth, :grid_width, :gridlw, :
add_aliases(:gridstyle, :grid_style, :gridlinestyle, :grid_linestyle, :grid_ls, :gridls) add_aliases(:gridstyle, :grid_style, :gridlinestyle, :grid_linestyle, :grid_ls, :gridls)
add_aliases(:framestyle, :frame_style, :frame, :axesstyle, :axes_style, :boxstyle, :box_style, :box, :borderstyle, :border_style, :border) add_aliases(:framestyle, :frame_style, :frame, :axesstyle, :axes_style, :boxstyle, :box_style, :box, :borderstyle, :border_style, :border)
add_aliases(:tick_direction, :tickdirection, :tick_dir, :tickdir, :tick_orientation, :tickorientation, :tick_or, :tickor) add_aliases(:tick_direction, :tickdirection, :tick_dir, :tickdir, :tick_orientation, :tickorientation, :tick_or, :tickor)
add_aliases(:camera, :cam, :viewangle, :view_angle)
# add all pluralized forms to the _keyAliases dict # add all pluralized forms to the _keyAliases dict
for arg in keys(_series_defaults) for arg in keys(_series_defaults)
@ -569,6 +614,7 @@ function default(d::KW, k::Symbol)
get(d, k, default(k)) get(d, k, default(k))
end end
reset_defaults() = foreach(merge!, _all_defaults, _initial_defaults)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -671,6 +717,9 @@ function processFillArg(d::KW, arg)
arg.color == nothing || (d[:fillcolor] = arg.color == :auto ? :auto : plot_color(arg.color)) arg.color == nothing || (d[:fillcolor] = arg.color == :auto ? :auto : plot_color(arg.color))
arg.alpha == nothing || (d[:fillalpha] = arg.alpha) arg.alpha == nothing || (d[:fillalpha] = arg.alpha)
elseif typeof(arg) <: Bool
d[:fillrange] = arg ? 0 : nothing
# fillrange function # fillrange function
elseif allFunctions(arg) elseif allFunctions(arg)
d[:fillrange] = arg d[:fillrange] = arg
@ -710,12 +759,44 @@ function processGridArg!(d::KW, arg, letter)
d[Symbol(letter, :gridlinewidth)] = arg d[Symbol(letter, :gridlinewidth)] = arg
# color # color
elseif !handleColors!(d, arg, Symbol(letter, :foreground_color_grid)) elseif !handleColors!(d, arg, Symbol(letter, :foreground_color_grid))
warn("Skipped grid arg $arg.") warn("Skipped grid arg $arg.")
end end
end end
function processFontArg!(d::KW, fontname::Symbol, arg)
T = typeof(arg)
if T <: Font
d[Symbol(fontname, :family)] = arg.family
d[Symbol(fontname, :size)] = arg.pointsize
d[Symbol(fontname, :halign)] = arg.halign
d[Symbol(fontname, :valign)] = arg.valign
d[Symbol(fontname, :rotation)] = arg.rotation
d[Symbol(fontname, :color)] = arg.color
elseif arg == :center
d[Symbol(fontname, :halign)] = :hcenter
d[Symbol(fontname, :valign)] = :vcenter
elseif arg in (:hcenter, :left, :right)
d[Symbol(fontname, :halign)] = arg
elseif arg in (:vcenter, :top, :bottom)
d[Symbol(fontname, :valign)] = arg
elseif T <: Colorant
d[Symbol(fontname, :color)] = arg
elseif T <: Symbol || T <: AbstractString
try
d[Symbol(fontname, :color)] = parse(Colorant, string(arg))
catch
d[Symbol(fontname, :family)] = string(arg)
end
elseif typeof(arg) <: Integer
d[Symbol(fontname, :size)] = arg
elseif typeof(arg) <: Real
d[Symbol(fontname, :rotation)] = convert(Float64, arg)
else
warn("Skipped font arg: $arg ($(typeof(arg)))")
end
end
_replace_markershape(shape::Symbol) = get(_markerAliases, shape, shape) _replace_markershape(shape::Symbol) = get(_markerAliases, shape, shape)
_replace_markershape(shapes::AVec) = map(_replace_markershape, shapes) _replace_markershape(shapes::AVec) = map(_replace_markershape, shapes)
@ -735,13 +816,13 @@ function preprocessArgs!(d::KW)
replaceAliases!(d, _keyAliases) replaceAliases!(d, _keyAliases)
# clear all axis stuff # clear all axis stuff
if haskey(d, :axis) && d[:axis] in (:none, nothing, false) # if haskey(d, :axis) && d[:axis] in (:none, nothing, false)
d[:ticks] = nothing # d[:ticks] = nothing
d[:foreground_color_border] = RGBA(0,0,0,0) # d[:foreground_color_border] = RGBA(0,0,0,0)
d[:foreground_color_axis] = RGBA(0,0,0,0) # d[:foreground_color_axis] = RGBA(0,0,0,0)
d[:grid] = false # d[:grid] = false
delete!(d, :axis) # delete!(d, :axis)
end # end
# for letter in (:x, :y, :z) # for letter in (:x, :y, :z)
# asym = Symbol(letter, :axis) # asym = Symbol(letter, :axis)
# if haskey(d, asym) || d[asym] in (:none, nothing, false) # if haskey(d, asym) || d[asym] in (:none, nothing, false)
@ -750,6 +831,13 @@ function preprocessArgs!(d::KW)
# end # end
# end # end
# handle axis args common to all axis
args = pop!(d, :axis, ())
for arg in wraptuple(args)
for letter in (:x, :y, :z)
process_axis_arg!(d, arg, letter)
end
end
# handle axis args # handle axis args
for letter in (:x, :y, :z) for letter in (:x, :y, :z)
asym = Symbol(letter, :axis) asym = Symbol(letter, :axis)
@ -777,6 +865,32 @@ function preprocessArgs!(d::KW)
end end
end end
# fonts
for fontname in (:titlefont, :legendfont)
args = pop!(d, fontname, ())
for arg in wraptuple(args)
processFontArg!(d, fontname, arg)
end
end
# handle font args common to all axes
for fontname in (:tickfont, :guidefont)
args = pop!(d, fontname, ())
for arg in wraptuple(args)
for letter in (:x, :y, :z)
processFontArg!(d, Symbol(letter, fontname), arg)
end
end
end
# handle individual axes font args
for letter in (:x, :y, :z)
for fontname in (:tickfont, :guidefont)
args = pop!(d, Symbol(letter, fontname), ())
for arg in wraptuple(args)
processFontArg!(d, Symbol(letter, fontname), arg)
end
end
end
# handle line args # handle line args
for arg in wraptuple(pop!(d, :line, ())) for arg in wraptuple(pop!(d, :line, ()))
processLineArg(d, arg) processLineArg(d, arg)
@ -858,7 +972,7 @@ end
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
"A special type that will break up incoming data into groups, and allow for easier creation of grouped plots" "A special type that will break up incoming data into groups, and allow for easier creation of grouped plots"
type GroupBy mutable struct GroupBy
groupLabels::Vector # length == numGroups groupLabels::Vector # length == numGroups
groupIds::Vector{Vector{Int}} # list of indices for each group groupIds::Vector{Vector{Int}} # list of indices for each group
end end
@ -885,7 +999,7 @@ function extractGroupArgs(vs::Tuple, args...)
end end
# expecting a mapping of "group label" to "group indices" # expecting a mapping of "group label" to "group indices"
function extractGroupArgs{T, V<:AVec{Int}}(idxmap::Dict{T,V}, args...) function extractGroupArgs(idxmap::Dict{T,V}, args...) where {T, V<:AVec{Int}}
groupLabels = sortedkeys(idxmap) groupLabels = sortedkeys(idxmap)
groupIds = Vector{Int}[collect(idxmap[k]) for k in groupLabels] groupIds = Vector{Int}[collect(idxmap[k]) for k in groupLabels]
GroupBy(groupLabels, groupIds) GroupBy(groupLabels, groupIds)
@ -968,7 +1082,7 @@ function convertLegendValue(val::Symbol)
:best :best
elseif val in (:no, :none) elseif val in (:no, :none)
:none :none
elseif val in (:right, :left, :top, :bottom, :inside, :best, :legend, :topright, :topleft, :bottomleft, :bottomright) elseif val in (:right, :left, :top, :bottom, :inside, :best, :legend, :topright, :topleft, :bottomleft, :bottomright, :outertopright)
val val
else else
error("Invalid symbol for legend: $val") error("Invalid symbol for legend: $val")
@ -976,7 +1090,7 @@ function convertLegendValue(val::Symbol)
end end
convertLegendValue(val::Bool) = val ? :best : :none convertLegendValue(val::Bool) = val ? :best : :none
convertLegendValue(val::Void) = :none convertLegendValue(val::Void) = :none
convertLegendValue{S<:Real, T<:Real}(v::Tuple{S,T}) = v convertLegendValue(v::Tuple{S,T}) where {S<:Real, T<:Real} = v
convertLegendValue(v::AbstractArray) = map(convertLegendValue, v) convertLegendValue(v::AbstractArray) = map(convertLegendValue, v)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -1050,6 +1164,12 @@ const _match_map = KW(
:top_margin => :margin, :top_margin => :margin,
:right_margin => :margin, :right_margin => :margin,
:bottom_margin => :margin, :bottom_margin => :margin,
:titlefontfamily => :fontfamily_subplot,
:legendfontfamily => :fontfamily_subplot,
:titlefontcolor => :foreground_color_subplot,
:legendfontcolor => :foreground_color_subplot,
:tickfontcolor => :foreground_color_text,
:guidefontcolor => :foreground_color_guide,
) )
# these can match values from the parent container (axis --> subplot --> plot) # these can match values from the parent container (axis --> subplot --> plot)
@ -1061,6 +1181,9 @@ const _match_map2 = KW(
:foreground_color_grid => :foreground_color_subplot, :foreground_color_grid => :foreground_color_subplot,
:foreground_color_guide => :foreground_color_subplot, :foreground_color_guide => :foreground_color_subplot,
:foreground_color_text => :foreground_color_subplot, :foreground_color_text => :foreground_color_subplot,
:fontfamily_subplot => :fontfamily,
:tickfontfamily => :fontfamily_subplot,
:guidefontfamily => :fontfamily_subplot,
) )
# properly retrieve from plt.attr, passing `:match` to the correct key # properly retrieve from plt.attr, passing `:match` to the correct key

View File

@ -70,13 +70,16 @@ function process_axis_arg!(d::KW, arg, letter = "")
elseif arg == nothing elseif arg == nothing
d[Symbol(letter,:ticks)] = [] d[Symbol(letter,:ticks)] = []
elseif T <: Bool || arg in _allShowaxisArgs
d[Symbol(letter,:showaxis)] = showaxis(arg, letter)
elseif typeof(arg) <: Number elseif typeof(arg) <: Number
d[Symbol(letter,:rotation)] = arg d[Symbol(letter,:rotation)] = arg
elseif typeof(arg) <: Function elseif typeof(arg) <: Function
d[Symbol(letter,:formatter)] = arg d[Symbol(letter,:formatter)] = arg
else elseif !handleColors!(d, arg, Symbol(letter, :foreground_color_axis))
warn("Skipped $(letter)axis arg $arg") warn("Skipped $(letter)axis arg $arg")
end end
@ -236,8 +239,13 @@ function get_ticks(axis::Axis)
# discrete ticks... # discrete ticks...
axis[:continuous_values], dvals axis[:continuous_values], dvals
elseif ticks == :auto elseif ticks == :auto
# compute optimal ticks and labels if ispolar(axis.sps[1]) && axis[:letter] == :x
optimal_ticks_and_labels(axis) #force theta axis to be full circle
(collect(0:pi/4:7pi/4), string.(0:45:315))
else
# compute optimal ticks and labels
optimal_ticks_and_labels(axis)
end
elseif typeof(ticks) <: Union{AVec, Int} elseif typeof(ticks) <: Union{AVec, Int}
# override ticks, but get the labels # override ticks, but get the labels
optimal_ticks_and_labels(axis, ticks) optimal_ticks_and_labels(axis, ticks)
@ -290,13 +298,13 @@ expand_extrema!(axis::Axis, ::Void) = axis[:extrema]
expand_extrema!(axis::Axis, ::Bool) = axis[:extrema] expand_extrema!(axis::Axis, ::Bool) = axis[:extrema]
function expand_extrema!{MIN<:Number,MAX<:Number}(axis::Axis, v::Tuple{MIN,MAX}) function expand_extrema!(axis::Axis, v::Tuple{MIN,MAX}) where {MIN<:Number,MAX<:Number}
ex = axis[:extrema] ex = axis[:extrema]
ex.emin = NaNMath.min(v[1], ex.emin) ex.emin = NaNMath.min(v[1], ex.emin)
ex.emax = NaNMath.max(v[2], ex.emax) ex.emax = NaNMath.max(v[2], ex.emax)
ex ex
end end
function expand_extrema!{N<:Number}(axis::Axis, v::AVec{N}) function expand_extrema!(axis::Axis, v::AVec{N}) where N<:Number
ex = axis[:extrema] ex = axis[:extrema]
for vi in v for vi in v
expand_extrema!(ex, vi) expand_extrema!(ex, vi)
@ -347,7 +355,7 @@ function expand_extrema!(sp::Subplot, d::KW)
if fr == nothing && d[:seriestype] == :bar if fr == nothing && d[:seriestype] == :bar
fr = 0.0 fr = 0.0
end end
if fr != nothing if fr != nothing && !all3D(d)
axis = sp.attr[vert ? :yaxis : :xaxis] axis = sp.attr[vert ? :yaxis : :xaxis]
if typeof(fr) <: Tuple if typeof(fr) <: Tuple
for fri in fr for fri in fr
@ -372,6 +380,15 @@ function expand_extrema!(sp::Subplot, d::KW)
expand_extrema!(axis, ignorenan_minimum(data) - 0.5minimum(bw)) expand_extrema!(axis, ignorenan_minimum(data) - 0.5minimum(bw))
end end
# expand for heatmaps
if d[:seriestype] == :heatmap
for letter in (:x, :y)
data = d[letter]
axis = sp[Symbol(letter, "axis")]
scale = get(d, Symbol(letter, "scale"), :identity)
expand_extrema!(axis, heatmap_edges(data, scale))
end
end
end end
function expand_extrema!(sp::Subplot, xmin, xmax, ymin, ymax) function expand_extrema!(sp::Subplot, xmin, xmax, ymin, ymax)
@ -424,7 +441,16 @@ function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis)
if !isfinite(amin) && !isfinite(amax) if !isfinite(amin) && !isfinite(amax)
amin, amax = 0.0, 1.0 amin, amax = 0.0, 1.0
end end
if should_widen if ispolar(axis.sps[1])
if axis[:letter] == :x
amin, amax = 0, 2pi
elseif lims == :auto
#widen max radius so ticks dont overlap with theta axis
amin, amax + 0.1 * abs(amax - amin)
else
amin, amax
end
elseif should_widen
widen(amin, amax) widen(amin, amax)
else else
amin, amax amin, amax
@ -515,18 +541,24 @@ function axis_drawing_info(sp::Subplot)
xborder_segs = Segments(2) xborder_segs = Segments(2)
yborder_segs = Segments(2) yborder_segs = Segments(2)
if !(sp[:framestyle] == :none) if sp[:framestyle] != :none
# xaxis # xaxis
sp[:framestyle] in (:grid, :origin, :zerolines) || push!(xaxis_segs, (xmin,ymin), (xmax,ymin)) # bottom spine / xaxis if xaxis[:showaxis]
if sp[:framestyle] in (:origin, :zerolines) if sp[:framestyle] != :grid
push!(xaxis_segs, (xmin, 0.0), (xmax, 0.0)) y1, y2 = if sp[:framestyle] in (:origin, :zerolines)
# don't show the 0 tick label for the origin framestyle 0.0, 0.0
if sp[:framestyle] == :origin && length(xticks) > 1 else
showticks = xticks[1] .!= 0 xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, ymin) : (ymin, ymax)
xticks = (xticks[1][showticks], xticks[2][showticks]) end
push!(xaxis_segs, (xmin, y1), (xmax, y1))
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && length(xticks) > 1
showticks = xticks[1] .!= 0
xticks = (xticks[1][showticks], xticks[2][showticks])
end
end end
sp[:framestyle] in (:semi, :box) && push!(xborder_segs, (xmin, y2), (xmax, y2)) # top spine
end end
sp[:framestyle] in (:semi, :box) && push!(xborder_segs, (xmin,ymax), (xmax,ymax)) # top spine
if !(xaxis[:ticks] in (nothing, false)) if !(xaxis[:ticks] in (nothing, false))
f = scalefunc(yaxis[:scale]) f = scalefunc(yaxis[:scale])
invf = invscalefunc(yaxis[:scale]) invf = invscalefunc(yaxis[:scale])
@ -536,28 +568,36 @@ function axis_drawing_info(sp::Subplot)
t3 = invf(f(0) + 0.015 * (f(ymax) - f(ymin)) * ticks_in) t3 = invf(f(0) + 0.015 * (f(ymax) - f(ymin)) * ticks_in)
for xtick in xticks[1] for xtick in xticks[1]
tick_start, tick_stop = if sp[:framestyle] == :origin if xaxis[:showaxis]
(0, t3) tick_start, tick_stop = if sp[:framestyle] == :origin
else (0, t3)
xaxis[:mirror] ? (ymax, t2) : (ymin, t1) else
xor(xaxis[:mirror], yaxis[:flip]) ? (ymax, t2) : (ymin, t1)
end
push!(xtick_segs, (xtick, tick_start), (xtick, tick_stop)) # bottom tick
end end
push!(xtick_segs, (xtick, tick_start), (xtick, tick_stop)) # bottom tick
# sp[:draw_axes_border] && push!(xaxis_segs, (xtick, ymax), (xtick, t2)) # top tick # sp[:draw_axes_border] && push!(xaxis_segs, (xtick, ymax), (xtick, t2)) # top tick
xaxis[:grid] && push!(xgrid_segs, (xtick, t1), (xtick, t2)) # vertical grid xaxis[:grid] && push!(xgrid_segs, (xtick, ymin), (xtick, ymax)) # vertical grid
end end
end end
# yaxis # yaxis
sp[:framestyle] in (:grid, :origin, :zerolines) || push!(yaxis_segs, (xmin,ymin), (xmin,ymax)) # left spine / yaxis if yaxis[:showaxis]
if sp[:framestyle] in (:origin, :zerolines) if sp[:framestyle] != :grid
push!(yaxis_segs, (0.0, ymin), (0.0, ymax)) x1, x2 = if sp[:framestyle] in (:origin, :zerolines)
# don't show the 0 tick label for the origin framestyle 0.0, 0.0
if sp[:framestyle] == :origin && length(yticks) > 1 else
showticks = yticks[1] .!= 0 xor(yaxis[:mirror], xaxis[:flip]) ? (xmax, xmin) : (xmin, xmax)
yticks = (yticks[1][showticks], yticks[2][showticks]) end
push!(yaxis_segs, (x1, ymin), (x1, ymax))
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && length(yticks) > 1
showticks = yticks[1] .!= 0
yticks = (yticks[1][showticks], yticks[2][showticks])
end
end end
sp[:framestyle] in (:semi, :box) && push!(yborder_segs, (x2, ymin), (x2, ymax)) # right spine
end end
sp[:framestyle] in (:semi, :box) && push!(yborder_segs, (xmax,ymin), (xmax,ymax)) # right spine
if !(yaxis[:ticks] in (nothing, false)) if !(yaxis[:ticks] in (nothing, false))
f = scalefunc(xaxis[:scale]) f = scalefunc(xaxis[:scale])
invf = invscalefunc(xaxis[:scale]) invf = invscalefunc(xaxis[:scale])
@ -567,14 +607,16 @@ function axis_drawing_info(sp::Subplot)
t3 = invf(f(0) + 0.015 * (f(xmax) - f(xmin)) * ticks_in) t3 = invf(f(0) + 0.015 * (f(xmax) - f(xmin)) * ticks_in)
for ytick in yticks[1] for ytick in yticks[1]
tick_start, tick_stop = if sp[:framestyle] == :origin if yaxis[:showaxis]
(0, t3) tick_start, tick_stop = if sp[:framestyle] == :origin
else (0, t3)
yaxis[:mirror] ? (xmax, t2) : (xmin, t1) else
xor(yaxis[:mirror], xaxis[:flip]) ? (xmax, t2) : (xmin, t1)
end
push!(ytick_segs, (tick_start, ytick), (tick_stop, ytick)) # left tick
end end
push!(ytick_segs, (tick_start, ytick), (tick_stop, ytick)) # left tick
# sp[:draw_axes_border] && push!(yaxis_segs, (xmax, ytick), (t2, ytick)) # right tick # sp[:draw_axes_border] && push!(yaxis_segs, (xmax, ytick), (t2, ytick)) # right tick
yaxis[:grid] && push!(ygrid_segs, (t1, ytick), (t2, ytick)) # horizontal grid yaxis[:grid] && push!(ygrid_segs, (xmin, ytick), (xmax, ytick)) # horizontal grid
end end
end end
end end

View File

@ -1,5 +1,5 @@
immutable NoBackend <: AbstractBackend end struct NoBackend <: AbstractBackend end
const _backendType = Dict{Symbol, DataType}(:none => NoBackend) const _backendType = Dict{Symbol, DataType}(:none => NoBackend)
const _backendSymbol = Dict{DataType, Symbol}(NoBackend => :none) const _backendSymbol = Dict{DataType, Symbol}(NoBackend => :none)
@ -18,7 +18,7 @@ macro init_backend(s)
sym = Symbol(str) sym = Symbol(str)
T = Symbol(string(s) * "Backend") T = Symbol(string(s) * "Backend")
esc(quote esc(quote
immutable $T <: AbstractBackend end struct $T <: AbstractBackend end
export $sym export $sym
$sym(; kw...) = (default(; kw...); backend(Symbol($str))) $sym(; kw...) = (default(; kw...); backend(Symbol($str)))
backend_name(::$T) = Symbol($str) backend_name(::$T) = Symbol($str)
@ -51,8 +51,8 @@ _series_updated(plt::Plot, series::Series) = nothing
_before_layout_calcs(plt::Plot) = nothing _before_layout_calcs(plt::Plot) = nothing
title_padding(sp::Subplot) = sp[:title] == "" ? 0mm : sp[:titlefont].pointsize * pt title_padding(sp::Subplot) = sp[:title] == "" ? 0mm : sp[:titlefontsize] * pt
guide_padding(axis::Axis) = axis[:guide] == "" ? 0mm : axis[:guidefont].pointsize * pt guide_padding(axis::Axis) = axis[:guide] == "" ? 0mm : axis[:guidefontsize] * pt
"Returns the (width,height) of a text label." "Returns the (width,height) of a text label."
function text_size(lablen::Int, sz::Number, rot::Number = 0) function text_size(lablen::Int, sz::Number, rot::Number = 0)
@ -93,7 +93,7 @@ function tick_padding(axis::Axis)
# hgt # hgt
# get the height of the rotated label # get the height of the rotated label
text_size(longest_label, axis[:tickfont].pointsize, rot)[2] text_size(longest_label, axis[:tickfontsize], rot)[2]
end end
end end
@ -123,7 +123,7 @@ _update_plot_object(plt::Plot) = nothing
# --------------------------------------------------------- # ---------------------------------------------------------
type CurrentBackend mutable struct CurrentBackend
sym::Symbol sym::Symbol
pkg::AbstractBackend pkg::AbstractBackend
end end

View File

@ -9,6 +9,10 @@ TODO
* fix units in all visuals (e.g dotted lines, marker scale, surfaces) * fix units in all visuals (e.g dotted lines, marker scale, surfaces)
=# =#
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "glvisualize.jl"))
end
const _glvisualize_attr = merge_with_base_supported([ const _glvisualize_attr = merge_with_base_supported([
:annotations, :annotations,
:background_color_legend, :background_color_inside, :background_color_outside, :background_color_legend, :background_color_inside, :background_color_outside,
@ -20,10 +24,13 @@ const _glvisualize_attr = merge_with_base_supported([
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha, :fillrange, :fillcolor, :fillalpha,
:bins, :bar_width, :bar_edges, :bar_position, :bins, :bar_width, :bar_edges, :bar_position,
:title, :title_location, :titlefont, :title, :title_location,
:window_title, :window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation, :guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont, :titlefontsize, :titlefontcolor,
:legendfontsize, :legendfontcolor,
:tickfontsize,
:guidefontsize, :guidefontcolor,
:grid, :gridalpha, :gridstyle, :gridlinewidth, :grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :colorbar, :legend, :colorbar,
:marker_z, :marker_z,
@ -69,9 +76,9 @@ function _initialize_backend(::GLVisualizeBackend; kw...)
import GLVisualize: visualize import GLVisualize: visualize
import Plots.GL import Plots.GL
import UnicodeFun import UnicodeFun
Plots.slice_arg{C<:Colorant}(img::Matrix{C}, idx::Int) = img Plots.slice_arg(img::Matrix{C}, idx::Int) where {C<:Colorant} = img
is_marker_supported(::GLVisualizeBackend, shape::GLVisualize.AllPrimitives) = true is_marker_supported(::GLVisualizeBackend, shape::GLVisualize.AllPrimitives) = true
is_marker_supported{C<:Colorant}(::GLVisualizeBackend, shape::Union{Vector{Matrix{C}}, Matrix{C}}) = true is_marker_supported(::GLVisualizeBackend, shape::Union{Vector{Matrix{C}}, Matrix{C}}) where {C<:Colorant} = true
is_marker_supported(::GLVisualizeBackend, shape::Shape) = true is_marker_supported(::GLVisualizeBackend, shape::Shape) = true
const GL = Plots const GL = Plots
end end
@ -214,13 +221,13 @@ function extract_limits(sp, d, kw_args)
nothing nothing
end end
to_vec{T <: StaticArrays.StaticVector}(::Type{T}, vec::T) = vec to_vec(::Type{T}, vec::T) where {T <: StaticArrays.StaticVector} = vec
to_vec{T <: StaticArrays.StaticVector}(::Type{T}, s::Number) = T(s) to_vec(::Type{T}, s::Number) where {T <: StaticArrays.StaticVector} = T(s)
to_vec{T <: StaticArrays.StaticVector{2}}(::Type{T}, vec::StaticArrays.StaticVector{3}) = T(vec[1], vec[2]) to_vec(::Type{T}, vec::StaticArrays.StaticVector{3}) where {T <: StaticArrays.StaticVector{2}} = T(vec[1], vec[2])
to_vec{T <: StaticArrays.StaticVector{3}}(::Type{T}, vec::StaticArrays.StaticVector{2}) = T(vec[1], vec[2], 0) to_vec(::Type{T}, vec::StaticArrays.StaticVector{2}) where {T <: StaticArrays.StaticVector{3}} = T(vec[1], vec[2], 0)
to_vec{T <: StaticArrays.StaticVector}(::Type{T}, vecs::AbstractVector) = map(x-> to_vec(T, x), vecs) to_vec(::Type{T}, vecs::AbstractVector) where {T <: StaticArrays.StaticVector} = map(x-> to_vec(T, x), vecs)
function extract_marker(d, kw_args) function extract_marker(d, kw_args)
dim = Plots.is3d(d) ? 3 : 2 dim = Plots.is3d(d) ? 3 : 2
@ -275,7 +282,7 @@ end
function extract_surface(d) function extract_surface(d)
map(_extract_surface, (d[:x], d[:y], d[:z])) map(_extract_surface, (d[:x], d[:y], d[:z]))
end end
function topoints{P}(::Type{P}, array) function topoints(::Type{P}, array) where P
[P(x) for x in zip(array...)] [P(x) for x in zip(array...)]
end end
function extract_points(d) function extract_points(d)
@ -283,7 +290,7 @@ function extract_points(d)
array = (d[:x], d[:y], d[:z])[1:dim] array = (d[:x], d[:y], d[:z])[1:dim]
topoints(Point{dim, Float32}, array) topoints(Point{dim, Float32}, array)
end end
function make_gradient{C <: Colorant}(grad::Vector{C}) function make_gradient(grad::Vector{C}) where C <: Colorant
grad grad
end end
function make_gradient(grad::ColorGradient) function make_gradient(grad::ColorGradient)
@ -338,7 +345,7 @@ function extract_color(d, sym)
end end
gl_color(c::PlotUtils.ColorGradient) = c.colors gl_color(c::PlotUtils.ColorGradient) = c.colors
gl_color{T<:Colorant}(c::Vector{T}) = c gl_color(c::Vector{T}) where {T<:Colorant} = c
gl_color(c::RGBA{Float32}) = c gl_color(c::RGBA{Float32}) = c
gl_color(c::Colorant) = RGBA{Float32}(c) gl_color(c::Colorant) = RGBA{Float32}(c)
@ -608,7 +615,7 @@ function draw_ticks(
axis, ticks, isx, isorigin, lims, m, text = "", axis, ticks, isx, isorigin, lims, m, text = "",
positions = Point2f0[], offsets=Vec2f0[] positions = Point2f0[], offsets=Vec2f0[]
) )
sz = pointsize(axis[:tickfont]) sz = pointsize(tickfont(axis))
atlas = GLVisualize.get_texture_atlas() atlas = GLVisualize.get_texture_atlas()
font = GLVisualize.defaultfont() font = GLVisualize.defaultfont()
@ -732,21 +739,31 @@ function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, are
xlim = Plots.axis_limits(xaxis) xlim = Plots.axis_limits(xaxis)
ylim = Plots.axis_limits(yaxis) ylim = Plots.axis_limits(yaxis)
if !(xaxis[:ticks] in (nothing, false, :none)) && !(sp[:framestyle] == :none) if !(xaxis[:ticks] in (nothing, false, :none)) && !(sp[:framestyle] == :none) && xaxis[:showaxis]
ticklabels = map(model) do m ticklabels = map(model) do m
mirror = xaxis[:mirror] mirror = xaxis[:mirror]
t, positions, offsets = draw_ticks(xaxis, xticks, true, sp[:framestyle] == :origin, ylim, m) t, positions, offsets = draw_ticks(xaxis, xticks, true, sp[:framestyle] == :origin, ylim, m)
mirror = xaxis[:mirror]
t, positions, offsets = draw_ticks(
yaxis, yticks, false, sp[:framestyle] == :origin, xlim, m,
t, positions, offsets
)
end end
kw_args = Dict{Symbol, Any}( kw_args = Dict{Symbol, Any}(
:position => map(x-> x[2], ticklabels), :position => map(x-> x[2], ticklabels),
:offset => map(last, ticklabels), :offset => map(last, ticklabels),
:color => fcolor, :color => fcolor,
:relative_scale => pointsize(xaxis[:tickfont]), :relative_scale => pointsize(tickfont(xaxis)),
:scale_primitive => false
)
push!(axis_vis, visualize(map(first, ticklabels), Style(:default), kw_args))
end
if !(yaxis[:ticks] in (nothing, false, :none)) && !(sp[:framestyle] == :none) && yaxis[:showaxis]
ticklabels = map(model) do m
mirror = yaxis[:mirror]
t, positions, offsets = draw_ticks(yaxis, yticks, false, sp[:framestyle] == :origin, xlim, m)
end
kw_args = Dict{Symbol, Any}(
:position => map(x-> x[2], ticklabels),
:offset => map(last, ticklabels),
:color => fcolor,
:relative_scale => pointsize(tickfont(xaxis)),
:scale_primitive => false :scale_primitive => false
) )
push!(axis_vis, visualize(map(first, ticklabels), Style(:default), kw_args)) push!(axis_vis, visualize(map(first, ticklabels), Style(:default), kw_args))
@ -763,8 +780,8 @@ function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, are
area_w = GeometryTypes.widths(area) area_w = GeometryTypes.widths(area)
if sp[:title] != "" if sp[:title] != ""
tf = sp[:titlefont]; color = gl_color(sp[:foreground_color_title]) tf = titlefont(sp)
font = Plots.Font(tf.family, tf.pointsize, :hcenter, :top, tf.rotation, color) font = Plots.Font(tf.family, tf.pointsize, :hcenter, :top, tf.rotation, tf.color)
xy = Point2f0(area.w/2, area_w[2] + pointsize(tf)/2) xy = Point2f0(area.w/2, area_w[2] + pointsize(tf)/2)
kw = Dict(:model => text_model(font, xy), :scale_primitive => true) kw = Dict(:model => text_model(font, xy), :scale_primitive => true)
extract_font(font, kw) extract_font(font, kw)
@ -772,9 +789,9 @@ function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, are
push!(axis_vis, glvisualize_text(xy, t, kw)) push!(axis_vis, glvisualize_text(xy, t, kw))
end end
if xaxis[:guide] != "" if xaxis[:guide] != ""
tf = xaxis[:guidefont]; color = gl_color(xaxis[:foreground_color_guide]) tf = guidefont(xaxis)
xy = Point2f0(area.w/2, - pointsize(tf)/2) xy = Point2f0(area.w/2, - pointsize(tf)/2)
font = Plots.Font(tf.family, tf.pointsize, :hcenter, :bottom, tf.rotation, color) font = Plots.Font(tf.family, tf.pointsize, :hcenter, :bottom, tf.rotation, tf.color)
kw = Dict(:model => text_model(font, xy), :scale_primitive => true) kw = Dict(:model => text_model(font, xy), :scale_primitive => true)
t = PlotText(xaxis[:guide], font) t = PlotText(xaxis[:guide], font)
extract_font(font, kw) extract_font(font, kw)
@ -782,8 +799,8 @@ function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, are
end end
if yaxis[:guide] != "" if yaxis[:guide] != ""
tf = yaxis[:guidefont]; color = gl_color(yaxis[:foreground_color_guide]) tf = guidefont(yaxis)
font = Plots.Font(tf.family, tf.pointsize, :hcenter, :top, 90f0, color) font = Plots.Font(tf.family, tf.pointsize, :hcenter, :top, 90f0, tf.color)
xy = Point2f0(-pointsize(tf)/2, area.h/2) xy = Point2f0(-pointsize(tf)/2, area.h/2)
kw = Dict(:model => text_model(font, xy), :scale_primitive=>true) kw = Dict(:model => text_model(font, xy), :scale_primitive=>true)
t = PlotText(yaxis[:guide], font) t = PlotText(yaxis[:guide], font)
@ -1202,7 +1219,7 @@ function gl_image(img, kw_args)
visualize(img, Style(:default), kw_args) visualize(img, Style(:default), kw_args)
end end
function handle_segment{P}(lines, line_segments, points::Vector{P}, segment) function handle_segment(lines, line_segments, points::Vector{P}, segment) where P
(isempty(segment) || length(segment) < 2) && return (isempty(segment) || length(segment) < 2) && return
if length(segment) == 2 if length(segment) == 2
append!(line_segments, view(points, segment)) append!(line_segments, view(points, segment))
@ -1469,9 +1486,8 @@ function make_label(sp, series, i)
else else
series[:label] series[:label]
end end
color = sp[:foreground_color_legend] ft = legendfont(sp)
ft = sp[:legendfont] font = Plots.Font(ft.family, ft.pointsize, :left, :bottom, 0.0, ft.color)
font = Plots.Font(ft.family, ft.pointsize, :left, :bottom, 0.0, color)
xy = Point2f0(w+gap, 0.0) xy = Point2f0(w+gap, 0.0)
kw = Dict(:model => text_model(font, xy), :scale_primitive=>false) kw = Dict(:model => text_model(font, xy), :scale_primitive=>false)
extract_font(font, kw) extract_font(font, kw)

View File

@ -3,6 +3,9 @@
# significant contributions by @jheinen # significant contributions by @jheinen
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "gr.jl"))
end
const _gr_attr = merge_with_base_supported([ const _gr_attr = merge_with_base_supported([
:annotations, :annotations,
@ -19,7 +22,14 @@ const _gr_attr = merge_with_base_supported([
:layout, :layout,
:title, :window_title, :title, :window_title,
:guide, :lims, :ticks, :scale, :flip, :guide, :lims, :ticks, :scale, :flip,
:tickfont, :guidefont, :legendfont, :titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
:titlefontrotation, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfonthalign, :legendfontvalign,
:legendfontrotation, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfonthalign, :tickfontvalign,
:tickfontrotation, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefonthalign, :guidefontvalign,
:guidefontrotation, :guidefontcolor,
:grid, :gridalpha, :gridstyle, :gridlinewidth, :grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar, :legend, :legendtitle, :colorbar,
:fill_z, :line_z, :marker_z, :levels, :fill_z, :line_z, :marker_z, :levels,
@ -34,6 +44,7 @@ const _gr_attr = merge_with_base_supported([
:arrow, :arrow,
:framestyle, :framestyle,
:tick_direction, :tick_direction,
:camera,
]) ])
const _gr_seriestype = [ const _gr_seriestype = [
:path, :scatter, :path, :scatter,
@ -201,35 +212,62 @@ function gr_text(x, y, s)
end end
end end
function gr_polaraxes(rmin, rmax) function gr_polaraxes(rmin::Real, rmax::Real, sp::Subplot)
GR.savestate() GR.savestate()
GR.setlinetype(GR.LINETYPE_SOLID) xaxis = sp[:xaxis]
GR.setlinecolorind(88) yaxis = sp[:yaxis]
tick = 0.5 * GR.tick(rmin, rmax)
n = round(Int, (rmax - rmin) / tick + 0.5) α = 0:45:315
for i in 0:n a = α .+ 90
r = float(i) / n sinf = sind.(a)
if i % 2 == 0 cosf = cosd.(a)
GR.setlinecolorind(88) rtick_values, rtick_labels = get_ticks(yaxis)
if i > 0
GR.drawarc(-r, r, -r, r, 0, 359) #draw angular grid
end if xaxis[:grid]
GR.settextalign(GR.TEXT_HALIGN_LEFT, GR.TEXT_VALIGN_HALF) gr_set_line(xaxis[:gridlinewidth], xaxis[:gridstyle], xaxis[:foreground_color_grid])
x, y = GR.wctondc(0.05, r) GR.settransparency(xaxis[:gridalpha])
GR.text(x, y, string(signif(rmin + i * tick, 12))) for i in 1:length(α)
else GR.polyline([sinf[i], 0], [cosf[i], 0])
GR.setlinecolorind(90)
GR.drawarc(-r, r, -r, r, 0, 359)
end end
end end
for α in 0:45:315
a = α + 90 #draw radial grid
sinf = sin(a * pi / 180) if yaxis[:grid]
cosf = cos(a * pi / 180) gr_set_line(yaxis[:gridlinewidth], yaxis[:gridstyle], yaxis[:foreground_color_grid])
GR.polyline([sinf, 0], [cosf, 0]) GR.settransparency(yaxis[:gridalpha])
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF) for i in 1:length(rtick_values)
x, y = GR.wctondc(1.1 * sinf, 1.1 * cosf) r = (rtick_values[i] - rmin) / (rmax - rmin)
GR.textext(x, y, string(α, "^o")) if r <= 1.0 && r >= 0.0
GR.drawarc(-r, r, -r, r, 0, 359)
end
end
GR.drawarc(-1, 1, -1, 1, 0, 359)
end
#prepare to draw ticks
GR.settransparency(1)
GR.setlinecolorind(90)
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF)
#draw angular ticks
if xaxis[:showaxis]
GR.drawarc(-1, 1, -1, 1, 0, 359)
for i in 1:length(α)
x, y = GR.wctondc(1.1 * sinf[i], 1.1 * cosf[i])
GR.textext(x, y, string((360-α[i])%360, "^o"))
end
end
#draw radial ticks
if yaxis[:showaxis]
for i in 1:length(rtick_values)
r = (rtick_values[i] - rmin) / (rmax - rmin)
if r <= 1.0 && r >= 0.0
x, y = GR.wctondc(0.05, r)
gr_text(x, y, _cycle(rtick_labels, i))
end
end
end end
GR.restorestate() GR.restorestate()
end end
@ -342,10 +380,6 @@ function gr_draw_markers(series::Series, x, y, clims)
mz = normalize_zvals(series[:marker_z], clims) mz = normalize_zvals(series[:marker_z], clims)
GR.setfillintstyle(GR.INTSTYLE_SOLID) GR.setfillintstyle(GR.INTSTYLE_SOLID)
gr_draw_markers(series, x, y, series[:markersize], mz) gr_draw_markers(series, x, y, series[:markersize], mz)
if hascolorbar(series[:subplot])
GR.setscale(0)
gr_colorbar(series[:subplot], clims)
end
end end
# --------------------------------------------------------- # ---------------------------------------------------------
@ -412,6 +446,9 @@ function gr_viewport_from_bbox(sp::Subplot{GRBackend}, bb::BoundingBox, w, h, vi
viewport[3] = 0.5 * (vp[3] + vp[4] - extent) viewport[3] = 0.5 * (vp[3] + vp[4] - extent)
viewport[4] = 0.5 * (vp[3] + vp[4] + extent) viewport[4] = 0.5 * (vp[3] + vp[4] + extent)
end end
if hascolorbar(sp)
viewport[2] -= 0.1
end
viewport viewport
end end
@ -447,17 +484,12 @@ function gr_set_viewport_polar()
end end
# add the colorbar # add the colorbar
function gr_colorbar(sp::Subplot)
gr_set_viewport_cmap(sp)
GR.colorbar()
gr_set_viewport_plotarea()
end
function gr_colorbar(sp::Subplot, clims) function gr_colorbar(sp::Subplot, clims)
xmin, xmax = gr_xy_axislims(sp)[1:2] xmin, xmax = gr_xy_axislims(sp)[1:2]
gr_set_viewport_cmap(sp) gr_set_viewport_cmap(sp)
l = zeros(Int32, 1, 256) l = zeros(Int32, 1, 256)
l[1,:] = Int[round(Int, _i) for _i in linspace(1000, 1255, 256)] l[1,:] = Int[round(Int, _i) for _i in linspace(1000, 1255, 256)]
GR.setscale(0)
GR.setwindow(xmin, xmax, clims[1], clims[2]) GR.setwindow(xmin, xmax, clims[1], clims[2])
GR.cellarray(xmin, xmax, clims[2], clims[1], 1, length(l), l) GR.cellarray(xmin, xmax, clims[2], clims[1], 1, length(l), l)
ztick = 0.5 * GR.tick(clims[1], clims[2]) ztick = 0.5 * GR.tick(clims[1], clims[2])
@ -490,7 +522,7 @@ function gr_legend_pos(s::Symbol,w,h)
(xpos,ypos) (xpos,ypos)
end end
function gr_legend_pos{S<:Real, T<:Real}(v::Tuple{S,T},w,h) function gr_legend_pos(v::Tuple{S,T},w,h) where {S<:Real, T<:Real}
xpos = v[1] * (viewport_plotarea[2] - viewport_plotarea[1]) + viewport_plotarea[1] xpos = v[1] * (viewport_plotarea[2] - viewport_plotarea[1]) + viewport_plotarea[1]
ypos = v[2] * (viewport_plotarea[4] - viewport_plotarea[3]) + viewport_plotarea[3] ypos = v[2] * (viewport_plotarea[4] - viewport_plotarea[3]) + viewport_plotarea[3]
(xpos,ypos) (xpos,ypos)
@ -558,10 +590,9 @@ end
function gr_set_xticks_font(sp) function gr_set_xticks_font(sp)
flip = sp[:yaxis][:flip] flip = sp[:yaxis][:flip]
mirror = sp[:xaxis][:mirror] mirror = sp[:xaxis][:mirror]
gr_set_font(sp[:xaxis][:tickfont], gr_set_font(tickfont(sp[:xaxis]),
halign = (:left, :hcenter, :right)[sign(sp[:xaxis][:rotation]) + 2], halign = (:left, :hcenter, :right)[sign(sp[:xaxis][:rotation]) + 2],
valign = (mirror ? :bottom : :top), valign = (mirror ? :bottom : :top),
color = sp[:xaxis][:foreground_color_axis],
rotation = sp[:xaxis][:rotation]) rotation = sp[:xaxis][:rotation])
return flip, mirror return flip, mirror
end end
@ -570,10 +601,9 @@ end
function gr_set_yticks_font(sp) function gr_set_yticks_font(sp)
flip = sp[:xaxis][:flip] flip = sp[:xaxis][:flip]
mirror = sp[:yaxis][:mirror] mirror = sp[:yaxis][:mirror]
gr_set_font(sp[:yaxis][:tickfont], gr_set_font(tickfont(sp[:yaxis]),
halign = (mirror ? :left : :right), halign = (mirror ? :left : :right),
valign = (:top, :vcenter, :bottom)[sign(sp[:yaxis][:rotation]) + 2], valign = (:top, :vcenter, :bottom)[sign(sp[:yaxis][:rotation]) + 2],
color = sp[:yaxis][:foreground_color_axis],
rotation = sp[:yaxis][:rotation]) rotation = sp[:yaxis][:rotation])
return flip, mirror return flip, mirror
end end
@ -692,11 +722,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
end end
end end
if cmap
# note: add extra midpadding on the right for the colorbar
viewport_plotarea[2] -= 0.1
end
# set our plot area view # set our plot area view
gr_set_viewport_plotarea() gr_set_viewport_plotarea()
@ -739,8 +764,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
end end
# draw the axes # draw the axes
gr_set_font(xaxis[:tickfont]) gr_set_font(tickfont(xaxis))
gr_set_textcolor(xaxis[:foreground_color_text])
GR.setlinewidth(1) GR.setlinewidth(1)
if is3d(sp) if is3d(sp)
@ -750,7 +774,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
isfinite(clims[1]) && (zmin = clims[1]) isfinite(clims[1]) && (zmin = clims[1])
isfinite(clims[2]) && (zmax = clims[2]) isfinite(clims[2]) && (zmax = clims[2])
end end
GR.setspace(zmin, zmax, 35, 60) GR.setspace(zmin, zmax, round.(Int, sp[:camera])...)
xtick = GR.tick(xmin, xmax) / 2 xtick = GR.tick(xmin, xmax) / 2
ytick = GR.tick(ymin, ymax) / 2 ytick = GR.tick(ymin, ymax) / 2
ztick = GR.tick(zmin, zmax) / 2 ztick = GR.tick(zmin, zmax) / 2
@ -765,9 +789,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
elseif ispolar(sp) elseif ispolar(sp)
r = gr_set_viewport_polar() r = gr_set_viewport_polar()
rmin, rmax = GR.adjustrange(ignorenan_minimum(r), ignorenan_maximum(r)) #rmin, rmax = GR.adjustrange(ignorenan_minimum(r), ignorenan_maximum(r))
# rmin, rmax = axis_limits(sp[:yaxis]) rmin, rmax = axis_limits(sp[:yaxis])
gr_polaraxes(rmin, rmax) gr_polaraxes(rmin, rmax, sp)
elseif draw_axes elseif draw_axes
if xmax > xmin && ymax > ymin if xmax > xmin && ymax > ymin
@ -793,35 +817,43 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
GR.settransparency(1.0) GR.settransparency(1.0)
# axis lines # axis lines
gr_set_line(1, :solid, xaxis[:foreground_color_axis]) if xaxis[:showaxis]
GR.setclip(0) gr_set_line(1, :solid, xaxis[:foreground_color_axis])
gr_polyline(coords(xspine_segs)...) GR.setclip(0)
gr_set_line(1, :solid, yaxis[:foreground_color_axis]) gr_polyline(coords(xspine_segs)...)
GR.setclip(0) end
gr_polyline(coords(yspine_segs)...) if yaxis[:showaxis]
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
GR.setclip(0)
gr_polyline(coords(yspine_segs)...)
end
GR.setclip(1) GR.setclip(1)
# axis ticks # axis ticks
if sp[:framestyle] in (:zerolines, :grid) if xaxis[:showaxis]
gr_set_line(1, :solid, xaxis[:foreground_color_grid]) if sp[:framestyle] in (:zerolines, :grid)
GR.settransparency(xaxis[:gridalpha]) gr_set_line(1, :solid, xaxis[:foreground_color_grid])
else GR.settransparency(xaxis[:gridalpha])
gr_set_line(1, :solid, xaxis[:foreground_color_axis]) else
gr_set_line(1, :solid, xaxis[:foreground_color_axis])
end
GR.setclip(0)
gr_polyline(coords(xtick_segs)...)
end end
GR.setclip(0) if yaxis[:showaxis]
gr_polyline(coords(xtick_segs)...) if sp[:framestyle] in (:zerolines, :grid)
if sp[:framestyle] in (:zerolines, :grid) gr_set_line(1, :solid, yaxis[:foreground_color_grid])
gr_set_line(1, :solid, yaxis[:foreground_color_grid]) GR.settransparency(yaxis[:gridalpha])
GR.settransparency(yaxis[:gridalpha]) else
else gr_set_line(1, :solid, yaxis[:foreground_color_axis])
gr_set_line(1, :solid, yaxis[:foreground_color_axis]) end
GR.setclip(0)
gr_polyline(coords(ytick_segs)...)
end end
GR.setclip(0)
gr_polyline(coords(ytick_segs)...)
GR.setclip(1) GR.setclip(1)
# tick marks # tick marks
if !(xticks in (:none, nothing, false)) if !(xticks in (:none, nothing, false)) && xaxis[:showaxis]
# x labels # x labels
flip, mirror = gr_set_xticks_font(sp) flip, mirror = gr_set_xticks_font(sp)
for (cv, dv) in zip(xticks...) for (cv, dv) in zip(xticks...)
@ -832,7 +864,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
end end
end end
if !(yticks in (:none, nothing, false)) if !(yticks in (:none, nothing, false)) && yaxis[:showaxis]
# y labels # y labels
flip, mirror = gr_set_yticks_font(sp) flip, mirror = gr_set_yticks_font(sp)
for (cv, dv) in zip(yticks...) for (cv, dv) in zip(yticks...)
@ -859,29 +891,37 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# add the guides # add the guides
GR.savestate() GR.savestate()
if sp[:title] != "" if sp[:title] != ""
gr_set_font(sp[:titlefont]) gr_set_font(titlefont(sp))
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP) loc = sp[:title_location]
gr_set_textcolor(sp[:foreground_color_title]) if loc == :left
gr_text(gr_view_xcenter(), viewport_subplot[4], sp[:title]) xpos = viewport_plotarea[1]
halign = GR.TEXT_HALIGN_LEFT
elseif loc == :right
xpos = viewport_plotarea[2]
halign = GR.TEXT_HALIGN_RIGHT
else
xpos = gr_view_xcenter()
halign = GR.TEXT_HALIGN_CENTER
end
GR.settextalign(halign, GR.TEXT_VALIGN_TOP)
gr_text(xpos, viewport_subplot[4], sp[:title])
end end
if xaxis[:guide] != "" if xaxis[:guide] != ""
gr_set_font(xaxis[:guidefont]) gr_set_font(guidefont(xaxis))
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_BOTTOM) GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_BOTTOM)
gr_set_textcolor(xaxis[:foreground_color_guide])
gr_text(gr_view_xcenter(), viewport_subplot[3], xaxis[:guide]) gr_text(gr_view_xcenter(), viewport_subplot[3], xaxis[:guide])
end end
if yaxis[:guide] != "" if yaxis[:guide] != ""
gr_set_font(yaxis[:guidefont]) gr_set_font(guidefont(yaxis))
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP) GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP)
GR.setcharup(-1, 0) GR.setcharup(-1, 0)
gr_set_textcolor(yaxis[:foreground_color_guide])
gr_text(viewport_subplot[1], gr_view_ycenter(), yaxis[:guide]) gr_text(viewport_subplot[1], gr_view_ycenter(), yaxis[:guide])
end end
GR.restorestate() GR.restorestate()
gr_set_font(xaxis[:tickfont]) gr_set_font(tickfont(xaxis))
# this needs to be here to point the colormap to the right indices # this needs to be here to point the colormap to the right indices
GR.setcolormap(1000 + GR.COLORMAP_COOLWARM) GR.setcolormap(1000 + GR.COLORMAP_COOLWARM)
@ -935,33 +975,32 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
if st in (:path, :scatter) if st in (:path, :scatter)
if length(x) > 1 if length(x) > 1
lz = series[:line_z]
segments_iterator = if lz != nothing && length(lz) > 1
[i:(i + 1) for i in 1:(length(x) - 1)]
else
iter_segments(x, y)
end
# do area fill # do area fill
if frng != nothing if frng != nothing
GR.setfillintstyle(GR.INTSTYLE_SOLID) GR.setfillintstyle(GR.INTSTYLE_SOLID)
fr_from, fr_to = (is_2tuple(frng) ? frng : (y, frng)) fr_from, fr_to = (is_2tuple(frng) ? frng : (y, frng))
for i in 1:length(x) - 1 for (i, rng) in enumerate(segments_iterator)
gr_set_fillcolor(get_fillcolor(sp, series, i)) gr_set_fillcolor(get_fillcolor(sp, series, i))
xseg = _cycle(x, [i, i+1, i+1, i]) fx = _cycle(x, vcat(rng, reverse(rng)))
yseg = [_cycle(fr_from, [i, i+1]); _cycle(fr_to, [i+1, i])] fy = vcat(_cycle(fr_from,rng), _cycle(fr_to,reverse(rng)))
series[:fillalpha] != nothing && GR.settransparency(series[:fillalpha]) series[:fillalpha] != nothing && GR.settransparency(series[:fillalpha])
GR.fillarea(xseg, yseg) GR.fillarea(fx, fy)
end end
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
GR.settransparency(1)
cmap && gr_colorbar(sp, clims)
end end
# draw the line(s) # draw the line(s)
if st == :path if st == :path
for i in 1:length(x) - 1 for (i, rng) in enumerate(segments_iterator)
xseg = x[i:(i + 1)]
yseg = y[i:(i + 1)]
gr_set_line(series[:linewidth], series[:linestyle], get_linecolor(sp, series, i)) #, series[:linealpha]) gr_set_line(series[:linewidth], series[:linestyle], get_linecolor(sp, series, i)) #, series[:linealpha])
arrowside = (i == length(y) - 1) && isa(series[:arrow], Arrow) ? series[:arrow].side : :none arrowside = isa(series[:arrow], Arrow) ? series[:arrow].side : :none
gr_polyline(xseg, yseg; arrowside = arrowside) gr_polyline(x[rng], y[rng]; arrowside = arrowside)
end end
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
cmap && gr_colorbar(sp, clims)
end end
end end
@ -984,11 +1023,14 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
if series[:fillrange] != nothing if series[:fillrange] != nothing
GR.surface(x, y, z, GR.OPTION_CELL_ARRAY) GR.surface(x, y, z, GR.OPTION_CELL_ARRAY)
else else
GR.setlinetype(gr_linetype[series[:linestyle]])
GR.setlinewidth(max(0, series[:linewidth] / (sum(gr_plot_size) * 0.001)))
GR.contour(x, y, h, z, 1000) GR.contour(x, y, h, z, 1000)
end end
# create the colorbar of contour levels # create the colorbar of contour levels
if cmap if cmap
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
gr_set_viewport_cmap(sp) gr_set_viewport_cmap(sp)
l = round.(Int32, 1000 + (h - ignorenan_minimum(h)) / (ignorenan_maximum(h) - ignorenan_minimum(h)) * 255) l = round.(Int32, 1000 + (h - ignorenan_minimum(h)) / (ignorenan_maximum(h) - ignorenan_minimum(h)) * 255)
GR.setwindow(xmin, xmax, zmin, zmax) GR.setwindow(xmin, xmax, zmin, zmax)
@ -1009,7 +1051,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
GR.setfillcolorind(0) GR.setfillcolorind(0)
GR.surface(x, y, z, GR.OPTION_FILLED_MESH) GR.surface(x, y, z, GR.OPTION_FILLED_MESH)
end end
cmap && gr_colorbar(sp)
elseif st == :heatmap elseif st == :heatmap
xmin, xmax, ymin, ymax = xy_lims xmin, xmax, ymin, ymax = xy_lims
@ -1023,20 +1064,22 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
round(Int, red(c) * 255) ), colors) round(Int, red(c) * 255) ), colors)
w, h = length(x), length(y) w, h = length(x), length(y)
GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba) GR.drawimage(xmin, xmax, ymax, ymin, w, h, rgba)
cmap && gr_colorbar(sp, clims)
elseif st in (:path3d, :scatter3d) elseif st in (:path3d, :scatter3d)
# draw path # draw path
if st == :path3d if st == :path3d
for i in 1:length(x) - 1 if length(x) > 1
xseg = x[i:(i + 1)] lz = series[:line_z]
yseg = y[i:(i + 1)] segments_iterator = if lz != nothing && length(lz) > 1
zseg = z[i:(i + 1)] [i:(i + 1) for i in 1:(length(x) - 1)]
gr_set_line(series[:linewidth], series[:linestyle], get_linecolor(sp, series, i)) #, series[:linealpha]) else
GR.polyline3d(xseg, yseg, zseg) iter_segments(x, y, z)
end
for (i, rng) in enumerate(segments_iterator)
gr_set_line(series[:linewidth], series[:linestyle], get_linecolor(sp, series, i)) #, series[:linealpha])
GR.polyline3d(x[rng], y[rng], z[rng])
end
end end
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
cmap && gr_colorbar(sp, clims)
end end
# draw markers # draw markers
@ -1111,8 +1154,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
GR.polyline(xseg, yseg) GR.polyline(xseg, yseg)
end end
end end
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
cmap && gr_colorbar(sp, clims)
elseif st == :image elseif st == :image
@ -1137,6 +1178,13 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
gr_text(GR.wctondc(xi, yi)..., str) gr_text(GR.wctondc(xi, yi)..., str)
end end
# draw the colorbar
if cmap && st != :contour # special colorbar with steps is drawn for contours
gr_set_line(1, :solid, yaxis[:foreground_color_axis])
GR.settransparency(1)
gr_colorbar(sp, clims)
end
GR.restorestate() GR.restorestate()
end end
@ -1146,7 +1194,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
GR.savestate() GR.savestate()
GR.selntran(0) GR.selntran(0)
GR.setscale(0) GR.setscale(0)
gr_set_font(sp[:legendfont]) gr_set_font(legendfont(sp))
w = 0 w = 0
i = 0 i = 0
n = 0 n = 0
@ -1164,23 +1212,22 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
else else
lab = series[:label] lab = series[:label]
end end
tbx, tby = gr_inqtext(0, 0, lab) tbx, tby = gr_inqtext(0, 0, string(lab))
w = max(w, tbx[3] - tbx[1]) w = max(w, tbx[3] - tbx[1])
end end
if w > 0 if w > 0
dy = _gr_point_mult[1] * sp[:legendfont].pointsize * 1.75 dy = _gr_point_mult[1] * sp[:legendfontsize] * 1.75
h = dy*n h = dy*n
(xpos,ypos) = gr_legend_pos(sp[:legend],w,h) (xpos,ypos) = gr_legend_pos(sp[:legend],w,h)
GR.setfillintstyle(GR.INTSTYLE_SOLID) GR.setfillintstyle(GR.INTSTYLE_SOLID)
gr_set_fillcolor(sp[:background_color_legend]) gr_set_fillcolor(sp[:background_color_legend])
GR.fillrect(xpos - 0.08, xpos + w + 0.02, ypos + dy, ypos - dy * n) GR.fillrect(xpos - 0.08, xpos + w + 0.02, ypos + dy, ypos - dy * n)
GR.setlinetype(1) gr_set_line(1, :solid, sp[:foreground_color_legend])
GR.setlinewidth(1)
GR.drawrect(xpos - 0.08, xpos + w + 0.02, ypos + dy, ypos - dy * n) GR.drawrect(xpos - 0.08, xpos + w + 0.02, ypos + dy, ypos - dy * n)
i = 0 i = 0
if sp[:legendtitle] != nothing if sp[:legendtitle] != nothing
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF) GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF)
gr_set_textcolor(sp[:foreground_color_legend]) gr_set_textcolor(sp[:legendfontcolor])
GR.settransparency(1) GR.settransparency(1)
gr_text(xpos - 0.03 + 0.5*w, ypos, string(sp[:legendtitle])) gr_text(xpos - 0.03 + 0.5*w, ypos, string(sp[:legendtitle]))
ypos -= dy ypos -= dy
@ -1222,8 +1269,8 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
lab = series[:label] lab = series[:label]
end end
GR.settextalign(GR.TEXT_HALIGN_LEFT, GR.TEXT_VALIGN_HALF) GR.settextalign(GR.TEXT_HALIGN_LEFT, GR.TEXT_VALIGN_HALF)
gr_set_textcolor(sp[:foreground_color_legend]) gr_set_textcolor(sp[:legendfontcolor])
gr_text(xpos, ypos, lab) gr_text(xpos, ypos, string(lab))
ypos -= dy ypos -= dy
end end
end end
@ -1281,12 +1328,18 @@ for (mime, fmt) in _gr_mimeformats
@eval function _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{GRBackend}) @eval function _show(io::IO, ::MIME{Symbol($mime)}, plt::Plot{GRBackend})
GR.emergencyclosegks() GR.emergencyclosegks()
filepath = tempname() * "." * $fmt filepath = tempname() * "." * $fmt
env = get(ENV, "GKSwstype", "0")
ENV["GKSwstype"] = $fmt ENV["GKSwstype"] = $fmt
ENV["GKS_FILEPATH"] = filepath ENV["GKS_FILEPATH"] = filepath
gr_display(plt) gr_display(plt)
GR.emergencyclosegks() GR.emergencyclosegks()
write(io, readstring(filepath)) write(io, readstring(filepath))
rm(filepath) rm(filepath)
if env != "0"
ENV["GKSwstype"] = env
else
pop!(ENV,"GKSwstype")
end
end end
end end

View File

@ -28,14 +28,17 @@ Read from .hdf5 file using:
- Should be reliable for archival purposes. - Should be reliable for archival purposes.
==# ==#
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "hdf5.jl"))
end
import FixedPointNumbers: N0f8 #In core Julia import FixedPointNumbers: N0f8 #In core Julia
#Dispatch types: #Dispatch types:
immutable HDF5PlotNative; end #Indentifies a data element that can natively be handled by HDF5 struct HDF5PlotNative; end #Indentifies a data element that can natively be handled by HDF5
immutable HDF5CTuple; end #Identifies a "complex" tuple structure struct HDF5CTuple; end #Identifies a "complex" tuple structure
type HDF5Plot_PlotRef mutable struct HDF5Plot_PlotRef
ref::Union{Plot, Void} ref::Union{Plot, Void}
end end
@ -128,7 +131,7 @@ function _hdf5_merge!(dest::Dict, src::Dict)
_hdf5_merge!(dest[k].d, v.d) _hdf5_merge!(dest[k].d, v.d)
else else
dest[k] = v dest[k] = v
end end
end end
return return
end end
@ -276,11 +279,11 @@ function _hdf5plot_overwritetype(grp, T::Type) #Write directly to group
HDF5.a_delete(grp, _hdf5plot_datatypeid) HDF5.a_delete(grp, _hdf5plot_datatypeid)
HDF5.a_write(grp, _hdf5plot_datatypeid, tstr) HDF5.a_write(grp, _hdf5plot_datatypeid, tstr)
end end
function _hdf5plot_writetype{T<:Any}(grp, ::Type{Array{T}}) function _hdf5plot_writetype(grp, ::Type{Array{T}}) where T<:Any
tstr = HDF5PLOT_MAP_TELEM2STR[Array] #ANY tstr = HDF5PLOT_MAP_TELEM2STR[Array] #ANY
HDF5.a_write(grp, _hdf5plot_datatypeid, tstr) HDF5.a_write(grp, _hdf5plot_datatypeid, tstr)
end end
function _hdf5plot_writetype{T<:BoundingBox}(grp, ::Type{T}) function _hdf5plot_writetype(grp, ::Type{T}) where T<:BoundingBox
tstr = HDF5PLOT_MAP_TELEM2STR[BoundingBox] tstr = HDF5PLOT_MAP_TELEM2STR[BoundingBox]
HDF5.a_write(grp, _hdf5plot_datatypeid, tstr) HDF5.a_write(grp, _hdf5plot_datatypeid, tstr)
end end
@ -305,7 +308,7 @@ function _hdf5plot_gwrite(grp, k::String, v) #Default
grp[k] = v grp[k] = v
_hdf5plot_writetype(grp, k, HDF5PlotNative) _hdf5plot_writetype(grp, k, HDF5PlotNative)
end end
function _hdf5plot_gwrite{T<:Number}(grp, k::String, v::Array{T}) #Default for arrays function _hdf5plot_gwrite(grp, k::String, v::Array{T}) where T<:Number #Default for arrays
grp[k] = v grp[k] = v
_hdf5plot_writetype(grp, k, HDF5PlotNative) _hdf5plot_writetype(grp, k, HDF5PlotNative)
end end
@ -355,7 +358,7 @@ function _hdf5plot_gwrite(grp, k::String, v::Colorant)
_hdf5plot_gwrite(grp, k, ARGB{N0f8}(v)) _hdf5plot_gwrite(grp, k, ARGB{N0f8}(v))
end end
#Custom vector (when not using simple numeric type): #Custom vector (when not using simple numeric type):
function _hdf5plot_gwritearray{T}(grp, k::String, v::Array{T}) function _hdf5plot_gwritearray(grp, k::String, v::Array{T}) where T
if "annotations" == k; if "annotations" == k;
return #Hack. Does not yet support annotations. return #Hack. Does not yet support annotations.
end end
@ -380,7 +383,7 @@ function _hdf5plot_gwrite(grp, k::String, v::Extrema)
grp[k] = [v.emin, v.emax] grp[k] = [v.emin, v.emax]
_hdf5plot_writetype(grp, k, Extrema) _hdf5plot_writetype(grp, k, Extrema)
end end
function _hdf5plot_gwrite{T}(grp, k::String, v::Length{T}) function _hdf5plot_gwrite(grp, k::String, v::Length{T}) where T
grp[k] = v.value grp[k] = v.value
_hdf5plot_writetype(grp, k, [HDF5PLOT_MAP_TELEM2STR[Length], string(T)]) _hdf5plot_writetype(grp, k, [HDF5PLOT_MAP_TELEM2STR[Length], string(T)])
end end

View File

@ -13,6 +13,10 @@ Add in functionality to Plots.jl:
:aspect_ratio, :aspect_ratio,
=# =#
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "inspectdr.jl"))
end
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
#TODO: remove features #TODO: remove features
const _inspectdr_attr = merge_with_base_supported([ const _inspectdr_attr = merge_with_base_supported([
@ -28,10 +32,13 @@ const _inspectdr_attr = merge_with_base_supported([
:markerstrokestyle, #Causes warning not to have it... what is this? :markerstrokestyle, #Causes warning not to have it... what is this?
:fillcolor, :fillalpha, #:fillrange, :fillcolor, :fillalpha, #:fillrange,
# :bins, :bar_width, :bar_edges, :bar_position, # :bins, :bar_width, :bar_edges, :bar_position,
:title, :title_location, :titlefont, :title, :title_location,
:window_title, :window_title,
:guide, :lims, :scale, #:ticks, :flip, :rotation, :guide, :lims, :scale, #:ticks, :flip, :rotation,
:tickfont, :guidefont, :legendfont, :titlefontfamily, :titlefontsize, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:grid, :legend, #:colorbar, :grid, :legend, #:colorbar,
# :marker_z, # :marker_z,
# :line_z, # :line_z,
@ -131,7 +138,7 @@ end
function _inspectdr_getscale(s::Symbol, yaxis::Bool) function _inspectdr_getscale(s::Symbol, yaxis::Bool)
#TODO: Support :asinh, :sqrt #TODO: Support :asinh, :sqrt
kwargs = yaxis? (:tgtmajor=>8, :tgtminor=>2): () #More grid lines on y-axis kwargs = yaxis ? (:tgtmajor=>8, :tgtminor=>2) : () #More grid lines on y-axis
if :log2 == s if :log2 == s
return InspectDR.AxisScale(:log2; kwargs...) return InspectDR.AxisScale(:log2; kwargs...)
elseif :log10 == s elseif :log10 == s
@ -163,7 +170,7 @@ function _initialize_backend(::InspectDRBackend; kw...)
2*InspectDR.GLYPH_SQUARE.x, InspectDR.GLYPH_SQUARE.y 2*InspectDR.GLYPH_SQUARE.x, InspectDR.GLYPH_SQUARE.y
) )
type InspecDRPlotRef mutable struct InspecDRPlotRef
mplot::Union{Void, InspectDR.Multiplot} mplot::Union{Void, InspectDR.Multiplot}
gui::Union{Void, InspectDR.GtkPlot} gui::Union{Void, InspectDR.GtkPlot}
end end
@ -172,7 +179,7 @@ function _initialize_backend(::InspectDRBackend; kw...)
_inspectdr_getmplot(r::InspecDRPlotRef) = r.mplot _inspectdr_getmplot(r::InspecDRPlotRef) = r.mplot
_inspectdr_getgui(::Any) = nothing _inspectdr_getgui(::Any) = nothing
_inspectdr_getgui(gplot::InspectDR.GtkPlot) = (gplot.destroyed? nothing: gplot) _inspectdr_getgui(gplot::InspectDR.GtkPlot) = (gplot.destroyed ? nothing : gplot)
_inspectdr_getgui(r::InspecDRPlotRef) = _inspectdr_getgui(r.gui) _inspectdr_getgui(r::InspecDRPlotRef) = _inspectdr_getgui(r.gui)
end end
end end
@ -235,13 +242,13 @@ function _series_added(plt::Plot{InspectDRBackend}, series::Series)
#Don't do anything without a "subplot" object: Will process later. #Don't do anything without a "subplot" object: Will process later.
if nothing == plot; return; end if nothing == plot; return; end
_vectorize(v) = isa(v, Vector)? v: collect(v) #InspectDR only supports vectors _vectorize(v) = isa(v, Vector) ? v : collect(v) #InspectDR only supports vectors
x = _vectorize(series[:x]); y = _vectorize(series[:y]) x = _vectorize(series[:x]); y = _vectorize(series[:y])
#No support for polar grid... but can still perform polar transformation: #No support for polar grid... but can still perform polar transformation:
if ispolar(sp) if ispolar(sp)
Θ = x; r = y Θ = x; r = y
x = r.*cos(Θ); y = r.*sin(Θ) x = r.*cos.(Θ); y = r.*sin.(Θ)
end end
# doesn't handle mismatched x/y - wrap data (pyplot behaviour): # doesn't handle mismatched x/y - wrap data (pyplot behaviour):
@ -278,7 +285,7 @@ For st in :shape:
end end
end end
i = (nmax >= 2? div(nmax, 2): nmax) #Must pick one set of colors for legend i = (nmax >= 2 ? div(nmax, 2) : nmax) #Must pick one set of colors for legend
if i > 1 #Add dummy waveform for legend entry: if i > 1 #Add dummy waveform for legend entry:
linewidth = series[:linewidth] linewidth = series[:linewidth]
linecolor = _inspectdr_mapcolor(_cycle(series[:linecolor], i)) linecolor = _inspectdr_mapcolor(_cycle(series[:linecolor], i))
@ -296,7 +303,7 @@ For st in :shape:
#NOTE: In Plots.jl, :scatter plots have 0-linewidths (I think). #NOTE: In Plots.jl, :scatter plots have 0-linewidths (I think).
linewidth = series[:linewidth] linewidth = series[:linewidth]
#More efficient & allows some support for markerstrokewidth: #More efficient & allows some support for markerstrokewidth:
_style = (0==linewidth? :none: series[:linestyle]) _style = (0==linewidth ? :none : series[:linestyle])
wfrm = InspectDR.add(plot, x, y, id=series[:label]) wfrm = InspectDR.add(plot, x, y, id=series[:label])
wfrm.line = InspectDR.line( wfrm.line = InspectDR.line(
style = _style, style = _style,
@ -369,24 +376,24 @@ function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
l[:frame_canvas].fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot]) l[:frame_canvas].fillcolor = _inspectdr_mapcolor(sp[:background_color_subplot])
l[:frame_data].fillcolor = _inspectdr_mapcolor(sp[:background_color_inside]) l[:frame_data].fillcolor = _inspectdr_mapcolor(sp[:background_color_inside])
l[:frame_data].line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis]) l[:frame_data].line.color = _inspectdr_mapcolor(xaxis[:foreground_color_axis])
l[:font_title] = InspectDR.Font(sp[:titlefont].family, l[:font_title] = InspectDR.Font(sp[:titlefontfamily],
_inspectdr_mapptsize(sp[:titlefont].pointsize), _inspectdr_mapptsize(sp[:titlefontsize]),
color = _inspectdr_mapcolor(sp[:foreground_color_title]) color = _inspectdr_mapcolor(sp[:titlefontcolor])
) )
#Cannot independently control fonts of axes with InspectDR: #Cannot independently control fonts of axes with InspectDR:
l[:font_axislabel] = InspectDR.Font(xaxis[:guidefont].family, l[:font_axislabel] = InspectDR.Font(xaxis[:guidefontfamily],
_inspectdr_mapptsize(xaxis[:guidefont].pointsize), _inspectdr_mapptsize(xaxis[:guidefontsize]),
color = _inspectdr_mapcolor(xaxis[:foreground_color_guide]) color = _inspectdr_mapcolor(xaxis[:guidefontcolor])
) )
l[:font_ticklabel] = InspectDR.Font(xaxis[:tickfont].family, l[:font_ticklabel] = InspectDR.Font(xaxis[:tickfontfamily],
_inspectdr_mapptsize(xaxis[:tickfont].pointsize), _inspectdr_mapptsize(xaxis[:tickfontsize]),
color = _inspectdr_mapcolor(xaxis[:foreground_color_text]) color = _inspectdr_mapcolor(xaxis[:tickfontcolor])
) )
l[:enable_legend] = (sp[:legend] != :none) l[:enable_legend] = (sp[:legend] != :none)
#l[:halloc_legend] = 150 #TODO: compute??? #l[:halloc_legend] = 150 #TODO: compute???
l[:font_legend] = InspectDR.Font(sp[:legendfont].family, l[:font_legend] = InspectDR.Font(sp[:legendfontfamily],
_inspectdr_mapptsize(sp[:legendfont].pointsize), _inspectdr_mapptsize(sp[:legendfontsize]),
color = _inspectdr_mapcolor(sp[:foreground_color_legend]) color = _inspectdr_mapcolor(sp[:legendfontcolor])
) )
l[:frame_legend].fillcolor = _inspectdr_mapcolor(sp[:background_color_legend]) l[:frame_legend].fillcolor = _inspectdr_mapcolor(sp[:background_color_legend])
end end

View File

@ -2,6 +2,10 @@
# significant contributions by: @pkofod # significant contributions by: @pkofod
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "pgfplots.jl"))
end
const _pgfplots_attr = merge_with_base_supported([ const _pgfplots_attr = merge_with_base_supported([
:annotations, :annotations,
# :background_color_legend, # :background_color_legend,
@ -32,10 +36,12 @@ const _pgfplots_attr = merge_with_base_supported([
:aspect_ratio, :aspect_ratio,
# :match_dimensions, # :match_dimensions,
:tick_direction, :tick_direction,
:framestyle,
:camera,
]) ])
const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape] const _pgfplots_seriestype = [:path, :path3d, :scatter, :steppre, :stepmid, :steppost, :histogram2d, :ysticks, :xsticks, :contour, :shape]
const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot] const _pgfplots_style = [:auto, :solid, :dash, :dot, :dashdot, :dashdotdot]
const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon] #vcat(_allMarkers, Shape) const _pgfplots_marker = [:none, :auto, :circle, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5, :pentagon, :hline] #vcat(_allMarkers, Shape)
const _pgfplots_scale = [:identity, :ln, :log2, :log10] const _pgfplots_scale = [:identity, :ln, :log2, :log10]
@ -80,6 +86,7 @@ const _pgfplots_markers = KW(
:star6 => "asterisk", :star6 => "asterisk",
:diamond => "diamond*", :diamond => "diamond*",
:pentagon => "pentagon*", :pentagon => "pentagon*",
:hline => "-"
) )
const _pgfplots_legend_pos = KW( const _pgfplots_legend_pos = KW(
@ -87,6 +94,7 @@ const _pgfplots_legend_pos = KW(
:bottomright => "south east", :bottomright => "south east",
:topright => "north east", :topright => "north east",
:topleft => "north west", :topleft => "north west",
:outertopright => "outer north east",
) )
@ -107,6 +115,18 @@ const _pgf_annotation_halign = KW(
:right => "left" :right => "left"
) )
const _pgf_framestyles = [:box, :axes, :origin, :zerolines, :grid, :none]
const _pgf_framestyle_defaults = Dict(:semi => :box)
function pgf_framestyle(style::Symbol)
if style in _pgf_framestyles
return style
else
default_style = get(_pgf_framestyle_defaults, style, :axes)
warn("Framestyle :$style is not (yet) supported by the PGFPlots backend. :$default_style was cosen instead.")
default_style
end
end
# -------------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------
# takes in color,alpha, and returns color and alpha appropriate for pgf style # takes in color,alpha, and returns color and alpha appropriate for pgf style
@ -188,6 +208,9 @@ function pgf_series(sp::Subplot, series::Series)
# add to legend? # add to legend?
if sp[:legend] != :none && should_add_to_legend(series) if sp[:legend] != :none && should_add_to_legend(series)
kw[:legendentry] = d[:label] kw[:legendentry] = d[:label]
if st == :shape || d[:fillrange] != nothing
push!(style, "area legend")
end
else else
push!(style, "forget plot") push!(style, "forget plot")
end end
@ -201,6 +224,9 @@ function pgf_series(sp::Subplot, series::Series)
# If a marker_z is used pass it as third coordinate to a 2D plot. # If a marker_z is used pass it as third coordinate to a 2D plot.
# See "Scatter Plots" in PGFPlots documentation # See "Scatter Plots" in PGFPlots documentation
d[:x], d[:y], d[:marker_z] d[:x], d[:y], d[:marker_z]
elseif ispolar(sp)
theta, r = filter_radial_data(d[:x], d[:y], axis_limits(sp[:yaxis]))
rad2deg.(theta), r
else else
d[:x], d[:y] d[:x], d[:y]
end end
@ -246,6 +272,9 @@ function pgf_axis(sp::Subplot, letter)
style = [] style = []
kw = KW() kw = KW()
# set to supported framestyle
framestyle = pgf_framestyle(sp[:framestyle])
# axis guide # axis guide
kw[Symbol(letter,:label)] = axis[:guide] kw[Symbol(letter,:label)] = axis[:guide]
@ -263,30 +292,67 @@ function pgf_axis(sp::Subplot, letter)
end end
# ticks on or off # ticks on or off
if axis[:ticks] in (nothing, false) if axis[:ticks] in (nothing, false) || framestyle == :none
push!(style, "$(letter)majorticks=false") push!(style, "$(letter)majorticks=false")
end end
# grid on or off # grid on or off
if axis[:grid] if axis[:grid] && framestyle != :none
push!(style, "$(letter)majorgrids = true") push!(style, "$(letter)majorgrids = true")
else
push!(style, "$(letter)majorgrids = false")
end end
# limits # limits
# TODO: support zlims # TODO: support zlims
if letter != :z if letter != :z
lims = axis_limits(axis) lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(axis)) : axis_limits(axis)
kw[Symbol(letter,:min)] = lims[1] kw[Symbol(letter,:min)] = lims[1]
kw[Symbol(letter,:max)] = lims[2] kw[Symbol(letter,:max)] = lims[2]
end end
if !(axis[:ticks] in (nothing, false, :none)) if !(axis[:ticks] in (nothing, false, :none)) && framestyle != :none
ticks = get_ticks(axis) ticks = get_ticks(axis)
push!(style, string(letter, "tick = {", join(ticks[1],","), "}")) #pgf plot ignores ticks with angle below 90 when xmin = 90 so shift values
push!(style, string(letter, "ticklabels = {", join(ticks[2],","), "}")) tick_values = ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 405] : ticks[1]
push!(style, string(letter, "tick = {", join(tick_values,","), "}"))
if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto
# wrap the power part of label with }
tick_labels = String[begin
base, power = split(label, "^")
power = string("{", power, "}")
string(base, "^", power)
end for label in ticks[2]]
push!(style, string(letter, "ticklabels = {\$", join(tick_labels,"\$,\$"), "\$}"))
elseif axis[:showaxis]
tick_labels = ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2]
push!(style, string(letter, "ticklabels = {", join(tick_labels,","), "}"))
else
push!(style, string(letter, "ticklabels = {}"))
end
push!(style, string(letter, "tick align = ", (axis[:tick_direction] == :out ? "outside" : "inside"))) push!(style, string(letter, "tick align = ", (axis[:tick_direction] == :out ? "outside" : "inside")))
end end
# framestyle
if framestyle in (:axes, :origin)
axispos = framestyle == :axes ? "left" : "middle"
# the * after lines disables the arrows at the axes
push!(style, string("axis lines* = ", axispos))
end
if framestyle == :zerolines
push!(style, string("extra ", letter, " ticks = 0"))
push!(style, string("extra ", letter, " tick labels = "))
push!(style, string("extra ", letter, " tick style = {grid = major, major grid style = {color = black, draw opacity=1.0, line width=0.5), solid}}"))
end
if !axis[:showaxis]
push!(style, "separate axis lines")
end
if !axis[:showaxis] || framestyle in (:zerolines, :grid, :none)
push!(style, string(letter, " axis line style = {draw opacity = 0}"))
end
# return the style list and KW args # return the style list and KW args
style, kw style, kw
end end
@ -340,9 +406,17 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
kw[:legendPos] = _pgfplots_legend_pos[legpos] kw[:legendPos] = _pgfplots_legend_pos[legpos]
end end
if is3d(sp)
azim, elev = sp[:camera]
kw[:view] = "{$(azim)}{$(elev)}"
end
axisf = PGFPlots.Axis axisf = PGFPlots.Axis
if sp[:projection] == :polar if sp[:projection] == :polar
axisf = PGFPlots.PolarAxis axisf = PGFPlots.PolarAxis
#make radial axis vertical
kw[:xmin] = 90
kw[:xmax] = 450
end end
# Search series for any gradient. In case one series uses a gradient set # Search series for any gradient. In case one series uses a gradient set

View File

@ -1,6 +1,10 @@
# https://plot.ly/javascript/getting-started # https://plot.ly/javascript/getting-started
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "plotly.jl"))
end
const _plotly_attr = merge_with_base_supported([ const _plotly_attr = merge_with_base_supported([
:annotations, :annotations,
:background_color_legend, :background_color_inside, :background_color_outside, :background_color_legend, :background_color_inside, :background_color_outside,
@ -15,7 +19,12 @@ const _plotly_attr = merge_with_base_supported([
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle, :markerstrokewidth, :markerstrokecolor, :markerstrokealpha, :markerstrokestyle,
:fillrange, :fillcolor, :fillalpha, :fillrange, :fillcolor, :fillalpha,
:bins, :bins,
:title, :title_location, :titlefont, :title, :title_location,
:titlefontfamily, :titlefontsize, :titlefonthalign, :titlefontvalign,
:titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:window_title, :window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation, :guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont, :tickfont, :guidefont, :legendfont,
@ -35,6 +44,7 @@ const _plotly_attr = merge_with_base_supported([
:clims, :clims,
:framestyle, :framestyle,
:tick_direction, :tick_direction,
:camera,
]) ])
const _plotly_seriestype = [ const _plotly_seriestype = [
@ -121,7 +131,7 @@ const _plotly_legend_pos = KW(
) )
plotly_legend_pos(pos::Symbol) = get(_plotly_legend_pos, pos, [1.,1.]) plotly_legend_pos(pos::Symbol) = get(_plotly_legend_pos, pos, [1.,1.])
plotly_legend_pos{S<:Real, T<:Real}(v::Tuple{S,T}) = v plotly_legend_pos(v::Tuple{S,T}) where {S<:Real, T<:Real} = v
function plotly_font(font::Font, color = font.color) function plotly_font(font::Font, color = font.color)
KW( KW(
@ -234,10 +244,11 @@ function plotly_axis(axis::Axis, sp::Subplot)
:gridwidth => axis[:gridlinewidth], :gridwidth => axis[:gridlinewidth],
:zeroline => framestyle == :zerolines, :zeroline => framestyle == :zerolines,
:zerolinecolor => rgba_string(axis[:foreground_color_axis]), :zerolinecolor => rgba_string(axis[:foreground_color_axis]),
:showline => framestyle in (:box, :axes), :showline => framestyle in (:box, :axes) && axis[:showaxis],
:linecolor => rgba_string(plot_color(axis[:foreground_color_axis])), :linecolor => rgba_string(plot_color(axis[:foreground_color_axis])),
:ticks => axis[:tick_direction] == :out ? "outside" : "inside", :ticks => axis[:tick_direction] == :out ? "outside" : "inside",
:mirror => framestyle == :box, :mirror => framestyle == :box,
:showticklabels => axis[:showaxis],
) )
if letter in (:x,:y) if letter in (:x,:y)
@ -246,20 +257,16 @@ function plotly_axis(axis::Axis, sp::Subplot)
end end
ax[:tickangle] = -axis[:rotation] ax[:tickangle] = -axis[:rotation]
lims = axis_limits(axis)
ax[:range] = map(scalefunc(axis[:scale]), lims)
if !(axis[:ticks] in (nothing, :none)) if !(axis[:ticks] in (nothing, :none))
ax[:titlefont] = plotly_font(axis[:guidefont], axis[:foreground_color_guide]) ax[:titlefont] = plotly_font(guidefont(axis))
ax[:type] = plotly_scale(axis[:scale]) ax[:type] = plotly_scale(axis[:scale])
ax[:tickfont] = plotly_font(axis[:tickfont], axis[:foreground_color_text]) ax[:tickfont] = plotly_font(tickfont(axis))
ax[:tickcolor] = framestyle in (:zerolines, :grid) ? rgba_string(invisible()) : rgb_string(axis[:foreground_color_axis]) ax[:tickcolor] = framestyle in (:zerolines, :grid) || !axis[:showaxis] ? rgba_string(invisible()) : rgb_string(axis[:foreground_color_axis])
ax[:linecolor] = rgba_string(axis[:foreground_color_axis]) ax[:linecolor] = rgba_string(axis[:foreground_color_axis])
# lims
lims = axis[:lims]
if lims != :auto && limsType(lims) == :limits
ax[:range] = map(scalefunc(axis[:scale]), lims)
end
# flip # flip
if axis[:flip] if axis[:flip]
ax[:autorange] = "reversed" ax[:autorange] = "reversed"
@ -282,6 +289,23 @@ function plotly_axis(axis::Axis, sp::Subplot)
ax[:showgrid] = false ax[:showgrid] = false
end end
ax
end
function plotly_polaraxis(axis::Axis)
ax = KW(
:visible => axis[:showaxis],
:showline => axis[:grid],
)
if axis[:letter] == :x
ax[:range] = rad2deg.(axis_limits(axis))
else
ax[:range] = axis_limits(axis)
ax[:orientation] = -90
end
ax ax
end end
@ -312,8 +336,8 @@ function plotly_layout(plt::Plot)
0.5 * (left(bb) + right(bb)) 0.5 * (left(bb) + right(bb))
end end
titlex, titley = xy_mm_to_pcts(xmm, top(bbox(sp)), w*px, h*px) titlex, titley = xy_mm_to_pcts(xmm, top(bbox(sp)), w*px, h*px)
titlefont = font(sp[:titlefont], :top, sp[:foreground_color_title]) title_font = font(titlefont(sp), :top)
push!(d_out[:annotations], plotly_annotation_dict(titlex, titley, text(sp[:title], titlefont))) push!(d_out[:annotations], plotly_annotation_dict(titlex, titley, text(sp[:title], title_font)))
end end
d_out[:plot_bgcolor] = rgba_string(sp[:background_color_inside]) d_out[:plot_bgcolor] = rgba_string(sp[:background_color_inside])
@ -323,11 +347,25 @@ function plotly_layout(plt::Plot)
# if any(is3d, seriesargs) # if any(is3d, seriesargs)
if is3d(sp) if is3d(sp)
azim = sp[:camera][1] - 90 #convert azimuthal to match GR behaviour
theta = 90 - sp[:camera][2] #spherical coordinate angle from z axis
d_out[:scene] = KW( d_out[:scene] = KW(
Symbol("xaxis$spidx") => plotly_axis(sp[:xaxis], sp), Symbol("xaxis$spidx") => plotly_axis(sp[:xaxis], sp),
Symbol("yaxis$spidx") => plotly_axis(sp[:yaxis], sp), Symbol("yaxis$spidx") => plotly_axis(sp[:yaxis], sp),
Symbol("zaxis$spidx") => plotly_axis(sp[:zaxis], sp), Symbol("zaxis$spidx") => plotly_axis(sp[:zaxis], sp),
#2.6 multiplier set camera eye such that whole plot can be seen
:camera => KW(
:eye => KW(
:x => cosd(azim)*sind(theta)*2.6,
:y => sind(azim)*sind(theta)*2.6,
:z => cosd(theta)*2.6,
),
),
) )
elseif ispolar(sp)
d_out[Symbol("angularaxis$spidx")] = plotly_polaraxis(sp[:xaxis])
d_out[Symbol("radialaxis$spidx")] = plotly_polaraxis(sp[:yaxis])
else else
d_out[Symbol("xaxis$spidx")] = plotly_axis(sp[:xaxis], sp) d_out[Symbol("xaxis$spidx")] = plotly_axis(sp[:xaxis], sp)
d_out[Symbol("yaxis$spidx")] = plotly_axis(sp[:yaxis], sp) d_out[Symbol("yaxis$spidx")] = plotly_axis(sp[:yaxis], sp)
@ -340,7 +378,7 @@ function plotly_layout(plt::Plot)
d_out[:legend] = KW( d_out[:legend] = KW(
:bgcolor => rgba_string(sp[:background_color_legend]), :bgcolor => rgba_string(sp[:background_color_legend]),
:bordercolor => rgba_string(sp[:foreground_color_legend]), :bordercolor => rgba_string(sp[:foreground_color_legend]),
:font => plotly_font(sp[:legendfont], sp[:foreground_color_legend]), :font => plotly_font(legendfont(sp)),
:x => xpos, :x => xpos,
:y => ypos :y => ypos
) )
@ -428,7 +466,7 @@ end
plotly_data(v) = collect(v) plotly_data(v) = collect(v)
plotly_data(surf::Surface) = surf.surf plotly_data(surf::Surface) = surf.surf
plotly_data{R<:Rational}(v::AbstractArray{R}) = float(v) plotly_data(v::AbstractArray{R}) where {R<:Rational} = float(v)
plotly_surface_data(series::Series, a::AbstractVector) = a plotly_surface_data(series::Series, a::AbstractVector) = a
plotly_surface_data(series::Series, a::AbstractMatrix) = transpose_z(series, a, false) plotly_surface_data(series::Series, a::AbstractMatrix) = transpose_z(series, a, false)
@ -509,7 +547,7 @@ function plotly_series(plt::Plot, series::Series)
d_out[:type] = "heatmap" d_out[:type] = "heatmap"
# d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false) # d_out[:x], d_out[:y], d_out[:z] = series[:x], series[:y], transpose_z(series, series[:z].surf, false)
d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha]) d_out[:colorscale] = plotly_colorscale(series[:fillcolor], series[:fillalpha])
d_out[:showscale] = sp[:legend] != :none d_out[:showscale] = hascolorbar(sp)
elseif st == :contour elseif st == :contour
d_out[:type] = "contour" d_out[:type] = "contour"
@ -518,7 +556,7 @@ function plotly_series(plt::Plot, series::Series)
d_out[:ncontours] = series[:levels] d_out[:ncontours] = series[:levels]
d_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines") d_out[:contours] = KW(:coloring => series[:fillrange] != nothing ? "fill" : "lines")
d_out[:colorscale] = plotly_colorscale(series[:linecolor], series[:linealpha]) d_out[:colorscale] = plotly_colorscale(series[:linecolor], series[:linealpha])
d_out[:showscale] = sp[:legend] != :none d_out[:showscale] = hascolorbar(sp)
elseif st in (:surface, :wireframe) elseif st in (:surface, :wireframe)
d_out[:type] = "surface" d_out[:type] = "surface"
@ -538,7 +576,7 @@ function plotly_series(plt::Plot, series::Series)
if series[:fill_z] != nothing if series[:fill_z] != nothing
d_out[:surfacecolor] = plotly_surface_data(series, series[:fill_z]) d_out[:surfacecolor] = plotly_surface_data(series, series[:fill_z])
end end
d_out[:showscale] = sp[:legend] != :none d_out[:showscale] = hascolorbar(sp)
end end
elseif st == :pie elseif st == :pie
@ -681,8 +719,9 @@ end
function plotly_polar!(d_out::KW, series::Series) function plotly_polar!(d_out::KW, series::Series)
# convert polar plots x/y to theta/radius # convert polar plots x/y to theta/radius
if ispolar(series[:subplot]) if ispolar(series[:subplot])
d_out[:t] = rad2deg(pop!(d_out, :x)) theta, r = filter_radial_data(pop!(d_out, :x), pop!(d_out, :y), axis_limits(series[:subplot][:yaxis]))
d_out[:r] = pop!(d_out, :y) d_out[:t] = rad2deg.(theta)
d_out[:r] = r
end end
end end
@ -711,7 +750,7 @@ end
const _use_remote = Ref(false) const _use_remote = Ref(false)
function html_head(plt::Plot{PlotlyBackend}) function html_head(plt::Plot{PlotlyBackend})
jsfilename = _use_remote[] ? _plotly_js_path_remote : _plotly_js_path jsfilename = _use_remote[] ? _plotly_js_path_remote : ("file://" * _plotly_js_path)
# "<script src=\"$(joinpath(dirname(@__FILE__),"..","..","deps","plotly-latest.min.js"))\"></script>" # "<script src=\"$(joinpath(dirname(@__FILE__),"..","..","deps","plotly-latest.min.js"))\"></script>"
"<script src=\"$jsfilename\"></script>" "<script src=\"$jsfilename\"></script>"
end end

View File

@ -1,3 +1,6 @@
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "plotlyjs.jl"))
end
# https://github.com/spencerlyon2/PlotlyJS.jl # https://github.com/spencerlyon2/PlotlyJS.jl
@ -85,7 +88,8 @@ end
# ---------------------------------------------------------------- # ----------------------------------------------------------------
function _show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend}) function Base.show(io::IO, ::MIME"text/html", plt::Plot{PlotlyJSBackend})
prepare_output(plt)
if isijulia() && !_use_remote[] if isijulia() && !_use_remote[]
write(io, PlotlyJS.html_body(PlotlyJS.JupyterPlot(plt.o))) write(io, PlotlyJS.html_body(PlotlyJS.JupyterPlot(plt.o)))
else else
@ -98,6 +102,7 @@ function plotlyjs_save_hack(io::IO, plt::Plot{PlotlyJSBackend}, ext::String)
PlotlyJS.savefig(plt.o, tmpfn) PlotlyJS.savefig(plt.o, tmpfn)
write(io, read(open(tmpfn))) write(io, read(open(tmpfn)))
end end
_show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "svg")
_show(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "png") _show(io::IO, ::MIME"image/png", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "png")
_show(io::IO, ::MIME"application/pdf", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "pdf") _show(io::IO, ::MIME"application/pdf", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "pdf")
_show(io::IO, ::MIME"image/eps", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "eps") _show(io::IO, ::MIME"image/eps", plt::Plot{PlotlyJSBackend}) = plotlyjs_save_hack(io, plt, "eps")

View File

@ -1,6 +1,9 @@
# https://github.com/stevengj/PyPlot.jl # https://github.com/stevengj/PyPlot.jl
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "pyplot.jl"))
end
const _pyplot_attr = merge_with_base_supported([ const _pyplot_attr = merge_with_base_supported([
:annotations, :annotations,
@ -16,7 +19,10 @@ const _pyplot_attr = merge_with_base_supported([
:title, :title_location, :titlefont, :title, :title_location, :titlefont,
:window_title, :window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation, :guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont, :titlefontfamily, :titlefontsize, :titlefontcolor,
:legendfontfamily, :legendfontsize, :legendfontcolor,
:tickfontfamily, :tickfontsize, :tickfontcolor,
:guidefontfamily, :guidefontsize, :guidefontcolor,
:grid, :gridalpha, :gridstyle, :gridlinewidth, :grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar, :legend, :legendtitle, :colorbar,
:marker_z, :line_z, :fill_z, :marker_z, :line_z, :fill_z,
@ -35,6 +41,7 @@ const _pyplot_attr = merge_with_base_supported([
:stride, :stride,
:framestyle, :framestyle,
:tick_direction, :tick_direction,
:camera,
]) ])
const _pyplot_seriestype = [ const _pyplot_seriestype = [
:path, :steppre, :steppost, :shape, :path, :steppre, :steppost, :shape,
@ -124,6 +131,7 @@ end
# # anything else just gets a bluesred gradient # # anything else just gets a bluesred gradient
# py_colormap(c, α=nothing) = py_colormap(default_gradient(), α) # py_colormap(c, α=nothing) = py_colormap(default_gradient(), α)
py_color(s) = py_color(parse(Colorant, string(s)))
py_color(c::Colorant) = (red(c), green(c), blue(c), alpha(c)) py_color(c::Colorant) = (red(c), green(c), blue(c), alpha(c))
py_color(cs::AVec) = map(py_color, cs) py_color(cs::AVec) = map(py_color, cs)
py_color(grad::ColorGradient) = py_color(grad.colors) py_color(grad::ColorGradient) = py_color(grad.colors)
@ -499,20 +507,19 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
:zorder => plt.n, :zorder => plt.n,
:cmap => py_linecolormap(series), :cmap => py_linecolormap(series),
:linewidth => py_dpi_scale(plt, series[:linewidth]), :linewidth => py_dpi_scale(plt, series[:linewidth]),
:linestyle => py_linestyle(st, series[:linestyle]) :linestyle => py_linestyle(st, series[:linestyle]),
:norm => pycolors["Normalize"](; extrakw...)
) )
if needs_colorbar lz = _cycle(series[:line_z], 1:n)
kw[:norm] = pycolors["Normalize"](; extrakw...)
end
lz = collect(series[:line_z])
handle = if is3d(st) handle = if is3d(st)
for rng in iter_segments(x, y, z) for rng in iter_segments(x, y, z)
length(rng) < 2 && continue length(rng) < 2 && continue
push!(segments, [(_cycle(x,i),_cycle(y,i),_cycle(z,i)) for i in rng]) for i in rng[1:end-1]
push!(segments, [(_cycle(x,i),_cycle(y,i),_cycle(z,i)),
(_cycle(x,i+1),_cycle(y,i+1),_cycle(z,i+1))])
end
end end
# for i=1:n
# segments[i] = [(_cycle(x,i), _cycle(y,i), _cycle(z,i)), (_cycle(x,i+1), _cycle(y,i+1), _cycle(z,i+1))]
# end
lc = pyart3d["Line3DCollection"](segments; kw...) lc = pyart3d["Line3DCollection"](segments; kw...)
lc[:set_array](lz) lc[:set_array](lz)
ax[:add_collection3d](lc, zs=z) #, zdir='y') ax[:add_collection3d](lc, zs=z) #, zdir='y')
@ -520,11 +527,11 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
else else
for rng in iter_segments(x, y) for rng in iter_segments(x, y)
length(rng) < 2 && continue length(rng) < 2 && continue
push!(segments, [(_cycle(x,i),_cycle(y,i)) for i in rng]) for i in rng[1:end-1]
push!(segments, [(_cycle(x,i),_cycle(y,i)), (_cycle(x,i+1),_cycle(y,i+1))])
end
end end
# for i=1:n
# segments[i] = [(_cycle(x,i), _cycle(y,i)), (_cycle(x,i+1), _cycle(y,i+1))]
# end
lc = pycollections["LineCollection"](segments; kw...) lc = pycollections["LineCollection"](segments; kw...)
lc[:set_array](lz) lc[:set_array](lz)
ax[:add_collection](lc) ax[:add_collection](lc)
@ -917,11 +924,11 @@ function py_set_axis_colors(sp, ax, a::Axis)
end end
axissym = Symbol(a[:letter], :axis) axissym = Symbol(a[:letter], :axis)
if haskey(ax, axissym) if haskey(ax, axissym)
tickcolor = sp[:framestyle] == :zerolines ? py_color(plot_color(a[:foreground_color_grid], a[:gridalpha])) : py_color(a[:foreground_color_axis]) tickcolor = sp[:framestyle] in (:zerolines, :grid) ? py_color(plot_color(a[:foreground_color_grid], a[:gridalpha])) : py_color(a[:foreground_color_axis])
ax[:tick_params](axis=string(a[:letter]), which="both", ax[:tick_params](axis=string(a[:letter]), which="both",
colors=tickcolor, colors=tickcolor,
labelcolor=py_color(a[:foreground_color_text])) labelcolor=py_color(a[:tickfontcolor]))
ax[axissym][:label][:set_color](py_color(a[:foreground_color_guide])) ax[axissym][:label][:set_color](py_color(a[:guidefontcolor]))
end end
end end
@ -975,9 +982,9 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
:title :title
end end
ax[func][:set_text](sp[:title]) ax[func][:set_text](sp[:title])
ax[func][:set_fontsize](py_dpi_scale(plt, sp[:titlefont].pointsize)) ax[func][:set_fontsize](py_dpi_scale(plt, sp[:titlefontsize]))
ax[func][:set_family](sp[:titlefont].family) ax[func][:set_family](sp[:titlefontfamily])
ax[func][:set_color](py_color(sp[:foreground_color_title])) ax[func][:set_color](py_color(sp[:titlefontcolor]))
# ax[:set_title](sp[:title], loc = loc) # ax[:set_title](sp[:title], loc = loc)
end end
@ -1002,7 +1009,12 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
fig = plt.o fig = plt.o
cbax = fig[:add_axes]([0.8,0.1,0.03,0.8], label = string(gensym())) cbax = fig[:add_axes]([0.8,0.1,0.03,0.8], label = string(gensym()))
cb = fig[:colorbar](handle; cax = cbax, kw...) cb = fig[:colorbar](handle; cax = cbax, kw...)
cb[:set_label](sp[:colorbar_title]) cb[:set_label](sp[:colorbar_title],size=py_dpi_scale(plt, sp[:yaxis][:guidefontsize]),family=sp[:yaxis][:guidefontfamily], color = py_color(sp[:yaxis][:guidefontcolor]))
for lab in cb[:ax][:yaxis][:get_ticklabels]()
lab[:set_fontsize](py_dpi_scale(plt, sp[:yaxis][:tickfontsize]))
lab[:set_family](sp[:yaxis][:tickfontfamily])
lab[:set_color](py_color(sp[:yaxis][:tickfontcolor]))
end
sp.attr[:cbar_handle] = cb sp.attr[:cbar_handle] = cb
sp.attr[:cbar_ax] = cbax sp.attr[:cbar_ax] = cbax
end end
@ -1047,6 +1059,9 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
end end
py_set_scale(ax, axis) py_set_scale(ax, axis)
py_set_lims(ax, axis) py_set_lims(ax, axis)
if ispolar(sp) && letter == :y
ax[:set_rlabel_position](90)
end
ticks = sp[:framestyle] == :none ? nothing : get_ticks(axis) ticks = sp[:framestyle] == :none ? nothing : get_ticks(axis)
# don't show the 0 tick label for the origin framestyle # don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && length(ticks) > 1 if sp[:framestyle] == :origin && length(ticks) > 1
@ -1058,11 +1073,11 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
if get(axis.d, :flip, false) if get(axis.d, :flip, false)
ax[Symbol("invert_", letter, "axis")]() ax[Symbol("invert_", letter, "axis")]()
end end
pyaxis[:label][:set_fontsize](py_dpi_scale(plt, axis[:guidefont].pointsize)) pyaxis[:label][:set_fontsize](py_dpi_scale(plt, axis[:guidefontsize]))
pyaxis[:label][:set_family](axis[:guidefont].family) pyaxis[:label][:set_family](axis[:guidefontfamily])
for lab in ax[Symbol("get_", letter, "ticklabels")]() for lab in ax[Symbol("get_", letter, "ticklabels")]()
lab[:set_fontsize](py_dpi_scale(plt, axis[:tickfont].pointsize)) lab[:set_fontsize](py_dpi_scale(plt, axis[:tickfontsize]))
lab[:set_family](axis[:tickfont].family) lab[:set_family](axis[:tickfontfamily])
lab[:set_rotation](axis[:rotation]) lab[:set_rotation](axis[:rotation])
end end
if axis[:grid] && !(ticks in (:none, nothing, false)) if axis[:grid] && !(ticks in (:none, nothing, false))
@ -1073,16 +1088,49 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
linewidth = axis[:gridlinewidth], linewidth = axis[:gridlinewidth],
alpha = axis[:gridalpha]) alpha = axis[:gridalpha])
ax[:set_axisbelow](true) ax[:set_axisbelow](true)
else
pyaxis[:grid](false)
end end
py_set_axis_colors(sp, ax, axis) py_set_axis_colors(sp, ax, axis)
end end
# showaxis
if !sp[:xaxis][:showaxis]
kw = KW()
for dir in (:top, :bottom)
if ispolar(sp)
ax[:spines]["polar"][:set_visible](false)
else
ax[:spines][string(dir)][:set_visible](false)
end
kw[dir] = kw[Symbol(:label,dir)] = "off"
end
ax[:xaxis][:set_tick_params](; which="both", kw...)
end
if !sp[:yaxis][:showaxis]
kw = KW()
for dir in (:left, :right)
if !ispolar(sp)
ax[:spines][string(dir)][:set_visible](false)
end
kw[dir] = kw[Symbol(:label,dir)] = "off"
end
ax[:yaxis][:set_tick_params](; which="both", kw...)
end
# aspect ratio # aspect ratio
aratio = sp[:aspect_ratio] aratio = sp[:aspect_ratio]
if aratio != :none if aratio != :none
ax[:set_aspect](isa(aratio, Symbol) ? string(aratio) : aratio, anchor = "C") ax[:set_aspect](isa(aratio, Symbol) ? string(aratio) : aratio, anchor = "C")
end end
#camera/view angle
if is3d(sp)
#convert azimuthal to match GR behaviour
#view_init(elevation, azimuthal) so reverse :camera args
ax[:view_init]((sp[:camera].-(90,0))[end:-1:1]...)
end
# legend # legend
py_add_legend(plt, sp, ax) py_add_legend(plt, sp, ax)
@ -1178,10 +1226,19 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
for series in series_list(sp) for series in series_list(sp)
if should_add_to_legend(series) if should_add_to_legend(series)
# add a line/marker and a label # add a line/marker and a label
push!(handles, if series[:seriestype] == :shape push!(handles, if series[:seriestype] == :shape || series[:fillrange] != nothing
pypatches[:Patch](
edgecolor = py_color(_cycle(series[:linecolor],1)),
facecolor = py_color(_cycle(series[:fillcolor],1)),
linewidth = py_dpi_scale(plt, clamp(series[:linewidth], 0, 5)),
)
elseif series[:seriestype] == :path
PyPlot.plt[:Line2D]((0,1),(0,0), PyPlot.plt[:Line2D]((0,1),(0,0),
color = py_color(_cycle(series[:fillcolor],1)), color = py_color(_cycle(series[:fillcolor],1)),
linewidth = py_dpi_scale(plt, 4) linewidth = py_dpi_scale(plt, clamp(series[:linewidth], 0, 5)),
marker = py_marker(series[:markershape]),
markeredgecolor = py_markerstrokecolor(series),
markerfacecolor = py_markercolor(series)
) )
else else
series[:serieshandle][1] series[:serieshandle][1]
@ -1196,7 +1253,7 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
labels, labels,
loc = get(_pyplot_legend_pos, leg, "best"), loc = get(_pyplot_legend_pos, leg, "best"),
scatterpoints = 1, scatterpoints = 1,
fontsize = py_dpi_scale(plt, sp[:legendfont].pointsize) fontsize = py_dpi_scale(plt, sp[:legendfontsize])
# family = sp[:legendfont].family # family = sp[:legendfont].family
# framealpha = 0.6 # framealpha = 0.6
) )
@ -1204,8 +1261,9 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
sp[:legendtitle] != nothing && leg[:set_title](sp[:legendtitle]) sp[:legendtitle] != nothing && leg[:set_title](sp[:legendtitle])
fgcolor = py_color(sp[:foreground_color_legend]) fgcolor = py_color(sp[:foreground_color_legend])
lfcolor = py_color(sp[:legendfontcolor])
for txt in leg[:get_texts]() for txt in leg[:get_texts]()
PyPlot.plt[:setp](txt, color = fgcolor, family = sp[:legendfont].family) PyPlot.plt[:setp](txt, color = lfcolor, family = sp[:legendfontfamily])
end end
# set some legend properties # set some legend properties

View File

@ -1,6 +1,10 @@
# https://github.com/Evizero/UnicodePlots.jl # https://github.com/Evizero/UnicodePlots.jl
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "unicodeplots.jl"))
end
const _unicodeplots_attr = merge_with_base_supported([ const _unicodeplots_attr = merge_with_base_supported([
:label, :label,
:legend, :legend,

View File

@ -2,7 +2,9 @@
# NOTE: backend should implement `html_body` and `html_head` # NOTE: backend should implement `html_body` and `html_head`
# CREDIT: parts of this implementation were inspired by @joshday's PlotlyLocal.jl # CREDIT: parts of this implementation were inspired by @joshday's PlotlyLocal.jl
@require Revise begin
Revise.track(Plots, joinpath(Pkg.dir("Plots"), "src", "backends", "web.jl"))
end
function standalone_html(plt::AbstractPlot; title::AbstractString = get(plt.attr, :window_title, "Plots.jl")) function standalone_html(plt::AbstractPlot; title::AbstractString = get(plt.attr, :window_title, "Plots.jl"))
""" """

View File

@ -11,7 +11,7 @@ compute_angle(v::P2) = (angle = atan2(v[2], v[1]); angle < 0 ? 2π - angle : ang
# ------------------------------------------------------------- # -------------------------------------------------------------
immutable Shape struct Shape
x::Vector{Float64} x::Vector{Float64}
y::Vector{Float64} y::Vector{Float64}
# function Shape(x::AVec, y::AVec) # function Shape(x::AVec, y::AVec)
@ -246,7 +246,7 @@ end
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
type Font mutable struct Font
family::AbstractString family::AbstractString
pointsize::Int pointsize::Int
halign::Symbol halign::Symbol
@ -336,7 +336,7 @@ function scalefontsizes()
end end
"Wrap a string with font info" "Wrap a string with font info"
immutable PlotText struct PlotText
str::AbstractString str::AbstractString
font::Font font::Font
end end
@ -359,7 +359,7 @@ Base.length(t::PlotText) = length(t.str)
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
immutable Stroke struct Stroke
width width
color color
alpha alpha
@ -401,7 +401,7 @@ function stroke(args...; alpha = nothing)
end end
immutable Brush struct Brush
size # fillrange, markersize, or any other sizey attribute size # fillrange, markersize, or any other sizey attribute
color color
alpha alpha
@ -434,7 +434,7 @@ end
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
type SeriesAnnotations mutable struct SeriesAnnotations
strs::AbstractVector # the labels/names strs::AbstractVector # the labels/names
font::Font font::Font
baseshape::Nullable baseshape::Nullable
@ -513,7 +513,7 @@ function series_annotations_shapes!(series::Series, scaletype::Symbol = :pixels)
return return
end end
type EachAnn mutable struct EachAnn
anns anns
x x
y y
@ -538,12 +538,12 @@ annotations(sa::SeriesAnnotations) = sa
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
"type which represents z-values for colors and sizes (and anything else that might come up)" "type which represents z-values for colors and sizes (and anything else that might come up)"
immutable ZValues struct ZValues
values::Vector{Float64} values::Vector{Float64}
zrange::Tuple{Float64,Float64} zrange::Tuple{Float64,Float64}
end end
function zvalues{T<:Real}(values::AVec{T}, zrange::Tuple{T,T} = (ignorenan_minimum(values), ignorenan_maximum(values))) function zvalues(values::AVec{T}, zrange::Tuple{T,T} = (ignorenan_minimum(values), ignorenan_maximum(values))) where T<:Real
ZValues(collect(float(values)), map(Float64, zrange)) ZValues(collect(float(values)), map(Float64, zrange))
end end
@ -552,7 +552,7 @@ end
abstract type AbstractSurface end abstract type AbstractSurface end
"represents a contour or surface mesh" "represents a contour or surface mesh"
immutable Surface{M<:AMat} <: AbstractSurface struct Surface{M<:AMat} <: AbstractSurface
surf::M surf::M
end end
@ -564,7 +564,7 @@ for f in (:length, :size)
@eval Base.$f(surf::Surface, args...) = $f(surf.surf, args...) @eval Base.$f(surf::Surface, args...) = $f(surf.surf, args...)
end end
Base.copy(surf::Surface) = Surface(copy(surf.surf)) Base.copy(surf::Surface) = Surface(copy(surf.surf))
Base.eltype{T}(surf::Surface{T}) = eltype(T) Base.eltype(surf::Surface{T}) where {T} = eltype(T)
function expand_extrema!(a::Axis, surf::Surface) function expand_extrema!(a::Axis, surf::Surface)
ex = a[:extrema] ex = a[:extrema]
@ -575,7 +575,7 @@ function expand_extrema!(a::Axis, surf::Surface)
end end
"For the case of representing a surface as a function of x/y... can possibly avoid allocations." "For the case of representing a surface as a function of x/y... can possibly avoid allocations."
immutable SurfaceFunction <: AbstractSurface struct SurfaceFunction <: AbstractSurface
f::Function f::Function
end end
@ -585,19 +585,19 @@ end
# # I don't want to clash with ValidatedNumerics, but this would be nice: # # I don't want to clash with ValidatedNumerics, but this would be nice:
# ..(a::T, b::T) = (a,b) # ..(a::T, b::T) = (a,b)
immutable Volume{T} struct Volume{T}
v::Array{T,3} v::Array{T,3}
x_extents::Tuple{T,T} x_extents::Tuple{T,T}
y_extents::Tuple{T,T} y_extents::Tuple{T,T}
z_extents::Tuple{T,T} z_extents::Tuple{T,T}
end end
default_extents{T}(::Type{T}) = (zero(T), one(T)) default_extents(::Type{T}) where {T} = (zero(T), one(T))
function Volume{T}(v::Array{T,3}, function Volume(v::Array{T,3},
x_extents = default_extents(T), x_extents = default_extents(T),
y_extents = default_extents(T), y_extents = default_extents(T),
z_extents = default_extents(T)) z_extents = default_extents(T)) where T
Volume(v, x_extents, y_extents, z_extents) Volume(v, x_extents, y_extents, z_extents)
end end
@ -605,13 +605,13 @@ Base.Array(vol::Volume) = vol.v
for f in (:length, :size) for f in (:length, :size)
@eval Base.$f(vol::Volume, args...) = $f(vol.v, args...) @eval Base.$f(vol::Volume, args...) = $f(vol.v, args...)
end end
Base.copy{T}(vol::Volume{T}) = Volume{T}(copy(vol.v), vol.x_extents, vol.y_extents, vol.z_extents) Base.copy(vol::Volume{T}) where {T} = Volume{T}(copy(vol.v), vol.x_extents, vol.y_extents, vol.z_extents)
Base.eltype{T}(vol::Volume{T}) = T Base.eltype(vol::Volume{T}) where {T} = T
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# style is :open or :closed (for now) # style is :open or :closed (for now)
immutable Arrow struct Arrow
style::Symbol style::Symbol
side::Symbol # :head (default), :tail, or :both side::Symbol # :head (default), :tail, or :both
headlength::Float64 headlength::Float64
@ -673,14 +673,14 @@ end
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
"Represents data values with formatting that should apply to the tick labels." "Represents data values with formatting that should apply to the tick labels."
immutable Formatted{T} struct Formatted{T}
data::T data::T
formatter::Function formatter::Function
end end
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
"create a BezierCurve for plotting" "create a BezierCurve for plotting"
type BezierCurve{T <: FixedSizeArrays.Vec} mutable struct BezierCurve{T <: FixedSizeArrays.Vec}
control_points::Vector{T} control_points::Vector{T}
end end

View File

@ -558,7 +558,7 @@ function createGadflyAnnotationObject(x, y, txt::PlotText)
)) ))
end end
function _add_annotations{X,Y,V}(plt::Plot{GadflyBackend}, anns::AVec{Tuple{X,Y,V}}) function _add_annotations(plt::Plot{GadflyBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns for ann in anns
push!(plt.o.guides, createGadflyAnnotationObject(ann...)) push!(plt.o.guides, createGadflyAnnotationObject(ann...))
end end
@ -614,7 +614,7 @@ function getxy(plt::Plot{GadflyBackend}, i::Integer)
mapping[:x], mapping[:y] mapping[:x], mapping[:y]
end end
function setxy!{X,Y}(plt::Plot{GadflyBackend}, xy::Tuple{X,Y}, i::Integer) function setxy!(plt::Plot{GadflyBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
for mapping in getGadflyMappings(plt, i) for mapping in getGadflyMappings(plt, i)
mapping[:x], mapping[:y] = xy mapping[:x], mapping[:y] = xy
end end
@ -677,7 +677,7 @@ setGadflyDisplaySize(plt::Plot) = setGadflyDisplaySize(plt.attr[:size]...)
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
function doshow{P<:Union{GadflyBackend,ImmerseBackend}}(io::IO, func, plt::AbstractPlot{P}) function doshow(io::IO, func, plt::AbstractPlot{P}) where P<:Union{GadflyBackend,ImmerseBackend}
gplt = getGadflyContext(plt) gplt = getGadflyContext(plt)
setGadflyDisplaySize(plt) setGadflyDisplaySize(plt)
Gadfly.draw(func(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt) Gadfly.draw(func(io, Compose.default_graphic_width, Compose.default_graphic_height), gplt)
@ -692,7 +692,7 @@ getGadflyWriteFunc(::MIME"application/x-tex") = Gadfly.PGF
getGadflyWriteFunc(m::MIME) = error("Unsupported in Gadfly/Immerse: ", m) getGadflyWriteFunc(m::MIME) = error("Unsupported in Gadfly/Immerse: ", m)
for mime in (MIME"image/png", MIME"image/svg+xml", MIME"application/pdf", MIME"application/postscript", MIME"application/x-tex") for mime in (MIME"image/png", MIME"image/svg+xml", MIME"application/pdf", MIME"application/postscript", MIME"application/x-tex")
@eval function Base.show{P<:Union{GadflyBackend,ImmerseBackend}}(io::IO, ::$mime, plt::AbstractPlot{P}) @eval function Base.show(io::IO, ::$mime, plt::AbstractPlot{P}) where P<:Union{GadflyBackend,ImmerseBackend}
func = getGadflyWriteFunc($mime()) func = getGadflyWriteFunc($mime())
doshow(io, func, plt) doshow(io, func, plt)
end end

View File

@ -2,7 +2,7 @@
# Geometry which displays arbitrary shapes at given (x, y) positions. # Geometry which displays arbitrary shapes at given (x, y) positions.
# note: vertices is a list of shapes # note: vertices is a list of shapes
immutable ShapeGeometry <: Gadfly.GeometryElement struct ShapeGeometry <: Gadfly.GeometryElement
vertices::AbstractVector #{Tuple{Float64,Float64}} vertices::AbstractVector #{Tuple{Float64,Float64}}
tag::Symbol tag::Symbol

View File

@ -61,7 +61,7 @@ end
# ---------------------------------------------------------------- # ----------------------------------------------------------------
function _add_annotations{X,Y,V}(plt::Plot{ImmerseBackend}, anns::AVec{Tuple{X,Y,V}}) function _add_annotations(plt::Plot{ImmerseBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns for ann in anns
push!(getGadflyContext(plt).guides, createGadflyAnnotationObject(ann...)) push!(getGadflyContext(plt).guides, createGadflyAnnotationObject(ann...))
end end
@ -76,7 +76,7 @@ function getxy(plt::Plot{ImmerseBackend}, i::Integer)
mapping[:x], mapping[:y] mapping[:x], mapping[:y]
end end
function setxy!{X,Y}(plt::Plot{ImmerseBackend}, xy::Tuple{X,Y}, i::Integer) function setxy!(plt::Plot{ImmerseBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
for mapping in getGadflyMappings(plt, i) for mapping in getGadflyMappings(plt, i)
mapping[:x], mapping[:y] = xy mapping[:x], mapping[:y] = xy
end end

View File

@ -218,7 +218,7 @@ function createQwtAnnotation(plt::Plot, x, y, val::AbstractString)
marker[:attach](plt.o.widget) marker[:attach](plt.o.widget)
end end
function _add_annotations{X,Y,V}(plt::Plot{QwtBackend}, anns::AVec{Tuple{X,Y,V}}) function _add_annotations(plt::Plot{QwtBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns for ann in anns
createQwtAnnotation(plt, ann...) createQwtAnnotation(plt, ann...)
end end
@ -233,7 +233,7 @@ function getxy(plt::Plot{QwtBackend}, i::Int)
series.x, series.y series.x, series.y
end end
function setxy!{X,Y}(plt::Plot{QwtBackend}, xy::Tuple{X,Y}, i::Integer) function setxy!(plt::Plot{QwtBackend}, xy::Tuple{X,Y}, i::Integer) where {X,Y}
series = plt.o.lines[i] series = plt.o.lines[i]
series.x, series.y = xy series.x, series.y = xy
plt plt

View File

@ -217,7 +217,7 @@ function createWinstonAnnotationObject(plt::Plot{WinstonBackend}, x, y, val::Abs
Winston.text(x, y, val) Winston.text(x, y, val)
end end
function _add_annotations{X,Y,V}(plt::Plot{WinstonBackend}, anns::AVec{Tuple{X,Y,V}}) function _add_annotations(plt::Plot{WinstonBackend}, anns::AVec{Tuple{X,Y,V}}) where {X,Y,V}
for ann in anns for ann in anns
createWinstonAnnotationObject(plt, ann...) createWinstonAnnotationObject(plt, ann...)
end end

View File

@ -34,9 +34,9 @@ getColorVector(scheme::ColorScheme) = [getColor(scheme)]
colorscheme(scheme::ColorScheme) = scheme colorscheme(scheme::ColorScheme) = scheme
colorscheme(s::AbstractString; kw...) = colorscheme(Symbol(s); kw...) colorscheme(s::AbstractString; kw...) = colorscheme(Symbol(s); kw...)
colorscheme(s::Symbol; kw...) = haskey(_gradients, s) ? ColorGradient(s; kw...) : ColorWrapper(convertColor(s); kw...) colorscheme(s::Symbol; kw...) = haskey(_gradients, s) ? ColorGradient(s; kw...) : ColorWrapper(convertColor(s); kw...)
colorscheme{T<:Real}(s::Symbol, vals::AVec{T}; kw...) = ColorGradient(s, vals; kw...) colorscheme(s::Symbol, vals::AVec{T}; kw...) where {T<:Real} = ColorGradient(s, vals; kw...)
colorscheme(cs::AVec, vs::AVec; kw...) = ColorGradient(cs, vs; kw...) colorscheme(cs::AVec, vs::AVec; kw...) = ColorGradient(cs, vs; kw...)
colorscheme{T<:Colorant}(cs::AVec{T}; kw...) = ColorGradient(cs; kw...) colorscheme(cs::AVec{T}; kw...) where {T<:Colorant} = ColorGradient(cs; kw...)
colorscheme(f::Function; kw...) = ColorFunction(f; kw...) colorscheme(f::Function; kw...) = ColorFunction(f; kw...)
colorscheme(v::AVec; kw...) = ColorVector(v; kw...) colorscheme(v::AVec; kw...) = ColorVector(v; kw...)
colorscheme(m::AMat; kw...) = size(m,1) == 1 ? map(c->colorscheme(c; kw...), m) : [colorscheme(m[:,i]; kw...) for i in 1:size(m,2)]' colorscheme(m::AMat; kw...) = size(m,1) == 1 ? map(c->colorscheme(c; kw...), m) : [colorscheme(m[:,i]; kw...) for i in 1:size(m,2)]'
@ -98,7 +98,7 @@ const _gradients = KW(
:lighttest => map(c -> lighten(c, 0.3), _testColors), :lighttest => map(c -> lighten(c, 0.3), _testColors),
) )
function register_gradient_colors{C<:Colorant}(name::Symbol, colors::AVec{C}) function register_gradient_colors(name::Symbol, colors::AVec{C}) where C<:Colorant
_gradients[name] = colors _gradients[name] = colors
end end
@ -109,11 +109,11 @@ default_gradient() = ColorGradient(:inferno)
# -------------------------------------------------------------- # --------------------------------------------------------------
"Continuous gradient between values. Wraps a list of bounding colors and the values they represent." "Continuous gradient between values. Wraps a list of bounding colors and the values they represent."
immutable ColorGradient <: ColorScheme struct ColorGradient <: ColorScheme
colors::Vector colors::Vector
values::Vector values::Vector
function ColorGradient{S<:Real}(cs::AVec, vals::AVec{S} = linspace(0, 1, length(cs)); alpha = nothing) function ColorGradient(cs::AVec, vals::AVec{S} = linspace(0, 1, length(cs)); alpha = nothing) where S<:Real
if length(cs) == length(vals) if length(cs) == length(vals)
return new(convertColor(cs,alpha), collect(vals)) return new(convertColor(cs,alpha), collect(vals))
end end
@ -138,7 +138,7 @@ Base.getindex(cs::ColorGradient, z::Number) = getColorZ(cs, z)
# create a gradient from a symbol (blues, reds, etc) and vector of boundary values # create a gradient from a symbol (blues, reds, etc) and vector of boundary values
function ColorGradient{T<:Real}(s::Symbol, vals::AVec{T} = 0:0; kw...) function ColorGradient(s::Symbol, vals::AVec{T} = 0:0; kw...) where T<:Real
haskey(_gradients, s) || error("Invalid gradient symbol. Choose from: ", sort(collect(keys(_gradients)))) haskey(_gradients, s) || error("Invalid gradient symbol. Choose from: ", sort(collect(keys(_gradients))))
cs = _gradients[s] cs = _gradients[s]
if vals == 0:0 if vals == 0:0
@ -208,7 +208,7 @@ end
# -------------------------------------------------------------- # --------------------------------------------------------------
"Wraps a function, taking an index and returning a Colorant" "Wraps a function, taking an index and returning a Colorant"
immutable ColorFunction <: ColorScheme struct ColorFunction <: ColorScheme
f::Function f::Function
end end
@ -217,7 +217,7 @@ getColor(scheme::ColorFunction, idx::Int) = scheme.f(idx)
# -------------------------------------------------------------- # --------------------------------------------------------------
"Wraps a function, taking an z-value and returning a Colorant" "Wraps a function, taking an z-value and returning a Colorant"
immutable ColorZFunction <: ColorScheme struct ColorZFunction <: ColorScheme
f::Function f::Function
end end
@ -226,7 +226,7 @@ getColorZ(scheme::ColorZFunction, z::Real) = scheme.f(z)
# -------------------------------------------------------------- # --------------------------------------------------------------
"Wraps a vector of colors... may be vector of Symbol/String/Colorant" "Wraps a vector of colors... may be vector of Symbol/String/Colorant"
immutable ColorVector <: ColorScheme struct ColorVector <: ColorScheme
v::Vector{Colorant} v::Vector{Colorant}
ColorVector(v::AVec; alpha = nothing) = new(convertColor(v,alpha)) ColorVector(v::AVec; alpha = nothing) = new(convertColor(v,alpha))
end end
@ -238,7 +238,7 @@ getColorVector(scheme::ColorVector) = scheme.v
# -------------------------------------------------------------- # --------------------------------------------------------------
"Wraps a single color" "Wraps a single color"
immutable ColorWrapper <: ColorScheme struct ColorWrapper <: ColorScheme
c::RGBA c::RGBA
ColorWrapper(c::Colorant; alpha = nothing) = new(convertColor(c, alpha)) ColorWrapper(c::Colorant; alpha = nothing) = new(convertColor(c, alpha))
end end
@ -347,8 +347,8 @@ function get_color_palette(palette, bgcolor::Union{Colorant,ColorWrapper}, numco
RGBA[getColorZ(grad, z) for z in zrng] RGBA[getColorZ(grad, z) for z in zrng]
end end
function get_color_palette{C<:Colorant}(palette::Vector{C}, function get_color_palette(palette::Vector{C},
bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer) bgcolor::Union{Colorant,ColorWrapper}, numcolors::Integer) where C<:Colorant
palette palette
end end

View File

@ -5,21 +5,21 @@
# This should cut down on boilerplate code and allow more focused dispatch on type # This should cut down on boilerplate code and allow more focused dispatch on type
# note: returns meta information... mainly for use with automatic labeling from DataFrames for now # note: returns meta information... mainly for use with automatic labeling from DataFrames for now
const FuncOrFuncs = @compat(Union{Function, AVec{Function}}) const FuncOrFuncs = Union{Function, AVec{Function}}
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(d, :seriestype, :none)) all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(d, :seriestype, :none))
# missing # missing
convertToAnyVector(v::@compat(Void), d::KW) = Any[nothing], nothing convertToAnyVector(v::Void, d::KW) = Any[nothing], nothing
# fixed number of blank series # fixed number of blank series
convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
# numeric vector # numeric vector
convertToAnyVector{T<:Number}(v::AVec{T}, d::KW) = Any[v], nothing convertToAnyVector(v::AVec{T}, d::KW) where {T<:Number} = Any[v], nothing
# string vector # string vector
convertToAnyVector{T<:@compat(AbstractString)}(v::AVec{T}, d::KW) = Any[v], nothing convertToAnyVector(v::AVec{T}, d::KW) where {T<:AbstractString} = Any[v], nothing
function convertToAnyVector(v::AMat, d::KW) function convertToAnyVector(v::AMat, d::KW)
if all3D(d) if all3D(d)
@ -39,7 +39,7 @@ convertToAnyVector(s::Surface, d::KW) = Any[s], nothing
# convertToAnyVector(v::AVec{OHLC}, d::KW) = Any[v], nothing # convertToAnyVector(v::AVec{OHLC}, d::KW) = Any[v], nothing
# dates # dates
convertToAnyVector{D<:Union{Date,DateTime}}(dts::AVec{D}, d::KW) = Any[dts], nothing convertToAnyVector(dts::AVec{D}, d::KW) where {D<:Union{Date,DateTime}} = Any[dts], nothing
# list of things (maybe other vectors, functions, or something else) # list of things (maybe other vectors, functions, or something else)
function convertToAnyVector(v::AVec, d::KW) function convertToAnyVector(v::AVec, d::KW)

View File

@ -1,7 +1,7 @@
""" """
Holds all data needed for a documentation example... header, description, and plotting expression (Expr) Holds all data needed for a documentation example... header, description, and plotting expression (Expr)
""" """
type PlotExample mutable struct PlotExample
header::AbstractString header::AbstractString
desc::AbstractString desc::AbstractString
exprs::Vector{Expr} exprs::Vector{Expr}
@ -172,7 +172,7 @@ PlotExample("Bar",
PlotExample("Histogram", PlotExample("Histogram",
"", "",
[:(begin [:(begin
histogram(randn(1000), nbins=20) histogram(randn(1000), bins = :scott, weights = repeat(1:5, outer = 200))
end)] end)]
), ),
@ -305,7 +305,7 @@ PlotExample("DataFrames",
[:(begin [:(begin
import RDatasets import RDatasets
iris = RDatasets.dataset("datasets", "iris") iris = RDatasets.dataset("datasets", "iris")
scatter(iris, :SepalLength, :SepalWidth, group=:Species, @df iris scatter(:SepalLength, :SepalWidth, group=:Species,
title = "My awesome plot", xlabel = "Length", ylabel = "Width", title = "My awesome plot", xlabel = "Length", ylabel = "Width",
marker = (0.5, [:cross :hex :star7], 12), bg=RGB(.2,.2,.2)) marker = (0.5, [:cross :hex :star7], 12), bg=RGB(.2,.2,.2))
end)] end)]
@ -314,9 +314,9 @@ PlotExample("DataFrames",
PlotExample("Groups and Subplots", PlotExample("Groups and Subplots",
"", "",
[:(begin [:(begin
group = rand(map(i->"group $i",1:4),100) group = rand(map(i->"group $i",1:4),100)
plot(rand(100), layout=@layout([a b;c]), group=group, plot(rand(100), layout=@layout([a b;c]), group=group,
linetype=[:bar :scatter :steppre]) linetype=[:bar :scatter :steppre], linecolor = :match)
end)] end)]
), ),
@ -354,8 +354,8 @@ PlotExample("Boxplot and Violin series recipes",
[:(begin [:(begin
import RDatasets import RDatasets
singers = RDatasets.dataset("lattice", "singer") singers = RDatasets.dataset("lattice", "singer")
violin(singers, :VoicePart, :Height, line = 0, fill = (0.2, :blue)) @df singers violin(:VoicePart, :Height, line = 0, fill = (0.2, :blue))
boxplot!(singers, :VoicePart, :Height, line = (2,:black), fill = (0.3, :orange)) @df singers boxplot!(:VoicePart, :Height, line = (2,:black), fill = (0.3, :orange))
end)] end)]
), ),
@ -377,16 +377,14 @@ PlotExample("Animation with subplots",
PlotExample("Spy", PlotExample("Spy",
""" """
For a matrix `mat` with unique nonzeros `spy(mat)` returns a colorless plot. If `mat` For a matrix `mat` with unique nonzeros `spy(mat)` returns a colorless plot. If `mat` has
has various different nonzero values, a colorbar is added. The colorbar can be disabled various different nonzero values, a colorbar is added. The colorbar can be disabled with
with `legend = nothing`. As always, the marker shape and size can be changed with `legend = nothing`.
`spy(mat, markersize = 3, markershape = :star)`. """
""",
[:(begin [:(begin
a = spdiagm((ones(50), ones(49), ones(49), ones(40), ones(40)),(0, 1, -1, 10, -10)) a = spdiagm((ones(50), ones(49), ones(49), ones(40), ones(40)),(0, 1, -1, 10, -10))
b = spdiagm((1:50, 1:49, 1:49, 1:40, 1:40),(0, 1, -1, 10, -10)) b = spdiagm((1:50, 1:49, 1:49, 1:40, 1:40),(0, 1, -1, 10, -10))
plot(spy(a, markershape = :dtriangle), spy(b), markersize = 3, plot(spy(a), spy(b), title = ["Unique nonzeros" "Different nonzeros"])
title = ["Unique nonzeros" "Different nonzeros"])
end)] end)]
), ),
@ -410,9 +408,11 @@ The style of the frame/axes of a (sub)plot can be changed with the `framestyle`
attribute. The default framestyle is `:axes`. attribute. The default framestyle is `:axes`.
""", """,
[:(begin [:(begin
histogram(fill(randn(1000), 5), framestyle = [:box :semi :axes :grid :none], scatter(fill(randn(10), 6), fill(randn(10), 6),
title = [":box" ":semi" ":axes" ":grid" ":none"], framestyle = [:box :semi :origin :zerolines :grid :none],
color = RowVector(1:5), layout = 5, label = "") title = [":box" ":semi" ":origin" ":zerolines" ":grid" ":none"],
color = RowVector(1:6), layout = 6, label = "", markerstrokewidth = 0,
ticks = -2:2)
end)] end)]
), ),

View File

@ -1,10 +1,6 @@
# NOTE: (0,0) is the top-left !!! # NOTE: (0,0) is the top-left !!!
# allow pixels and percentages
const px = AbsoluteLength(0.254)
const pct = Length{:pct, Float64}(1.0)
to_pixels(m::AbsoluteLength) = m.value / 0.254 to_pixels(m::AbsoluteLength) = m.value / 0.254
const _cbar_width = 5mm const _cbar_width = 5mm
@ -17,7 +13,7 @@ Base.zero(::Type{typeof(mm)}) = 0mm
Base.one(::Type{typeof(mm)}) = 1mm Base.one(::Type{typeof(mm)}) = 1mm
Base.typemin(::typeof(mm)) = -Inf*mm Base.typemin(::typeof(mm)) = -Inf*mm
Base.typemax(::typeof(mm)) = Inf*mm Base.typemax(::typeof(mm)) = Inf*mm
Base.convert{F<:AbstractFloat}(::Type{F}, l::AbsoluteLength) = convert(F, l.value) Base.convert(::Type{F}, l::AbsoluteLength) where {F<:AbstractFloat} = convert(F, l.value)
# TODO: these are unintuitive and may cause tricky bugs # TODO: these are unintuitive and may cause tricky bugs
# Base.:+(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * (1 + m2.value)) # Base.:+(m1::AbsoluteLength, m2::Length{:pct}) = AbsoluteLength(m1.value * (1 + m2.value))
@ -99,7 +95,7 @@ end
# ----------------------------------------------------------- # -----------------------------------------------------------
# points combined by x/y, pct, and length # points combined by x/y, pct, and length
type MixedMeasures mutable struct MixedMeasures
xy::Float64 xy::Float64
pct::Float64 pct::Float64
len::AbsoluteLength len::AbsoluteLength
@ -220,7 +216,7 @@ bottompad(layout::AbstractLayout) = 0mm
# RootLayout # RootLayout
# this is the parent of the top-level layout # this is the parent of the top-level layout
immutable RootLayout <: AbstractLayout end struct RootLayout <: AbstractLayout end
Base.parent(::RootLayout) = nothing Base.parent(::RootLayout) = nothing
parent_bbox(::RootLayout) = defaultbox parent_bbox(::RootLayout) = defaultbox
@ -230,7 +226,7 @@ bbox(::RootLayout) = defaultbox
# EmptyLayout # EmptyLayout
# contains blank space # contains blank space
type EmptyLayout <: AbstractLayout mutable struct EmptyLayout <: AbstractLayout
parent::AbstractLayout parent::AbstractLayout
bbox::BoundingBox bbox::BoundingBox
attr::KW # store label, width, and height for initialization attr::KW # store label, width, and height for initialization
@ -248,7 +244,7 @@ _update_min_padding!(layout::EmptyLayout) = nothing
# GridLayout # GridLayout
# nested, gridded layout with optional size percentages # nested, gridded layout with optional size percentages
type GridLayout <: AbstractLayout mutable struct GridLayout <: AbstractLayout
parent::AbstractLayout parent::AbstractLayout
minpad::Tuple # leftpad, toppad, rightpad, bottompad minpad::Tuple # leftpad, toppad, rightpad, bottompad
bbox::BoundingBox bbox::BoundingBox
@ -485,12 +481,12 @@ function layout_args(n::Integer)
GridLayout(nr, nc), n GridLayout(nr, nc), n
end end
function layout_args{I<:Integer}(sztup::NTuple{2,I}) function layout_args(sztup::NTuple{2,I}) where I<:Integer
nr, nc = sztup nr, nc = sztup
GridLayout(nr, nc), nr*nc GridLayout(nr, nc), nr*nc
end end
function layout_args{I<:Integer}(sztup::NTuple{3,I}) function layout_args(sztup::NTuple{3,I}) where I<:Integer
n, nr, nc = sztup n, nr, nc = sztup
nr, nc = compute_gridsize(n, nr, nc) nr, nc = compute_gridsize(n, nr, nc)
GridLayout(nr, nc), n GridLayout(nr, nc), n

View File

@ -193,7 +193,7 @@ function Base.show(io::IO, ::MIME"text/html", plt::Plot)
end end
end end
function _show{B}(io::IO, m, plt::Plot{B}) function _show(io::IO, m, plt::Plot{B}) where B
# Base.show_backtrace(STDOUT, backtrace()) # Base.show_backtrace(STDOUT, backtrace())
warn("_show is not defined for this backend. m=", string(m)) warn("_show is not defined for this backend. m=", string(m))
end end
@ -203,7 +203,7 @@ end
# for writing to io streams... first prepare, then callback # for writing to io streams... first prepare, then callback
for mime in keys(_mimeformats) for mime in keys(_mimeformats)
@eval function Base.show{B}(io::IO, m::MIME{Symbol($mime)}, plt::Plot{B}) @eval function Base.show(io::IO, m::MIME{Symbol($mime)}, plt::Plot{B}) where B
prepare_output(plt) prepare_output(plt)
_show(io, m, plt) _show(io, m, plt)
end end
@ -258,7 +258,6 @@ end
const _ijulia_output = String["text/html"] const _ijulia_output = String["text/html"]
using Requires
@require IJulia begin @require IJulia begin
if IJulia.inited if IJulia.inited
export set_ijulia_output export set_ijulia_output
@ -293,7 +292,7 @@ end
Media.media(Plot, Media.Plot) Media.media(Plot, Media.Plot)
_show{B}(io::IO, m::MIME"text/plain", plt::Plot{B}) = print(io, "Plot{$B}()") _show(io::IO, m::MIME"text/plain", plt::Plot{B}) where {B} = print(io, "Plot{$B}()")
function Juno.render(e::Juno.Editor, plt::Plot) function Juno.render(e::Juno.Editor, plt::Plot)
Juno.render(e, nothing) Juno.render(e, nothing)

View File

@ -301,7 +301,7 @@ end
# getting ready to add the series... last update to subplot from anything # getting ready to add the series... last update to subplot from anything
# that might have been added during series recipes # that might have been added during series recipes
function _prepare_subplot{T}(plt::Plot{T}, d::KW) function _prepare_subplot(plt::Plot{T}, d::KW) where T
st::Symbol = d[:seriestype] st::Symbol = d[:seriestype]
sp::Subplot{T} = d[:subplot] sp::Subplot{T} = d[:subplot]
sp_idx = get_subplot_index(plt, sp) sp_idx = get_subplot_index(plt, sp)

View File

@ -1,5 +1,5 @@
type CurrentPlot mutable struct CurrentPlot
nullableplot::Nullable{AbstractPlot} nullableplot::Nullable{AbstractPlot}
end end
const CURRENT_PLOT = CurrentPlot(Nullable{AbstractPlot}()) const CURRENT_PLOT = CurrentPlot(Nullable{AbstractPlot}())

View File

@ -47,7 +47,7 @@ end
num_series(x::AMat) = size(x,2) num_series(x::AMat) = size(x,2)
num_series(x) = 1 num_series(x) = 1
RecipesBase.apply_recipe{T}(d::KW, ::Type{T}, plt::AbstractPlot) = throw(MethodError("Unmatched plot recipe: $T")) RecipesBase.apply_recipe(d::KW, ::Type{T}, plt::AbstractPlot) where {T} = throw(MethodError("Unmatched plot recipe: $T"))
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@ -343,9 +343,9 @@ _bin_centers(v::AVec) = (v[1:end-1] + v[2:end]) / 2
_is_positive(x) = (x > 0) && !(x 0) _is_positive(x) = (x > 0) && !(x 0)
_positive_else_nan{T}(::Type{T}, x::Real) = _is_positive(x) ? T(x) : T(NaN) _positive_else_nan(::Type{T}, x::Real) where {T} = _is_positive(x) ? T(x) : T(NaN)
function _scale_adjusted_values{T<:AbstractFloat}(::Type{T}, V::AbstractVector, scale::Symbol) function _scale_adjusted_values(::Type{T}, V::AbstractVector, scale::Symbol) where T<:AbstractFloat
if scale in _logScales if scale in _logScales
[_positive_else_nan(T, x) for x in V] [_positive_else_nan(T, x) for x in V]
else else
@ -354,7 +354,7 @@ function _scale_adjusted_values{T<:AbstractFloat}(::Type{T}, V::AbstractVector,
end end
function _binbarlike_baseline{T<:Real}(min_value::T, scale::Symbol) function _binbarlike_baseline(min_value::T, scale::Symbol) where T<:Real
if (scale in _logScales) if (scale in _logScales)
!isnan(min_value) ? min_value / T(_logScaleBases[scale]^log10(2)) : T(1E-3) !isnan(min_value) ? min_value / T(_logScaleBases[scale]^log10(2)) : T(1E-3)
else else
@ -363,7 +363,7 @@ function _binbarlike_baseline{T<:Real}(min_value::T, scale::Symbol)
end end
function _preprocess_binbarlike_weights{T<:AbstractFloat}(::Type{T}, w, wscale::Symbol) function _preprocess_binbarlike_weights(::Type{T}, w, wscale::Symbol) where T<:AbstractFloat
w_adj = _scale_adjusted_values(T, w, wscale) w_adj = _scale_adjusted_values(T, w, wscale)
w_min = ignorenan_minimum(w_adj) w_min = ignorenan_minimum(w_adj)
w_max = ignorenan_maximum(w_adj) w_max = ignorenan_maximum(w_adj)
@ -499,7 +499,7 @@ Plots.@deps stepbins path
wand_edges(x...) = (warn("Load the StatPlots package in order to use :wand bins. Defaulting to :auto", once = true); :auto) wand_edges(x...) = (warn("Load the StatPlots package in order to use :wand bins. Defaulting to :auto", once = true); :auto)
function _auto_binning_nbins{N}(vs::NTuple{N,AbstractVector}, dim::Integer; mode::Symbol = :auto) function _auto_binning_nbins(vs::NTuple{N,AbstractVector}, dim::Integer; mode::Symbol = :auto) where N
_cl(x) = ceil(Int, NaNMath.max(x, one(x))) _cl(x) = ceil(Int, NaNMath.max(x, one(x)))
_iqr(v) = (q = quantile(v, 0.75) - quantile(v, 0.25); q > 0 ? q : oftype(q, 1)) _iqr(v) = (q = quantile(v, 0.75) - quantile(v, 0.25); q > 0 ? q : oftype(q, 1))
_span(v) = ignorenan_maximum(v) - ignorenan_minimum(v) _span(v) = ignorenan_maximum(v) - ignorenan_minimum(v)
@ -533,24 +533,24 @@ function _auto_binning_nbins{N}(vs::NTuple{N,AbstractVector}, dim::Integer; mode
end end
end end
_hist_edge{N}(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Integer) = StatsBase.histrange(vs[dim], binning, :left) _hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Integer) where {N} = StatsBase.histrange(vs[dim], binning, :left)
_hist_edge{N}(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Symbol) = _hist_edge(vs, dim, _auto_binning_nbins(vs, dim, mode = binning)) _hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Symbol) where {N} = _hist_edge(vs, dim, _auto_binning_nbins(vs, dim, mode = binning))
_hist_edge{N}(vs::NTuple{N,AbstractVector}, dim::Integer, binning::AbstractVector) = binning _hist_edge(vs::NTuple{N,AbstractVector}, dim::Integer, binning::AbstractVector) where {N} = binning
_hist_edges{N}(vs::NTuple{N,AbstractVector}, binning::NTuple{N}) = _hist_edges(vs::NTuple{N,AbstractVector}, binning::NTuple{N}) where {N} =
map(dim -> _hist_edge(vs, dim, binning[dim]), (1:N...)) map(dim -> _hist_edge(vs, dim, binning[dim]), (1:N...))
_hist_edges{N}(vs::NTuple{N,AbstractVector}, binning::Union{Integer, Symbol, AbstractVector}) = _hist_edges(vs::NTuple{N,AbstractVector}, binning::Union{Integer, Symbol, AbstractVector}) where {N} =
map(dim -> _hist_edge(vs, dim, binning), (1:N...)) map(dim -> _hist_edge(vs, dim, binning), (1:N...))
_hist_norm_mode(mode::Symbol) = mode _hist_norm_mode(mode::Symbol) = mode
_hist_norm_mode(mode::Bool) = mode ? :pdf : :none _hist_norm_mode(mode::Bool) = mode ? :pdf : :none
function _make_hist{N}(vs::NTuple{N,AbstractVector}, binning; normed = false, weights = nothing) function _make_hist(vs::NTuple{N,AbstractVector}, binning; normed = false, weights = nothing) where N
edges = _hist_edges(vs, binning) edges = _hist_edges(vs, binning)
h = float( weights == nothing ? h = float( weights == nothing ?
StatsBase.fit(StatsBase.Histogram, vs, edges, closed = :left) : StatsBase.fit(StatsBase.Histogram, vs, edges, closed = :left) :
StatsBase.fit(StatsBase.Histogram, vs, weights, edges, closed = :left) StatsBase.fit(StatsBase.Histogram, vs, StatsBase.Weights(weights), edges, closed = :left)
) )
normalize!(h, mode = _hist_norm_mode(normed)) normalize!(h, mode = _hist_norm_mode(normed))
end end
@ -590,7 +590,7 @@ end
@deps scatterhist scatterbins @deps scatterhist scatterbins
@recipe function f{T, E}(h::StatsBase.Histogram{T, 1, E}) @recipe function f(h::StatsBase.Histogram{T, 1, E}) where {T, E}
seriestype --> :barbins seriestype --> :barbins
st_map = Dict( st_map = Dict(
@ -611,7 +611,7 @@ end
end end
@recipe function f{H <: StatsBase.Histogram}(hv::AbstractVector{H}) @recipe function f(hv::AbstractVector{H}) where H <: StatsBase.Histogram
for h in hv for h in hv
@series begin @series begin
h h
@ -658,7 +658,7 @@ end
@deps histogram2d bins2d @deps histogram2d bins2d
@recipe function f{T, E}(h::StatsBase.Histogram{T, 2, E}) @recipe function f(h::StatsBase.Histogram{T, 2, E}) where {T, E}
seriestype --> :bins2d seriestype --> :bins2d
(h.edges[1], h.edges[2], Surface(h.weights)) (h.edges[1], h.edges[2], Surface(h.weights))
end end
@ -855,7 +855,7 @@ end
# TODO: move OHLC to PlotRecipes finance.jl # TODO: move OHLC to PlotRecipes finance.jl
"Represent Open High Low Close data (used in finance)" "Represent Open High Low Close data (used in finance)"
type OHLC{T<:Real} mutable struct OHLC{T<:Real}
open::T open::T
high::T high::T
low::T low::T
@ -894,10 +894,10 @@ end
# to squash ambiguity warnings... # to squash ambiguity warnings...
@recipe f(x::AVec{Function}, v::AVec{OHLC}) = error() @recipe f(x::AVec{Function}, v::AVec{OHLC}) = error()
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(x::AVec{Function}, v::AVec{Tuple{R1,R2,R3,R4}}) = error() @recipe f(x::AVec{Function}, v::AVec{Tuple{R1,R2,R3,R4}}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = error()
# this must be OHLC? # this must be OHLC?
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(x::AVec, ohlc::AVec{Tuple{R1,R2,R3,R4}}) = x, OHLC[OHLC(t...) for t in ohlc] @recipe f(x::AVec, ohlc::AVec{Tuple{R1,R2,R3,R4}}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = x, OHLC[OHLC(t...) for t in ohlc]
@recipe function f(x::AVec, v::AVec{OHLC}) @recipe function f(x::AVec, v::AVec{OHLC})
seriestype := :path seriestype := :path
@ -937,6 +937,7 @@ end
mat = g.args[1] mat = g.args[1]
if length(unique(mat[mat .!= 0])) < 2 if length(unique(mat[mat .!= 0])) < 2
legend --> nothing legend --> nothing
seriescolor --> cgrad([invisible(), fg_color(plotattributes)])
end end
n,m = size(mat) n,m = size(mat)
Plots.SliceIt, 1:m, 1:n, Surface(mat) Plots.SliceIt, 1:m, 1:n, Surface(mat)
@ -945,23 +946,21 @@ end
@recipe function f(::Type{Val{:spy}}, x,y,z) @recipe function f(::Type{Val{:spy}}, x,y,z)
yflip := true yflip := true
aspect_ratio := 1 aspect_ratio := 1
rs, cs, zs = findnz(z.surf) rs, cs, zs = findnz(z.surf)
xlim := ignorenan_extrema(cs) newz = fill(NaN, size(z)...)
ylim := ignorenan_extrema(rs)
if plotattributes[:markershape] == :none for i in eachindex(zs)
markershape := :circle newz[rs[i],cs[i]] = zs[i]
end end
if plotattributes[:markersize] == default(:markersize)
markersize := 1 seriestype := :heatmap
end
markerstrokewidth := 0
marker_z := zs
label := ""
x := cs
y := rs
z := nothing
seriestype := :scatter
grid --> false grid --> false
framestyle --> :box
x := x
y := y
z := Surface(newz)
() ()
end end
@ -987,7 +986,7 @@ datetimeformatter(dt) = string(DateTime(Dates.UTM(dt)))
# ------------------------------------------------- # -------------------------------------------------
# Complex Numbers # Complex Numbers
@recipe function f{T<:Number}(A::Array{Complex{T}}) @recipe function f(A::Array{Complex{T}}) where T<:Number
xguide --> "Re(x)" xguide --> "Re(x)"
yguide --> "Im(x)" yguide --> "Im(x)"
real.(A), imag.(A) real.(A), imag.(A)
@ -996,7 +995,7 @@ end
# Splits a complex matrix to its real and complex parts # Splits a complex matrix to its real and complex parts
# Reals defaults solid, imaginary defaults dashed # Reals defaults solid, imaginary defaults dashed
# Label defaults are changed to match the real-imaginary reference / indexing # Label defaults are changed to match the real-imaginary reference / indexing
@recipe function f{T<:Real,T2}(x::AbstractArray{T},y::Array{Complex{T2}}) @recipe function f(x::AbstractArray{T},y::Array{Complex{T2}}) where {T<:Real,T2}
ylabel --> "Re(y)" ylabel --> "Re(y)"
zlabel --> "Im(y)" zlabel --> "Im(y)"
x,real.(y),imag.(y) x,real.(y),imag.(y)

View File

@ -20,10 +20,10 @@ convertToAnyVector(v::Void, d::KW) = Any[nothing], nothing
convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing convertToAnyVector(n::Integer, d::KW) = Any[zeros(0) for i in 1:n], nothing
# numeric vector # numeric vector
convertToAnyVector{T<:Number}(v::AVec{T}, d::KW) = Any[v], nothing convertToAnyVector(v::AVec{T}, d::KW) where {T<:Number} = Any[v], nothing
# string vector # string vector
convertToAnyVector{T<:AbstractString}(v::AVec{T}, d::KW) = Any[v], nothing convertToAnyVector(v::AVec{T}, d::KW) where {T<:AbstractString} = Any[v], nothing
function convertToAnyVector(v::AMat, d::KW) function convertToAnyVector(v::AMat, d::KW)
if all3D(d) if all3D(d)
@ -99,8 +99,8 @@ nobigs(v) = v
end end
# not allowed # not allowed
compute_xyz{F<:Function}(x::Void, y::FuncOrFuncs{F}, z) = error("If you want to plot the function `$y`, you need to define the x values!") compute_xyz(x::Void, y::FuncOrFuncs{F}, z) where {F<:Function} = error("If you want to plot the function `$y`, you need to define the x values!")
compute_xyz{F<:Function}(x::Void, y::Void, z::FuncOrFuncs{F}) = error("If you want to plot the function `$z`, you need to define x and y values!") compute_xyz(x::Void, y::Void, z::FuncOrFuncs{F}) where {F<:Function} = error("If you want to plot the function `$z`, you need to define x and y values!")
compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!") compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!")
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -109,7 +109,7 @@ compute_xyz(x::Void, y::Void, z::Void) = error("x/y/z are all nothing!")
# we are going to build recipes to do the processing and splitting of the args # we are going to build recipes to do the processing and splitting of the args
# ensure we dispatch to the slicer # ensure we dispatch to the slicer
immutable SliceIt end struct SliceIt end
# the catch-all recipes # the catch-all recipes
@recipe function f(::Type{SliceIt}, x, y, z) @recipe function f(::Type{SliceIt}, x, y, z)
@ -163,10 +163,10 @@ immutable SliceIt end
end end
# this is the default "type recipe"... just pass the object through # this is the default "type recipe"... just pass the object through
@recipe f{T<:Any}(::Type{T}, v::T) = v @recipe f(::Type{T}, v::T) where {T<:Any} = v
# this should catch unhandled "series recipes" and error with a nice message # 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.") @recipe f(::Type{V}, x, y, z) where {V<:Val} = 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] _apply_type_recipe(d, v) = RecipesBase.apply_recipe(d, typeof(v), v)[1].args[1]
@ -201,7 +201,7 @@ end
# end # end
# don't do anything for ints or floats # don't do anything for ints or floats
_apply_type_recipe{T<:Union{Integer,AbstractFloat}}(d, v::AbstractArray{T}) = v _apply_type_recipe(d, v::AbstractArray{T}) where {T<:Union{Integer,AbstractFloat}} = v
# handle "type recipes" by converting inputs, and then either re-calling or slicing # handle "type recipes" by converting inputs, and then either re-calling or slicing
@recipe function f(x, y, z) @recipe function f(x, y, z)
@ -274,7 +274,7 @@ end
@recipe f(n::Integer) = is3d(get(plotattributes,:seriestype,:path)) ? (SliceIt, n, n, n) : (SliceIt, n, n, nothing) @recipe f(n::Integer) = is3d(get(plotattributes,:seriestype,:path)) ? (SliceIt, n, n, n) : (SliceIt, n, n, nothing)
# return a surface if this is a 3d plot, otherwise let it be sliced up # return a surface if this is a 3d plot, otherwise let it be sliced up
@recipe function f{T<:Union{Integer,AbstractFloat}}(mat::AMat{T}) @recipe function f(mat::AMat{T}) where T<:Union{Integer,AbstractFloat}
if all3D(plotattributes) if all3D(plotattributes)
n,m = size(mat) n,m = size(mat)
wrap_surfaces(plotattributes) wrap_surfaces(plotattributes)
@ -285,7 +285,7 @@ end
end end
# if a matrix is wrapped by Formatted, do similar logic, but wrap data with Surface # if a matrix is wrapped by Formatted, do similar logic, but wrap data with Surface
@recipe function f{T<:AbstractMatrix}(fmt::Formatted{T}) @recipe function f(fmt::Formatted{T}) where T<:AbstractMatrix
if all3D(plotattributes) if all3D(plotattributes)
mat = fmt.data mat = fmt.data
n,m = size(mat) n,m = size(mat)
@ -297,7 +297,7 @@ end
end end
# assume this is a Volume, so construct one # assume this is a Volume, so construct one
@recipe function f{T<:Number}(vol::AbstractArray{T,3}, args...) @recipe function f(vol::AbstractArray{T,3}, args...) where T<:Number
seriestype := :volume seriestype := :volume
SliceIt, nothing, Volume(vol, args...), nothing SliceIt, nothing, Volume(vol, args...), nothing
end end
@ -305,7 +305,7 @@ end
# # images - grays # # images - grays
@recipe function f{T<:Gray}(mat::AMat{T}) @recipe function f(mat::AMat{T}) where T<:Gray
if is_seriestype_supported(:image) if is_seriestype_supported(:image)
seriestype := :image seriestype := :image
n, m = size(mat) n, m = size(mat)
@ -320,7 +320,7 @@ end
# # images - colors # # images - colors
@recipe function f{T<:Colorant}(mat::AMat{T}) @recipe function f(mat::AMat{T}) where T<:Colorant
n, m = size(mat) n, m = size(mat)
if is_seriestype_supported(:image) if is_seriestype_supported(:image)
@ -358,7 +358,7 @@ end
# function without range... use the current range of the x-axis # function without range... use the current range of the x-axis
@recipe function f{F<:Function}(f::FuncOrFuncs{F}) @recipe function f(f::FuncOrFuncs{F}) where F<:Function
plt = plotattributes[:plot_object] plt = plotattributes[:plot_object]
xmin, xmax = try xmin, xmax = try
axis_limits(plt[1][:xaxis]) axis_limits(plt[1][:xaxis])
@ -371,6 +371,13 @@ end
end end
# try some intervals over which the function may be defined # try some intervals over which the function may be defined
function tryrange(F::AbstractArray, vec)
rets = [tryrange(f, vec) for f in F] # get the preferred for each
maxind = maximum(indexin(rets, vec)) # get the last attempt that succeeded (most likely to fit all)
rets .= [tryrange(f, vec[maxind:maxind]) for f in F] # ensure that all functions compute there
rets[1]
end
function tryrange(F, vec) function tryrange(F, vec)
for v in vec for v in vec
try try
@ -379,7 +386,7 @@ function tryrange(F, vec)
catch catch
end end
end end
error("Function not defined over the given interval, $vec") error("$F is not a Function, or is not defined at any of the values $vec")
end end
# #
# # -------------------------------------------------------------------- # # --------------------------------------------------------------------
@ -390,7 +397,7 @@ end
# # if functions come first, just swap the order (not to be confused with parametric functions... # # if functions come first, just swap the order (not to be confused with parametric functions...
# # as there would be more than one function passed in) # # as there would be more than one function passed in)
@recipe function f{F<:Function}(f::FuncOrFuncs{F}, x) @recipe function f(f::FuncOrFuncs{F}, x) where F<:Function
F2 = typeof(x) F2 = typeof(x)
@assert !(F2 <: Function || (F2 <: AbstractArray && F2.parameters[1] <: Function)) # otherwise we'd hit infinite recursion here @assert !(F2 <: Function || (F2 <: AbstractArray && F2.parameters[1] <: Function)) # otherwise we'd hit infinite recursion here
x, f x, f
@ -458,19 +465,19 @@ end
xs = adapted_grid(f, (xmin, xmax)) xs = adapted_grid(f, (xmin, xmax))
xs, f xs, f
end end
@recipe function f{F<:Function}(fs::AbstractArray{F}, xmin::Number, xmax::Number) @recipe function f(fs::AbstractArray{F}, xmin::Number, xmax::Number) where F<:Function
xs = Any[adapted_grid(f, (xmin, xmax)) for f in fs] xs = Any[adapted_grid(f, (xmin, xmax)) for f in fs]
xs, fs xs, fs
end end
@recipe f{F<:Function,G<:Function}(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, u::AVec) = mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u) @recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, u::AVec) where {F<:Function,G<:Function} = mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u)
@recipe f{F<:Function,G<:Function}(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, umin::Number, umax::Number, n = 200) = fx, fy, linspace(umin, umax, n) @recipe f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, umin::Number, umax::Number, n = 200) where {F<:Function,G<:Function} = fx, fy, linspace(umin, umax, n)
# #
# # special handling... 3D parametric function(s) # # special handling... 3D parametric function(s)
@recipe function f{F<:Function,G<:Function,H<:Function}(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, u::AVec) @recipe function f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, u::AVec) where {F<:Function,G<:Function,H<:Function}
mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u) mapFuncOrFuncs(fx, u), mapFuncOrFuncs(fy, u), mapFuncOrFuncs(fz, u)
end end
@recipe function f{F<:Function,G<:Function,H<:Function}(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, umin::Number, umax::Number, numPoints = 200) @recipe function f(fx::FuncOrFuncs{F}, fy::FuncOrFuncs{G}, fz::FuncOrFuncs{H}, umin::Number, umax::Number, numPoints = 200) where {F<:Function,G<:Function,H<:Function}
fx, fy, fz, linspace(umin, umax, numPoints) fx, fy, fz, linspace(umin, umax, numPoints)
end end
@ -485,28 +492,28 @@ end
# #
# # (x,y) tuples # # (x,y) tuples
@recipe f{R1<:Number,R2<:Number}(xy::AVec{Tuple{R1,R2}}) = unzip(xy) @recipe f(xy::AVec{Tuple{R1,R2}}) where {R1<:Number,R2<:Number} = unzip(xy)
@recipe f{R1<:Number,R2<:Number}(xy::Tuple{R1,R2}) = [xy[1]], [xy[2]] @recipe f(xy::Tuple{R1,R2}) where {R1<:Number,R2<:Number} = [xy[1]], [xy[2]]
# #
# # (x,y,z) tuples # # (x,y,z) tuples
@recipe f{R1<:Number,R2<:Number,R3<:Number}(xyz::AVec{Tuple{R1,R2,R3}}) = unzip(xyz) @recipe f(xyz::AVec{Tuple{R1,R2,R3}}) where {R1<:Number,R2<:Number,R3<:Number} = unzip(xyz)
@recipe f{R1<:Number,R2<:Number,R3<:Number}(xyz::Tuple{R1,R2,R3}) = [xyz[1]], [xyz[2]], [xyz[3]] @recipe f(xyz::Tuple{R1,R2,R3}) where {R1<:Number,R2<:Number,R3<:Number} = [xyz[1]], [xyz[2]], [xyz[3]]
# these might be points+velocity, or OHLC or something else # these might be points+velocity, or OHLC or something else
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(xyuv::AVec{Tuple{R1,R2,R3,R4}}) = get(plotattributes,:seriestype,:path)==:ohlc ? OHLC[OHLC(t...) for t in xyuv] : unzip(xyuv) @recipe f(xyuv::AVec{Tuple{R1,R2,R3,R4}}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = get(plotattributes,:seriestype,:path)==:ohlc ? OHLC[OHLC(t...) for t in xyuv] : unzip(xyuv)
@recipe f{R1<:Number,R2<:Number,R3<:Number,R4<:Number}(xyuv::Tuple{R1,R2,R3,R4}) = [xyuv[1]], [xyuv[2]], [xyuv[3]], [xyuv[4]] @recipe f(xyuv::Tuple{R1,R2,R3,R4}) where {R1<:Number,R2<:Number,R3<:Number,R4<:Number} = [xyuv[1]], [xyuv[2]], [xyuv[3]], [xyuv[4]]
# #
# # 2D FixedSizeArrays # # 2D FixedSizeArrays
@recipe f{T<:Number}(xy::AVec{FixedSizeArrays.Vec{2,T}}) = unzip(xy) @recipe f(xy::AVec{FixedSizeArrays.Vec{2,T}}) where {T<:Number} = unzip(xy)
@recipe f{T<:Number}(xy::FixedSizeArrays.Vec{2,T}) = [xy[1]], [xy[2]] @recipe f(xy::FixedSizeArrays.Vec{2,T}) where {T<:Number} = [xy[1]], [xy[2]]
# #
# # 3D FixedSizeArrays # # 3D FixedSizeArrays
@recipe f{T<:Number}(xyz::AVec{FixedSizeArrays.Vec{3,T}}) = unzip(xyz) @recipe f(xyz::AVec{FixedSizeArrays.Vec{3,T}}) where {T<:Number} = unzip(xyz)
@recipe f{T<:Number}(xyz::FixedSizeArrays.Vec{3,T}) = [xyz[1]], [xyz[2]], [xyz[3]] @recipe f(xyz::FixedSizeArrays.Vec{3,T}) where {T<:Number} = [xyz[1]], [xyz[2]], [xyz[3]]
# #
# # -------------------------------------------------------------------- # # --------------------------------------------------------------------

View File

@ -1,6 +1,6 @@
function Subplot{T<:AbstractBackend}(::T; parent = RootLayout()) function Subplot(::T; parent = RootLayout()) where T<:AbstractBackend
Subplot{T}( Subplot{T}(
parent, parent,
Series[], Series[],

View File

@ -6,20 +6,20 @@ const AVec = AbstractVector
const AMat = AbstractMatrix const AMat = AbstractMatrix
const KW = Dict{Symbol,Any} const KW = Dict{Symbol,Any}
immutable PlotsDisplay <: Display end struct PlotsDisplay <: Display end
# ----------------------------------------------------------- # -----------------------------------------------------------
immutable InputWrapper{T} struct InputWrapper{T}
obj::T obj::T
end end
wrap{T}(obj::T) = InputWrapper{T}(obj) wrap(obj::T) where {T} = InputWrapper{T}(obj)
Base.isempty(wrapper::InputWrapper) = false Base.isempty(wrapper::InputWrapper) = false
# ----------------------------------------------------------- # -----------------------------------------------------------
type Series mutable struct Series
d::KW d::KW
end end
@ -29,7 +29,7 @@ attr!(series::Series, v, k::Symbol) = (series.d[k] = v)
# ----------------------------------------------------------- # -----------------------------------------------------------
# a single subplot # a single subplot
type Subplot{T<:AbstractBackend} <: AbstractLayout mutable struct Subplot{T<:AbstractBackend} <: AbstractLayout
parent::AbstractLayout parent::AbstractLayout
series_list::Vector{Series} # arguments for each series series_list::Vector{Series} # arguments for each series
minpad::Tuple # leftpad, toppad, rightpad, bottompad minpad::Tuple # leftpad, toppad, rightpad, bottompad
@ -45,12 +45,12 @@ Base.show(io::IO, sp::Subplot) = print(io, "Subplot{$(sp[:subplot_index])}")
# ----------------------------------------------------------- # -----------------------------------------------------------
# simple wrapper around a KW so we can hold all attributes pertaining to the axis in one place # simple wrapper around a KW so we can hold all attributes pertaining to the axis in one place
type Axis mutable struct Axis
sps::Vector{Subplot} sps::Vector{Subplot}
d::KW d::KW
end end
type Extrema mutable struct Extrema
emin::Float64 emin::Float64
emax::Float64 emax::Float64
end end
@ -63,7 +63,7 @@ const SubplotMap = Dict{Any, Subplot}
# ----------------------------------------------------------- # -----------------------------------------------------------
type Plot{T<:AbstractBackend} <: AbstractPlot{T} mutable struct Plot{T<:AbstractBackend} <: AbstractPlot{T}
backend::T # the backend type backend::T # the backend type
n::Int # number of series n::Int # number of series
attr::KW # arguments for the whole plot attr::KW # arguments for the whole plot

View File

@ -114,7 +114,7 @@ function regressionXY(x, y)
regx, regy regx, regy
end end
function replace_image_with_heatmap{T<:Colorant}(z::Array{T}) function replace_image_with_heatmap(z::Array{T}) where T<:Colorant
@show T, size(z) @show T, size(z)
n, m = size(z) n, m = size(z)
# idx = 0 # idx = 0
@ -138,14 +138,14 @@ end
# --------------------------------------------------------------- # ---------------------------------------------------------------
"Build line segments for plotting" "Build line segments for plotting"
type Segments{T} mutable struct Segments{T}
pts::Vector{T} pts::Vector{T}
end end
# Segments() = Segments{Float64}(zeros(0)) # Segments() = Segments{Float64}(zeros(0))
Segments() = Segments(Float64) Segments() = Segments(Float64)
Segments{T}(::Type{T}) = Segments(T[]) Segments(::Type{T}) where {T} = Segments(T[])
Segments(p::Int) = Segments(NTuple{2,Float64}[]) Segments(p::Int) = Segments(NTuple{2,Float64}[])
@ -157,7 +157,7 @@ to_nan(::Type{NTuple{2,Float64}}) = (NaN, NaN)
coords(segs::Segments{Float64}) = segs.pts coords(segs::Segments{Float64}) = segs.pts
coords(segs::Segments{NTuple{2,Float64}}) = Float64[p[1] for p in segs.pts], Float64[p[2] for p in segs.pts] coords(segs::Segments{NTuple{2,Float64}}) = Float64[p[1] for p in segs.pts], Float64[p[2] for p in segs.pts]
function Base.push!{T}(segments::Segments{T}, vs...) function Base.push!(segments::Segments{T}, vs...) where T
if !isempty(segments.pts) if !isempty(segments.pts)
push!(segments.pts, to_nan(T)) push!(segments.pts, to_nan(T))
end end
@ -167,7 +167,7 @@ function Base.push!{T}(segments::Segments{T}, vs...)
segments segments
end end
function Base.push!{T}(segments::Segments{T}, vs::AVec) function Base.push!(segments::Segments{T}, vs::AVec) where T
if !isempty(segments.pts) if !isempty(segments.pts)
push!(segments.pts, to_nan(T)) push!(segments.pts, to_nan(T))
end end
@ -181,7 +181,7 @@ end
# ----------------------------------------------------- # -----------------------------------------------------
# helper to manage NaN-separated segments # helper to manage NaN-separated segments
type SegmentsIterator mutable struct SegmentsIterator
args::Tuple args::Tuple
n::Int n::Int
end end
@ -232,8 +232,8 @@ end
# Find minimal type that can contain NaN and x # Find minimal type that can contain NaN and x
# To allow use of NaN separated segments with categorical x axis # To allow use of NaN separated segments with categorical x axis
float_extended_type{T}(x::AbstractArray{T}) = Union{T,Float64} float_extended_type(x::AbstractArray{T}) where {T} = Union{T,Float64}
float_extended_type{T<:Real}(x::AbstractArray{T}) = Float64 float_extended_type(x::AbstractArray{T}) where {T<:Real} = Float64
# ------------------------------------------------------------------------------------ # ------------------------------------------------------------------------------------
@ -259,27 +259,27 @@ _cycle(grad::ColorGradient, idx::Int) = _cycle(grad.colors, idx)
_cycle(grad::ColorGradient, indices::AVec{Int}) = _cycle(grad.colors, indices) _cycle(grad::ColorGradient, indices::AVec{Int}) = _cycle(grad.colors, indices)
makevec(v::AVec) = v makevec(v::AVec) = v
makevec{T}(v::T) = T[v] makevec(v::T) where {T} = T[v]
"duplicate a single value, or pass the 2-tuple through" "duplicate a single value, or pass the 2-tuple through"
maketuple(x::Real) = (x,x) maketuple(x::Real) = (x,x)
maketuple{T,S}(x::Tuple{T,S}) = x maketuple(x::Tuple{T,S}) where {T,S} = x
mapFuncOrFuncs(f::Function, u::AVec) = map(f, u) mapFuncOrFuncs(f::Function, u::AVec) = map(f, u)
mapFuncOrFuncs{F<:Function}(fs::AVec{F}, u::AVec) = [map(f, u) for f in fs] mapFuncOrFuncs(fs::AVec{F}, u::AVec) where {F<:Function} = [map(f, u) for f in fs]
unzip{X,Y}(xy::AVec{Tuple{X,Y}}) = [t[1] for t in xy], [t[2] for t in xy] unzip(xy::AVec{Tuple{X,Y}}) where {X,Y} = [t[1] for t in xy], [t[2] for t in xy]
unzip{X,Y,Z}(xyz::AVec{Tuple{X,Y,Z}}) = [t[1] for t in xyz], [t[2] for t in xyz], [t[3] for t in xyz] unzip(xyz::AVec{Tuple{X,Y,Z}}) where {X,Y,Z} = [t[1] for t in xyz], [t[2] for t in xyz], [t[3] for t in xyz]
unzip{X,Y,U,V}(xyuv::AVec{Tuple{X,Y,U,V}}) = [t[1] for t in xyuv], [t[2] for t in xyuv], [t[3] for t in xyuv], [t[4] for t in xyuv] unzip(xyuv::AVec{Tuple{X,Y,U,V}}) where {X,Y,U,V} = [t[1] for t in xyuv], [t[2] for t in xyuv], [t[3] for t in xyuv], [t[4] for t in xyuv]
unzip{T}(xy::AVec{FixedSizeArrays.Vec{2,T}}) = T[t[1] for t in xy], T[t[2] for t in xy] unzip(xy::AVec{FixedSizeArrays.Vec{2,T}}) where {T} = T[t[1] for t in xy], T[t[2] for t in xy]
unzip{T}(xy::FixedSizeArrays.Vec{2,T}) = T[xy[1]], T[xy[2]] unzip(xy::FixedSizeArrays.Vec{2,T}) where {T} = T[xy[1]], T[xy[2]]
unzip{T}(xyz::AVec{FixedSizeArrays.Vec{3,T}}) = T[t[1] for t in xyz], T[t[2] for t in xyz], T[t[3] for t in xyz] unzip(xyz::AVec{FixedSizeArrays.Vec{3,T}}) where {T} = T[t[1] for t in xyz], T[t[2] for t in xyz], T[t[3] for t in xyz]
unzip{T}(xyz::FixedSizeArrays.Vec{3,T}) = T[xyz[1]], T[xyz[2]], T[xyz[3]] unzip(xyz::FixedSizeArrays.Vec{3,T}) where {T} = T[xyz[1]], T[xyz[2]], T[xyz[3]]
unzip{T}(xyuv::AVec{FixedSizeArrays.Vec{4,T}}) = T[t[1] for t in xyuv], T[t[2] for t in xyuv], T[t[3] for t in xyuv], T[t[4] for t in xyuv] unzip(xyuv::AVec{FixedSizeArrays.Vec{4,T}}) where {T} = T[t[1] for t in xyuv], T[t[2] for t in xyuv], T[t[3] for t in xyuv], T[t[4] for t in xyuv]
unzip{T}(xyuv::FixedSizeArrays.Vec{4,T}) = T[xyuv[1]], T[xyuv[2]], T[xyuv[3]], T[xyuv[4]] unzip(xyuv::FixedSizeArrays.Vec{4,T}) where {T} = T[xyuv[1]], T[xyuv[2]], T[xyuv[3]], T[xyuv[4]]
# given 2-element lims and a vector of data x, widen lims to account for the extrema of x # given 2-element lims and a vector of data x, widen lims to account for the extrema of x
function _expand_limits(lims, x) function _expand_limits(lims, x)
@ -363,15 +363,26 @@ end
function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y)) function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y))
rmin, rmax = r_extrema rmin, rmax = r_extrema
phi, r = x, y theta, r = filter_radial_data(x, y, r_extrema)
r = (r - rmin) / (rmax - rmin) r = (r - rmin) / (rmax - rmin)
n = max(length(phi), length(r)) x = r.*cos.(theta)
x = zeros(n) y = r.*sin.(theta)
y = zeros(n) x, y
end
# Filters radial data for points within the axis limits
function filter_radial_data(theta, r, r_extrema::Tuple{Real, Real})
n = max(length(theta), length(r))
rmin, rmax = r_extrema
x, y = zeros(n), zeros(n)
for i in 1:n for i in 1:n
x[i] = _cycle(r,i) * cos.(_cycle(phi,i)) x[i] = _cycle(theta, i)
y[i] = _cycle(r,i) * sin.(_cycle(phi,i)) y[i] = _cycle(r, i)
end end
points = map((a, b) -> (a, b), x, y)
filter!(a -> a[2] >= rmin && a[2] <= rmax, points)
x = map(a -> a[1], points)
y = map(a -> a[2], points)
x, y x, y
end end
@ -388,7 +399,7 @@ isatom() = isdefined(Main, :Atom) && Main.Atom.isconnected()
function is_installed(pkgstr::AbstractString) function is_installed(pkgstr::AbstractString)
try try
Pkg.installed(pkgstr) === nothing ? false: true Pkg.installed(pkgstr) === nothing ? false : true
catch catch
false false
end end
@ -410,20 +421,20 @@ isvertical(d::KW) = get(d, :orientation, :vertical) in (:vertical, :v, :vert)
isvertical(series::Series) = isvertical(series.d) isvertical(series::Series) = isvertical(series.d)
ticksType{T<:Real}(ticks::AVec{T}) = :ticks ticksType(ticks::AVec{T}) where {T<:Real} = :ticks
ticksType{T<:AbstractString}(ticks::AVec{T}) = :labels ticksType(ticks::AVec{T}) where {T<:AbstractString} = :labels
ticksType{T<:AVec,S<:AVec}(ticks::Tuple{T,S}) = :ticks_and_labels ticksType(ticks::Tuple{T,S}) where {T<:AVec,S<:AVec} = :ticks_and_labels
ticksType(ticks) = :invalid ticksType(ticks) = :invalid
limsType{T<:Real,S<:Real}(lims::Tuple{T,S}) = :limits limsType(lims::Tuple{T,S}) where {T<:Real,S<:Real} = :limits
limsType(lims::Symbol) = lims == :auto ? :auto : :invalid limsType(lims::Symbol) = lims == :auto ? :auto : :invalid
limsType(lims) = :invalid limsType(lims) = :invalid
# axis_Symbol(letter, postfix) = Symbol(letter * postfix) # axis_Symbol(letter, postfix) = Symbol(letter * postfix)
# axis_symbols(letter, postfix...) = map(s -> axis_Symbol(letter, s), postfix) # axis_symbols(letter, postfix...) = map(s -> axis_Symbol(letter, s), postfix)
Base.convert{T<:Real}(::Type{Vector{T}}, rng::Range{T}) = T[x for x in rng] Base.convert(::Type{Vector{T}}, rng::Range{T}) where {T<:Real} = T[x for x in rng]
Base.convert{T<:Real,S<:Real}(::Type{Vector{T}}, rng::Range{S}) = T[x for x in rng] Base.convert(::Type{Vector{T}}, rng::Range{S}) where {T<:Real,S<:Real} = T[x for x in rng]
Base.merge(a::AbstractVector, b::AbstractVector) = sort(unique(vcat(a,b))) Base.merge(a::AbstractVector, b::AbstractVector) = sort(unique(vcat(a,b)))
@ -727,7 +738,7 @@ end
# --------------------------------------------------------------- # ---------------------------------------------------------------
# --------------------------------------------------------------- # ---------------------------------------------------------------
type DebugMode mutable struct DebugMode
on::Bool on::Bool
end end
const _debugMode = DebugMode(false) const _debugMode = DebugMode(false)
@ -765,10 +776,10 @@ end
extendSeriesByOne(v::UnitRange{Int}, n::Int = 1) = isempty(v) ? (1:n) : (minimum(v):maximum(v)+n) extendSeriesByOne(v::UnitRange{Int}, n::Int = 1) = isempty(v) ? (1:n) : (minimum(v):maximum(v)+n)
extendSeriesByOne(v::AVec, n::Integer = 1) = isempty(v) ? (1:n) : vcat(v, (1:n) + ignorenan_maximum(v)) extendSeriesByOne(v::AVec, n::Integer = 1) = isempty(v) ? (1:n) : vcat(v, (1:n) + ignorenan_maximum(v))
extendSeriesData{T}(v::Range{T}, z::Real) = extendSeriesData(float(collect(v)), z) extendSeriesData(v::Range{T}, z::Real) where {T} = extendSeriesData(float(collect(v)), z)
extendSeriesData{T}(v::Range{T}, z::AVec) = extendSeriesData(float(collect(v)), z) extendSeriesData(v::Range{T}, z::AVec) where {T} = extendSeriesData(float(collect(v)), z)
extendSeriesData{T}(v::AVec{T}, z::Real) = (push!(v, convert(T, z)); v) extendSeriesData(v::AVec{T}, z::Real) where {T} = (push!(v, convert(T, z)); v)
extendSeriesData{T}(v::AVec{T}, z::AVec) = (append!(v, convert(Vector{T}, z)); v) extendSeriesData(v::AVec{T}, z::AVec) where {T} = (append!(v, convert(Vector{T}, z)); v)
# ------------------------------------------------------- # -------------------------------------------------------
@ -786,14 +797,14 @@ function getxyz(plt::Plot, i::Integer)
tovec(d[:x]), tovec(d[:y]), tovec(d[:z]) tovec(d[:x]), tovec(d[:y]), tovec(d[:z])
end end
function setxy!{X,Y}(plt::Plot, xy::Tuple{X,Y}, i::Integer) function setxy!(plt::Plot, xy::Tuple{X,Y}, i::Integer) where {X,Y}
series = plt.series_list[i] series = plt.series_list[i]
series.d[:x], series.d[:y] = xy series.d[:x], series.d[:y] = xy
sp = series.d[:subplot] sp = series.d[:subplot]
reset_extrema!(sp) reset_extrema!(sp)
_series_updated(plt, series) _series_updated(plt, series)
end end
function setxyz!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) function setxyz!(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) where {X,Y,Z}
series = plt.series_list[i] series = plt.series_list[i]
series.d[:x], series.d[:y], series.d[:z] = xyz series.d[:x], series.d[:y], series.d[:z] = xyz
sp = series.d[:subplot] sp = series.d[:subplot]
@ -801,7 +812,7 @@ function setxyz!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer)
_series_updated(plt, series) _series_updated(plt, series)
end end
function setxyz!{X,Y,Z<:AbstractMatrix}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) function setxyz!(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) where {X,Y,Z<:AbstractMatrix}
setxyz!(plt, (xyz[1], xyz[2], Surface(xyz[3])), i) setxyz!(plt, (xyz[1], xyz[2], Surface(xyz[3])), i)
end end
@ -810,8 +821,8 @@ end
# indexing notation # indexing notation
# Base.getindex(plt::Plot, i::Integer) = getxy(plt, i) # Base.getindex(plt::Plot, i::Integer) = getxy(plt, i)
Base.setindex!{X,Y}(plt::Plot, xy::Tuple{X,Y}, i::Integer) = (setxy!(plt, xy, i); plt) Base.setindex!(plt::Plot, xy::Tuple{X,Y}, i::Integer) where {X,Y} = (setxy!(plt, xy, i); plt)
Base.setindex!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) = (setxyz!(plt, xyz, i); plt) Base.setindex!(plt::Plot, xyz::Tuple{X,Y,Z}, i::Integer) where {X,Y,Z} = (setxyz!(plt, xyz, i); plt)
# ------------------------------------------------------- # -------------------------------------------------------
@ -923,10 +934,10 @@ function Base.append!(plt::Plot, i::Integer, x::AVec, y::AVec, z::AVec)
end end
# tuples # tuples
Base.push!{X,Y}(plt::Plot, xy::Tuple{X,Y}) = push!(plt, 1, xy...) Base.push!(plt::Plot, xy::Tuple{X,Y}) where {X,Y} = push!(plt, 1, xy...)
Base.push!{X,Y,Z}(plt::Plot, xyz::Tuple{X,Y,Z}) = push!(plt, 1, xyz...) Base.push!(plt::Plot, xyz::Tuple{X,Y,Z}) where {X,Y,Z} = push!(plt, 1, xyz...)
Base.push!{X,Y}(plt::Plot, i::Integer, xy::Tuple{X,Y}) = push!(plt, i, xy...) Base.push!(plt::Plot, i::Integer, xy::Tuple{X,Y}) where {X,Y} = push!(plt, i, xy...)
Base.push!{X,Y,Z}(plt::Plot, i::Integer, xyz::Tuple{X,Y,Z}) = push!(plt, i, xyz...) Base.push!(plt::Plot, i::Integer, xyz::Tuple{X,Y,Z}) where {X,Y,Z} = push!(plt, i, xyz...)
# ------------------------------------------------------- # -------------------------------------------------------
# push/append for all series # push/append for all series
@ -996,3 +1007,43 @@ xmax(plt::Plot) = ignorenan_maximum([ignorenan_maximum(series.d[:x]) for series
"Extrema of x-values in plot" "Extrema of x-values in plot"
ignorenan_extrema(plt::Plot) = (xmin(plt), xmax(plt)) ignorenan_extrema(plt::Plot) = (xmin(plt), xmax(plt))
# ---------------------------------------------------------------
# get fonts from objects:
titlefont(sp::Subplot) = font(
sp[:titlefontfamily],
sp[:titlefontsize],
sp[:titlefontvalign],
sp[:titlefonthalign],
sp[:titlefontrotation],
sp[:titlefontcolor],
)
legendfont(sp::Subplot) = font(
sp[:legendfontfamily],
sp[:legendfontsize],
sp[:legendfontvalign],
sp[:legendfonthalign],
sp[:legendfontrotation],
sp[:legendfontcolor],
)
tickfont(ax::Axis) = font(
ax[:tickfontfamily],
ax[:tickfontsize],
ax[:tickfontvalign],
ax[:tickfonthalign],
ax[:tickfontrotation],
ax[:tickfontcolor],
)
guidefont(ax::Axis) = font(
ax[:guidefontfamily],
ax[:guidefontsize],
ax[:guidefontvalign],
ax[:guidefonthalign],
ax[:guidefontrotation],
ax[:guidefontcolor],
)

View File

@ -23,7 +23,7 @@ default(size=(500,300))
# TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that # 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) # is referenced in a button press callback (the button clicked callback will call notify() on that condition)
const _current_plots_version = v"0.12.4" const _current_plots_version = v"0.13.1"
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2) function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)

View File

@ -16,12 +16,12 @@ img_eps = isinteractive() ? 1e-2 : 10e-2
end end
@testset "PyPlot" begin #@testset "PyPlot" begin
@test pyplot() == Plots.PyPlotBackend() # @test pyplot() == Plots.PyPlotBackend()
@test backend() == Plots.PyPlotBackend() # @test backend() == Plots.PyPlotBackend()
#
image_comparison_facts(:pyplot, eps=img_eps) # image_comparison_facts(:pyplot, eps=img_eps)
end #end
@testset "UnicodePlots" begin @testset "UnicodePlots" begin
@test unicodeplots() == Plots.UnicodePlotsBackend() @test unicodeplots() == Plots.UnicodePlotsBackend()