Compare commits

..

3 Commits

Author SHA1 Message Date
Michael Krabbe Borregaard 45a04d5309 Merge pull request #713 from oschulz/new-hist-dev
Change histogram implementation, use StatsPlots, add new histogram st…
2017-03-01 22:32:06 +01:00
Oliver Schulz 6420f6fdc9 Conform to Plots.jl coding style 2017-03-01 17:33:22 +01:00
Oliver Schulz 19a9726e61 Change histogram implementation, use StatsPlots, add new histogram styles
New series recipes for binned data:

* barbins
* scatterbins
* stepbins

New series recipes for histogram:

* barhist (histogram is now an alias for this)
* scatterhist
* stephist

Supports plotting 1D and 2D StatsBase histograms, seriestype can be set to
bar(bins), scatter(bins) or step(bins).

Also adds support for some common auto-binning modes:

* :sturges, :auto - Sturges' formula
* :sqrt - Square-root choice
* :rice - Rice Rule
* :scott - Scott's normal reference rule
* :fd - Freedman–Diaconis rule

Maybe these could be contributed to StatsBase at some point.

Error bars currently don't work correctly for scatterbins and scatterhist,
due to problem with manipulating error bars in a series recipe, but do work
for "plot(h::StatsBase.Histogram, seriestype = :scatter)" (works around
the problem by calling scatter directly, it seems that error bars can be
manipulated correctly in a type recipe).
2017-03-01 14:24:00 +01:00
34 changed files with 340 additions and 1357 deletions
+4 -49
View File
@@ -3,59 +3,14 @@
#### notes on release changes, ongoing development, and future planned work
- All new development should target 0.12!
- Minor version 0.11 is the last one to support Julia 0.5!!
- All new development should target 0.9!
- Minor version 0.8 is the last one to support Julia 0.4!!
- Critical bugfixes only
- `backports` branch is for Julia 0.4
---
## 0.11 (current master/dev)
#### 0.11.3
- add HDF5 backend
- GR replaces PyPlot as first-choice backend
- support for legend position in GR
- smaller markers in GR
- better viewport size in GR
- fix glvisualize support
- remove bug with three-argument method of `text`
- `legendtitle` attribute added
- add test for `spy`
#### 0.11.0
- julia 0.6 compatibility
- matplotlib 0.2.0 compatibility
- add inspectdr backend
- improved histogram functionality:
- added a `:stephist` and `:scatterhist` series type as well as ``:barhist` (the default)
- support for log scale axes with histograms
- support for plotting `StatsBase.Histogram`
- allowing bins to be specified as `:sturges`, `:rice`, `:scott` or :fd
- allow `normalization` to be specified as :density (for unequal bins) or :pdf (sum to 1)
- add a `plotattr` function to access documentation for Plots attribute
- add `fill_z` attribute for pyplot
- add colorbar_title to plotlyjs
- enable standalone window for plotlyjs
- improved support for pgfplots, ticks rotation, clims, series_annotations
- restore colorbars for GR
- better axis labels for heatmap in GR
- better marker sizes in GR
- fix color representation in GR
- update GR legend
- fix image bug on GR
- fix glvisualize dependencies
- set dotted grid lines for pyplot
- several improvements to inspectdr
- improved tick positions for TimeType x axes
- support for improved color gradient capability in PlotUtils
- add a showlibrary recipe to display color libraries
- add a showgradient recipe to display color gradients
- add `vectorfield` as an alias for `quiver`
- use `PlotUtils.adaptedgrid` for functions
## 0.9 (current master/dev)
#### 0.9.5
@@ -376,7 +331,7 @@
- z-axis keywords
- 3D indexing overhaul: `push!`, `append!` support
- matplotlib colormap constants (`:inferno` is the new default colormap for Plots)
- `const KW = Dict{Symbol,Any}` used in place of splatting in many places
- `typealias KW Dict{Symbol,Any}` used in place of splatting in many places
- png generation for plotly backend using wkhtmltoimage
- `normalize` and `weights` keywords
- background/foreground subcategories for fine-tuning of looks
+1 -1
View File
@@ -1,6 +1,6 @@
# 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/tbreloff/Plots.jl.svg?branch=master)](https://travis-ci.org/tbreloff/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)
<!-- [![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) -->
+3 -6
View File
@@ -1,13 +1,10 @@
julia 0.5
RecipesBase
PlotUtils 0.4.1
PlotThemes 0.1.3
PlotUtils
PlotThemes
Reexport
FixedSizeArrays
FixedPointNumbers 0.3
Measures
Showoff
StatsBase 0.14.0
JSON
NaNMath
StatsBase
+5 -6
View File
@@ -1,9 +1,9 @@
environment:
matrix:
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.5/julia-0.5-latest-win32.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.5/julia-0.5-latest-win64.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
- JULIAVERSION: "julialang/bin/winnt/x86/0.5/julia-0.5-latest-win32.exe"
- JULIAVERSION: "julialang/bin/winnt/x64/0.5/julia-0.5-latest-win64.exe"
- JULIAVERSION: "julianightlies/bin/winnt/x86/julia-latest-win32.exe"
- JULIAVERSION: "julianightlies/bin/winnt/x64/julia-latest-win64.exe"
notifications:
- provider: Email
@@ -12,14 +12,13 @@ notifications:
on_build_status_changed: false
install:
- ps: "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12"
# If there's a newer build queued for the same PR, cancel this one
- ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
throw "There are newer queued builds for this pull request, failing early." }
# Download most recent Julia Windows binary
- ps: (new-object net.webclient).DownloadFile($env:JULIA_URL, "C:\projects\julia-binary.exe")
- ps: (new-object net.webclient).DownloadFile($("http://s3.amazonaws.com/"+$env:JULIAVERSION), "C:\projects\julia-binary.exe")
# Run installer silently, output to C:\projects\julia
- C:\projects\julia-binary.exe /S /D=C:\projects\julia
+3 -15
View File
@@ -1,4 +1,4 @@
__precompile__(false)
__precompile__(true)
module Plots
@@ -106,21 +106,9 @@ export
# ---------------------------------------------------------
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) = Base.minimum(x)
ignoreNaN_maximum{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.maximum(x)
ignoreNaN_maximum(x) = Base.maximum(x)
ignoreNaN_mean{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.mean(x)
ignoreNaN_mean(x) = Base.mean(x)
ignoreNaN_extrema{F<:AbstractFloat}(x::AbstractArray{F}) = NaNMath.extrema(x)
ignoreNaN_extrema(x) = Base.extrema(x)
# ---------------------------------------------------------
import Measures
import Measures: Length, AbsoluteLength, Measure, BoundingBox, mm, cm, inch, pt, width, height, w, h
const BBox = Measures.Absolute2DBox
typealias BBox Measures.Absolute2DBox
export BBox, BoundingBox, mm, cm, inch, pt, px, pct, w, h
# ---------------------------------------------------------
@@ -130,6 +118,7 @@ include("utils.jl")
include("components.jl")
include("axes.jl")
include("args.jl")
include("backends.jl")
include("themes.jl")
include("plot.jl")
include("pipeline.jl")
@@ -142,7 +131,6 @@ include("output.jl")
include("examples.jl")
include("arg_desc.jl")
include("plotattr.jl")
include("backends.jl")
# ---------------------------------------------------------
+1 -2
View File
@@ -80,8 +80,7 @@ function buildanimation(animdir::AbstractString, fn::AbstractString;
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.
ImageMagick can be installed by executing `Pkg.add("ImageMagick")`
Will try ffmpeg, but it's lower quality...)""")
# low quality
+2 -3
View File
@@ -21,7 +21,7 @@ const _arg_desc = KW(
:markerstrokewidth => "Number. Width of the marker stroke (border. in pixels)",
:markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:foreground_color_subplot`.",
:markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.",
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto. For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `linspace(extrema(x)..., 25)`",
:bins => "Integer, NTuple{2,Integer}, AbstractVector. For histogram-types, defines the number of bins, or the edges, of the histogram.",
:smooth => "Bool. Add a regression line?",
:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.",
:x => "Various. Input data. First Dimension",
@@ -40,7 +40,7 @@ const _arg_desc = KW(
:ribbon => "Number or AbstractVector. Creates a fillrange around the data points.",
:quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.",
:arrow => "nothing (no arrows), Bool (if true, default arrows), Arrow object, or arg(s) that could be style or head length/widths. Defines arrowheads that should be displayed at the end of path line segments (just before a NaN and the last non-NaN point). Used in quiverplot, streamplot, or similar.",
:normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a PDF with integral of 1) and :density (only normalize in respect to bin sizes).",
:normalize => "Bool. Should normalize histogram types? Trying for area == 1.",
:weights => "AbstractVector. Used in histogram types for weighted counts.",
:contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.",
:match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.",
@@ -80,7 +80,6 @@ const _arg_desc = KW(
: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.",
: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.",
:colorbar => "Bool (show the colorbar?) or Symbol (colorbar position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:legend` (matches legend value) (note: only some may be supported in each backend)",
:clims => "`:auto` or NTuple{2,Number}. Fixes the limits of the colorbar.",
:legendfont => "Font. Font of legend items.",
+4 -11
View File
@@ -35,9 +35,7 @@ const _3dTypes = [
]
const _allTypes = vcat([
:none, :line, :path, :steppre, :steppost, :sticks, :scatter,
:heatmap, :hexbin, :barbins, :barhist, :histogram, :scatterbins,
:scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :histogram3d,
:density, :bar, :hline, :vline,
:heatmap, :hexbin, :histogram, :histogram2d, :histogram3d, :density, :bar, :hline, :vline,
:contour, :pie, :shape, :image
], _3dTypes)
@@ -67,7 +65,6 @@ const _typeAliases = Dict{Symbol,Symbol}(
:polygon => :shape,
:box => :boxplot,
:velocity => :quiver,
:vectorfield => :quiver,
:gradient => :quiver,
:img => :image,
:imshow => :image,
@@ -80,7 +77,7 @@ const _typeAliases = Dict{Symbol,Symbol}(
add_non_underscore_aliases!(_typeAliases)
like_histogram(seriestype::Symbol) = seriestype in (:histogram, :barhist, :barbins)
like_histogram(seriestype::Symbol) = seriestype in (:histogram, :barhist, :barbins, :density)
like_line(seriestype::Symbol) = seriestype in (:line, :path, :steppre, :steppost)
like_surface(seriestype::Symbol) = seriestype in (:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image)
@@ -156,8 +153,6 @@ const _markerAliases = Dict{Symbol,Symbol}(
)
const _allScales = [:identity, :ln, :log2, :log10, :asinh, :sqrt]
const _logScales = [:ln, :log2, :log10]
const _logScaleBases = Dict(:ln => e, :log2 => 2.0, :log10 => 10.0)
const _scaleAliases = Dict{Symbol,Symbol}(
:none => :identity,
:log => :log10,
@@ -185,7 +180,7 @@ const _series_defaults = KW(
:markerstrokewidth => 1,
:markerstrokecolor => :match,
:markerstrokealpha => nothing,
:bins => :auto, # number of bins for hists
:bins => 30, # number of bins for hists
:smooth => false, # regression line?
:group => nothing, # groupby vector
:x => nothing,
@@ -251,7 +246,6 @@ const _subplot_defaults = KW(
:foreground_color_title => :match, # title color
:color_palette => :auto,
:legend => :best,
:legendtitle => nothing,
:colorbar => :legend,
:clims => :auto,
:legendfont => font(8),
@@ -440,7 +434,6 @@ add_aliases(:zticks, :ztick)
add_aliases(:zrotation, :zrot, :zr)
add_aliases(:fill_z, :fillz, :fz, :surfacecolor, :surfacecolour, :sc, :surfcolor, :surfcolour)
add_aliases(:legend, :leg, :key)
add_aliases(:legendtitle, :legend_title, :labeltitle, :label_title, :leg_title, :key_title)
add_aliases(:colorbar, :cb, :cbar, :colorkey)
add_aliases(:clims, :clim, :cbarlims, :cbar_lims, :climits, :color_limits)
add_aliases(:smooth, :regression, :reg)
@@ -452,7 +445,7 @@ add_aliases(:color_palette, :palette)
add_aliases(:overwrite_figure, :clf, :clearfig, :overwrite, :reuse)
add_aliases(:xerror, :xerr, :xerrorbar)
add_aliases(:yerror, :yerr, :yerrorbar, :err, :errorbar)
add_aliases(:quiver, :velocity, :quiver2d, :gradient, :vectorfield)
add_aliases(:quiver, :velocity, :quiver2d, :gradient)
add_aliases(:normalize, :norm, :normed, :normalized)
add_aliases(:aspect_ratio, :aspectratio, :axis_ratio, :axisratio, :ratio)
add_aliases(:match_dimensions, :transpose, :transpose_z)
+13 -37
View File
@@ -118,7 +118,7 @@ Base.show(io::IO, axis::Axis) = dumpdict(axis.d, "Axis", true)
# Base.getindex(axis::Axis, k::Symbol) = getindex(axis.d, k)
Base.setindex!(axis::Axis, v, ks::Symbol...) = setindex!(axis.d, v, ks...)
Base.haskey(axis::Axis, k::Symbol) = haskey(axis.d, k)
ignoreNaN_extrema(axis::Axis) = (ex = axis[:extrema]; (ex.emin, ex.emax))
Base.extrema(axis::Axis) = (ex = axis[:extrema]; (ex.emin, ex.emax))
const _scale_funcs = Dict{Symbol,Function}(
@@ -156,30 +156,6 @@ function optimal_ticks_and_labels(axis::Axis, ticks = nothing)
scale = axis[:scale]
sf = scalefunc(scale)
# If the axis input was a Date or DateTime use a special logic to find
# "round" Date(Time)s as ticks
# This bypasses the rest of optimal_ticks_and_labels, because
# optimize_datetime_ticks returns ticks AND labels: the label format (Date
# or DateTime) is chosen based on the time span between amin and amax
# rather than on the input format
# TODO: maybe: non-trivial scale (:ln, :log2, :log10) for date/datetime
if ticks == nothing && scale == :identity
if axis[:formatter] == dateformatter
# optimize_datetime_ticks returns ticks and labels(!) based on
# integers/floats corresponding to the DateTime type. Thus, the axes
# limits, which resulted from converting the Date type to integers,
# are converted to 'DateTime integers' (actually floats) before
# being passed to optimize_datetime_ticks.
# (convert(Int, convert(DateTime, convert(Date, i))) == 87600000*i)
ticks, labels = optimize_datetime_ticks(864e5 * amin, 864e5 * amax;
k_min = 2, k_max = 4)
# Now the ticks are converted back to floats corresponding to Dates.
return ticks / 864e5, labels
elseif axis[:formatter] == datetimeformatter
return optimize_datetime_ticks(amin, amax; k_min = 2, k_max = 4)
end
end
# get a list of well-laid-out ticks
scaled_ticks = if ticks == nothing
optimize_ticks(
@@ -229,7 +205,7 @@ function get_ticks(axis::Axis)
elseif typeof(ticks) <: AVec
# override ticks, but get the labels
optimal_ticks_and_labels(axis, ticks)
elseif typeof(ticks) <: NTuple{2, Any}
elseif typeof(ticks) <: NTuple{2}
# assuming we're passed (ticks, labels)
ticks
else
@@ -238,7 +214,7 @@ function get_ticks(axis::Axis)
# @show ticks dvals cv dv
# TODO: better/smarter cutoff values for sampling ticks
if length(cv) > 30 && ticks == :auto
if length(cv) > 30
rng = Int[round(Int,i) for i in linspace(1, length(cv), 15)]
cv[rng], dv[rng]
else
@@ -260,8 +236,8 @@ end
function expand_extrema!(ex::Extrema, v::Number)
ex.emin = NaNMath.min(v, ex.emin)
ex.emax = NaNMath.max(v, ex.emax)
ex.emin = min(v, ex.emin)
ex.emax = max(v, ex.emax)
ex
end
@@ -276,8 +252,8 @@ expand_extrema!(axis::Axis, ::Bool) = axis[:extrema]
function expand_extrema!{MIN<:Number,MAX<:Number}(axis::Axis, v::Tuple{MIN,MAX})
ex = axis[:extrema]
ex.emin = NaNMath.min(v[1], ex.emin)
ex.emax = NaNMath.max(v[2], ex.emax)
ex.emin = min(v[1], ex.emin)
ex.emax = max(v[2], ex.emax)
ex
end
function expand_extrema!{N<:Number}(axis::Axis, v::AVec{N})
@@ -349,11 +325,11 @@ function expand_extrema!(sp::Subplot, d::KW)
bw = d[:bar_width]
if bw == nothing
bw = d[:bar_width] = ignoreNaN_mean(diff(data))
bw = d[:bar_width] = mean(diff(data))
end
axis = sp.attr[Symbol(dsym, :axis)]
expand_extrema!(axis, ignoreNaN_maximum(data) + 0.5maximum(bw))
expand_extrema!(axis, ignoreNaN_minimum(data) - 0.5minimum(bw))
expand_extrema!(axis, maximum(data) + 0.5maximum(bw))
expand_extrema!(axis, minimum(data) - 0.5minimum(bw))
end
end
@@ -368,8 +344,8 @@ end
# push the limits out slightly
function widen(lmin, lmax)
span = lmax - lmin
# eps = NaNMath.max(1e-16, min(1e-2span, 1e-10))
eps = NaNMath.max(1e-16, 0.03span)
# eps = max(1e-16, min(1e-2span, 1e-10))
eps = max(1e-16, 0.03span)
lmin-eps, lmax+eps
end
@@ -425,7 +401,7 @@ function discrete_value!(axis::Axis, dv)
# @show axis[:discrete_map], axis[:discrete_values], dv
if cv_idx == -1
ex = axis[:extrema]
cv = NaNMath.max(0.5, ex.emax + 1.0)
cv = max(0.5, ex.emax + 1.0)
expand_extrema!(axis, cv)
push!(axis[:discrete_values], dv)
push!(axis[:continuous_values], cv)
+1 -2
View File
@@ -148,7 +148,7 @@ function pickDefaultBackend()
# the ordering/inclusion of this package list is my semi-arbitrary guess at
# which one someone will want to use if they have the package installed...accounting for
# features, speed, and robustness
for pkgstr in ("GR", "PyPlot", "PlotlyJS", "PGFPlots", "UnicodePlots", "InspectDR", "GLVisualize")
for pkgstr in ("PyPlot", "GR", "PlotlyJS", "Immerse", "Gadfly", "UnicodePlots")
if Pkg.installed(pkgstr) != nothing
return backend(Symbol(lowercase(pkgstr)))
end
@@ -277,7 +277,6 @@ end
@init_backend GLVisualize
@init_backend PGFPlots
@init_backend InspectDR
@init_backend HDF5
# ---------------------------------------------------------
+78 -34
View File
@@ -1,4 +1,4 @@
#=
``#=
TODO
* move all gl_ methods to GLPlot
* integrate GLPlot UI
@@ -7,6 +7,7 @@ TODO
* polar plots
* labes and axis
* fix units in all visuals (e.g dotted lines, marker scale, surfaces)
* why is there so little unicode supported in the font!??!?
=#
const _glvisualize_attr = merge_with_base_supported([
@@ -77,9 +78,14 @@ end
function add_backend_string(b::GLVisualizeBackend)
"""
if !Plots.is_installed("GLVisualize")
Pkg.add("GLVisualize")
end
For those incredibly brave souls who assume full responsibility for what happens next...
There's an easy way to get what you need for the GLVisualize backend to work (until Pkg3 is usable):
Pkg.clone("https://github.com/tbreloff/MetaPkg.jl")
using MetaPkg
meta_checkout("MetaGL")
See the MetaPkg readme for details...
"""
end
@@ -93,6 +99,46 @@ end
# end
const _glplot_deletes = []
function close_child_signals!(screen)
for child in screen.children
for (k, s) in child.inputs
empty!(s.actions)
end
for (k, cam) in child.cameras
for f in fieldnames(cam)
s = getfield(cam, f)
if isa(s, Signal)
close(s, false)
end
end
end
empty!(child.cameras)
close_child_signals!(child)
end
return
end
function empty_screen!(screen)
if isempty(_glplot_deletes)
close_child_signals!(screen)
empty!(screen)
empty!(screen.cameras)
for (k, s) in screen.inputs
empty!(s.actions)
end
empty!(screen)
else
for del_signal in _glplot_deletes
push!(del_signal, true) # trigger delete
end
empty!(_glplot_deletes)
end
nothing
end
function poll_reactive()
# run_till_now blocks when message queue is empty!
Base.n_avail(Reactive._messages) > 0 && Reactive.run_till_now()
end
function get_plot_screen(list::Vector, name, result = [])
for elem in list
@@ -109,36 +155,38 @@ function get_plot_screen(screen, name, result = [])
end
function create_window(plt::Plot{GLVisualizeBackend}, visible)
name = Symbol("__Plots.jl")
name = Symbol("Plots.jl")
# make sure we have any screen open
if isempty(GLVisualize.get_screens())
# create a fresh, new screen
parent_screen = GLVisualize.glscreen(
"Plots",
"Plot",
resolution = plt[:size],
visible = visible
)
@async GLWindow.renderloop(parent_screen)
GLVisualize.add_screen(parent_screen)
@async GLWindow.waiting_renderloop(parent_screen)
end
# now lets get ourselves a permanent Plotting screen
plot_screens = get_plot_screen(GLVisualize.current_screen(), name)
plot_screens = get_plot_screen(GLVisualize.get_screens(), name)
screen = if isempty(plot_screens) # no screen with `name`
parent = GLVisualize.current_screen()
screen = GLWindow.Screen(
parent, area = map(GLWindow.zeroposition, parent.area),
name = name
)
for (k, s) in screen.inputs # copy signals, so we can clean them up better
screen.inputs[k] = map(identity, s)
end
screen
elseif length(plot_screens) == 1
plot_screens[1]
else
# okay this is silly! Lets see if we can. There is an ID we could use
# will not be fine for more than 255 screens though -.-.
error("multiple Plot screens. Please don't use any screen with the name $name")
error("multiple Plot screens. Please don't use any screen with the name Plots.jl")
end
# Since we own this window, we can do deep cleansing
empty!(screen)
empty_screen!(screen)
plt.o = screen
GLWindow.set_visibility!(screen, visible)
resize!(screen, plt[:size]...)
@@ -304,7 +352,7 @@ function extract_any_color(d, kw_args)
kw_args[:color_norm] = Vec2f0(clims)
end
elseif clims == :auto
kw_args[:color_norm] = Vec2f0(ignoreNaN_extrema(d[:y]))
kw_args[:color_norm] = Vec2f0(extrema(d[:y]))
end
end
else
@@ -315,7 +363,7 @@ function extract_any_color(d, kw_args)
kw_args[:color_norm] = Vec2f0(clims)
end
elseif clims == :auto
kw_args[:color_norm] = Vec2f0(ignoreNaN_extrema(d[:y]))
kw_args[:color_norm] = Vec2f0(extrema(d[:y]))
else
error("Unsupported limits: $clims")
end
@@ -367,14 +415,14 @@ end
dist(a, b) = abs(a-b)
mindist(x, a, b) = NaNMath.min(dist(a, x), dist(b, x))
mindist(x, a, b) = min(dist(a, x), dist(b, x))
function gappy(x, ps)
n = length(ps)
x <= first(ps) && return first(ps) - x
for j=1:(n-1)
p0 = ps[j]
p1 = ps[NaNMath.min(j+1, n)]
p1 = ps[min(j+1, n)]
if p0 <= x && p1 >= x
return mindist(x, p0, p1) * (isodd(j) ? 1 : -1)
end
@@ -482,7 +530,7 @@ function hover(to_hover, to_display, window)
end
function extract_extrema(d, kw_args)
xmin, xmax = ignoreNaN_extrema(d[:x]); ymin, ymax = ignoreNaN_extrema(d[:y])
xmin, xmax = extrema(d[:x]); ymin, ymax = extrema(d[:y])
kw_args[:primitive] = GeometryTypes.SimpleRectangle{Float32}(xmin, ymin, xmax-xmin, ymax-ymin)
nothing
end
@@ -509,7 +557,7 @@ function extract_colornorm(d, kw_args)
else
d[:y]
end
kw_args[:color_norm] = Vec2f0(ignoreNaN_extrema(z))
kw_args[:color_norm] = Vec2f0(extrema(z))
kw_args[:intensity] = map(Float32, collect(z))
end
end
@@ -649,7 +697,7 @@ function draw_ticks(
text, positions, offsets
end
function glvisualize_text(position, text, kw_args)
function text(position, text, kw_args)
text_align = alignment2num(text.font)
startpos = Vec2f0(position)
atlas = GLVisualize.get_texture_atlas()
@@ -726,7 +774,7 @@ function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, are
kw = Dict(:model => text_model(font, xy), :scale_primitive => true)
extract_font(font, kw)
t = PlotText(sp[:title], font)
push!(axis_vis, glvisualize_text(xy, t, kw))
push!(axis_vis, text(xy, t, kw))
end
if xaxis[:guide] != ""
tf = xaxis[:guidefont]; color = gl_color(xaxis[:foreground_color_guide])
@@ -735,7 +783,7 @@ function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, are
kw = Dict(:model => text_model(font, xy), :scale_primitive => true)
t = PlotText(xaxis[:guide], font)
extract_font(font, kw)
push!(axis_vis, glvisualize_text(xy, t, kw))
push!(axis_vis, text(xy, t, kw))
end
if yaxis[:guide] != ""
@@ -745,7 +793,7 @@ function gl_draw_axes_2d(sp::Plots.Subplot{Plots.GLVisualizeBackend}, model, are
kw = Dict(:model => text_model(font, xy), :scale_primitive=>true)
t = PlotText(yaxis[:guide], font)
extract_font(font, kw)
push!(axis_vis, glvisualize_text(xy, t, kw))
push!(axis_vis, text(xy, t, kw))
end
axis_vis
@@ -781,7 +829,7 @@ function gl_bar(d, kw_args)
# compute half-width of bars
bw = nothing
hw = if bw == nothing
ignoreNaN_mean(diff(x))
mean(diff(x))
else
Float64[cycle(bw,i)*0.5 for i=1:length(x)]
end
@@ -864,7 +912,7 @@ function gl_boxplot(d, kw_args)
end
# change q1 and q5 to show outliers
# using maximum and minimum values inside the limits
q1, q5 = ignoreNaN_extrema(inside)
q1, q5 = extrema(inside)
end
# Box
if notch
@@ -1093,7 +1141,8 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
vis = gl_bar(d, kw_args)
elseif st == :image
extract_extrema(d, kw_args)
vis = GL.gl_image(d[:z].surf, kw_args)
z = transpose_z(series, d[:z].surf, false)
vis = GL.gl_image(z, kw_args)
elseif st == :boxplot
extract_c(d, kw_args, :fill)
vis = gl_boxplot(d, kw_args)
@@ -1124,7 +1173,7 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
txt_args = Dict{Symbol, Any}(:model => eye(GLAbstraction.Mat4f0))
x, y = Reactive.value(model_m) * Vec{4, Float32}(x, y, 0, 1)
extract_font(font, txt_args)
t = glvisualize_text(Point2f0(x, y), PlotText(str, font), txt_args)
t = text(Point2f0(x, y), PlotText(str, font), txt_args)
GLVisualize._view(t, sp_screen, camera = :perspective)
end
@@ -1133,7 +1182,7 @@ function _display(plt::Plot{GLVisualizeBackend}, visible = true)
if _3d
GLAbstraction.center!(sp_screen)
end
GLAbstraction.post_empty()
Reactive.post_empty()
yield()
end
end
@@ -1318,7 +1367,7 @@ function gl_contour(x, y, z, kw_args)
T = eltype(z)
levels = Contour.contours(map(T, x), map(T, y), z, h)
result = Point2f0[]
zmin, zmax = get(kw_args, :limits, Vec2f0(ignoreNaN_extrema(z)))
zmin, zmax = get(kw_args, :limits, Vec2f0(extrema(z)))
cmap = get(kw_args, :color_map, get(kw_args, :color, RGBA{Float32}(0,0,0,1)))
colors = RGBA{Float32}[]
for c in levels.contours
@@ -1339,7 +1388,7 @@ end
function gl_heatmap(x,y,z, kw_args)
get!(kw_args, :color_norm, Vec2f0(ignoreNaN_extrema(z)))
get!(kw_args, :color_norm, Vec2f0(extrema(z)))
get!(kw_args, :color_map, Plots.make_gradient(cgrad()))
delete!(kw_args, :intensity)
I = GLVisualize.Intensity{1, Float32}
@@ -1373,8 +1422,6 @@ function label_scatter(d, w, ho)
color = get(kw, :color, nothing)
kw[:color] = isa(color, Array) ? first(color) : color
end
strcolor = get(kw, :stroke_color, RGBA{Float32}(0,0,0,0))
kw[:stroke_color] = isa(strcolor, Array) ? first(strcolor) : strcolor
p = get(kw, :primitive, GeometryTypes.Circle)
if isa(p, GLNormalMesh)
bb = GeometryTypes.AABB{Float32}(GeometryTypes.vertices(p))
@@ -1389,9 +1436,6 @@ function label_scatter(d, w, ho)
kw[:scale] = Vec3f0(w/2)
delete!(kw, :offset)
end
if isa(p, Array)
kw[:primitive] = GeometryTypes.Circle
end
GL.gl_scatter(Point2f0[(w/2, ho)], kw)
end
@@ -1436,7 +1480,7 @@ function make_label(sp, series, i)
kw = Dict(:model => text_model(font, xy), :scale_primitive=>false)
extract_font(font, kw)
t = PlotText(labeltext, font)
push!(result, glvisualize_text(xy, t, kw))
push!(result, text(xy, t, kw))
GLAbstraction.Context(result...), i
end
+52 -93
View File
@@ -20,7 +20,7 @@ const _gr_attr = merge_with_base_supported([
:title, :window_title,
:guide, :lims, :ticks, :scale, :flip,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :legendtitle, :colorbar,
:grid, :legend, :colorbar,
:marker_z, :levels,
:ribbon, :quiver,
:orientation,
@@ -76,8 +76,6 @@ const gr_markertype = KW(
:diamond => -13,
:utriangle => -3,
:dtriangle => -5,
:ltriangle => -18,
:rtriangle => -17,
:pentagon => -21,
:hexagon => -22,
:heptagon => -23,
@@ -174,8 +172,6 @@ function gr_polyline(x, y, func = GR.polyline; arrowside=:none)
end
end
gr_inqtext(x, y, s::Symbol) = gr_inqtext(x, y, string(s))
function gr_inqtext(x, y, s)
if length(s) >= 2 && s[1] == '$' && s[end] == '$'
GR.inqtextext(x, y, s[2:end-1])
@@ -186,8 +182,6 @@ function gr_inqtext(x, y, s)
end
end
gr_text(x, y, s::Symbol) = gr_text(x, y, string(s))
function gr_text(x, y, s)
if length(s) >= 2 && s[1] == '$' && s[end] == '$'
GR.mathtex(x, y, s[2:end-1])
@@ -264,7 +258,7 @@ end
normalize_zvals(zv::Void) = zv
function normalize_zvals(zv::AVec)
vmin, vmax = ignoreNaN_extrema(zv)
vmin, vmax = extrema(zv)
if vmin == vmax
zeros(length(zv))
else
@@ -279,19 +273,17 @@ function gr_draw_marker(xi, yi, msize, shape::Shape)
sx, sy = coords(shape)
# convert to ndc coords (percentages of window)
GR.selntran(0)
w, h = gr_plot_size
f = msize / (w + h)
xi, yi = GR.wctondc(xi, yi)
GR.fillarea(xi .+ sx .* f,
yi .+ sy .* f)
ms_ndc_x, ms_ndc_y = gr_pixels_to_ndc(msize, msize)
GR.fillarea(xi .+ sx .* ms_ndc_x,
yi .+ sy .* ms_ndc_y)
GR.selntran(1)
end
# draw ONE symbol marker
function gr_draw_marker(xi, yi, msize::Number, shape::Symbol)
GR.setmarkertype(gr_markertype[shape])
w, h = gr_plot_size
GR.setmarkersize(0.3msize / ((w + h) * 0.001))
GR.setmarkersize(0.3msize)
GR.polymarker([xi], [yi])
end
@@ -338,10 +330,9 @@ end
# ---------------------------------------------------------
function gr_set_line(lw, style, c) #, a)
function gr_set_line(w, style, c) #, a)
GR.setlinetype(gr_linetype[style])
w, h = gr_plot_size
GR.setlinewidth(max(0, lw / ((w + h) * 0.001)))
GR.setlinewidth(w)
gr_set_linecolor(c) #, a)
end
@@ -386,28 +377,20 @@ const viewport_plotarea = zeros(4)
# the size of the current plot in pixels
const gr_plot_size = zeros(2)
function gr_viewport_from_bbox(sp::Subplot{GRBackend}, bb::BoundingBox, w, h, viewport_canvas)
function gr_viewport_from_bbox(bb::BoundingBox, w, h, viewport_canvas)
viewport = zeros(4)
viewport[1] = viewport_canvas[2] * (left(bb) / w)
viewport[2] = viewport_canvas[2] * (right(bb) / w)
viewport[3] = viewport_canvas[4] * (1.0 - bottom(bb) / h)
viewport[4] = viewport_canvas[4] * (1.0 - top(bb) / h)
if is3d(sp)
vp = viewport[:]
extent = min(vp[2] - vp[1], vp[4] - vp[3])
viewport[1] = 0.5 * (vp[1] + vp[2] - extent)
viewport[2] = 0.5 * (vp[1] + vp[2] + extent)
viewport[3] = 0.5 * (vp[3] + vp[4] - extent)
viewport[4] = 0.5 * (vp[3] + vp[4] + extent)
end
viewport
end
# change so we're focused on the viewport area
function gr_set_viewport_cmap(sp::Subplot)
GR.setviewport(
viewport_plotarea[2] + (is3d(sp) ? 0.07 : 0.02),
viewport_plotarea[2] + (is3d(sp) ? 0.10 : 0.05),
viewport_plotarea[2] + (is3d(sp) ? 0.04 : 0.02),
viewport_plotarea[2] + (is3d(sp) ? 0.07 : 0.05),
viewport_plotarea[3],
viewport_plotarea[4]
)
@@ -428,7 +411,7 @@ function gr_set_viewport_polar()
ymax -= 0.05 * (xmax - xmin)
xcenter = 0.5 * (xmin + xmax)
ycenter = 0.5 * (ymin + ymax)
r = 0.5 * NaNMath.min(xmax - xmin, ymax - ymin)
r = 0.5 * min(xmax - xmin, ymax - ymin)
GR.setviewport(xcenter -r, xcenter + r, ycenter - r, ycenter + r)
GR.setwindow(-1, 1, -1, 1)
r
@@ -438,41 +421,23 @@ end
function gr_colorbar(sp::Subplot)
if sp[:colorbar] != :none
gr_set_viewport_cmap(sp)
GR.colorbar()
GR.colormap()
gr_set_viewport_plotarea()
end
end
gr_view_xcenter() = 0.5 * (viewport_plotarea[1] + viewport_plotarea[2])
gr_view_ycenter() = 0.5 * (viewport_plotarea[3] + viewport_plotarea[4])
gr_view_xdiff() = viewport_plotarea[2] - viewport_plotarea[1]
gr_view_ydiff() = viewport_plotarea[4] - viewport_plotarea[3]
function gr_legend_pos(s::Symbol,w,h)
str = string(s)
if str == "best"
str = "topright"
end
if contains(str,"right")
xpos = viewport_plotarea[2] - 0.05 - w
elseif contains(str,"left")
xpos = viewport_plotarea[1] + 0.11
else
xpos = (viewport_plotarea[2]-viewport_plotarea[1])/2 - w/2 +.04
end
if contains(str,"top")
ypos = viewport_plotarea[4] - 0.06
elseif contains(str,"bottom")
ypos = viewport_plotarea[3] + h + 0.06
else
ypos = (viewport_plotarea[4]-viewport_plotarea[3])/2 + h/2
end
(xpos,ypos)
function gr_pixels_to_ndc(x_pixels, y_pixels)
w,h = gr_plot_size
totx = w * gr_view_xdiff()
toty = h * gr_view_ydiff()
x_pixels / totx, y_pixels / toty
end
function gr_legend_pos{S<:Real, T<:Real}(v::Tuple{S,T},w,h)
xpos = v[1] * (viewport_plotarea[2] - viewport_plotarea[1]) + viewport_plotarea[1]
ypos = v[2] * (viewport_plotarea[4] - viewport_plotarea[3]) + viewport_plotarea[3]
(xpos,ypos)
end
# --------------------------------------------------------------------------------------
@@ -533,15 +498,10 @@ function gr_display(plt::Plot)
end
function _update_min_padding!(sp::Subplot{GRBackend})
sp.minpad = (10mm,2mm,2mm,8mm)
end
function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# the viewports for this subplot
viewport_subplot = gr_viewport_from_bbox(sp, bbox(sp), w, h, viewport_canvas)
viewport_plotarea[:] = gr_viewport_from_bbox(sp, plotarea(sp), w, h, viewport_canvas)
viewport_subplot = gr_viewport_from_bbox(bbox(sp), w, h, viewport_canvas)
viewport_plotarea[:] = gr_viewport_from_bbox(plotarea(sp), w, h, viewport_canvas)
# get data limits
data_lims = gr_xy_axislims(sp)
@@ -585,10 +545,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
end
if st == :heatmap
outside_ticks = true
x, y = heatmap_edges(series[:x]), heatmap_edges(series[:y])
expand_extrema!(sp[:xaxis], x)
expand_extrema!(sp[:yaxis], y)
data_lims = gr_xy_axislims(sp)
end
end
@@ -666,7 +622,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
elseif ispolar(sp)
r = gr_set_viewport_polar()
rmin, rmax = GR.adjustrange(ignoreNaN_minimum(r), ignoreNaN_maximum(r))
rmin, rmax = GR.adjustrange(minimum(r), maximum(r))
# rmin, rmax = axis_limits(sp[:yaxis])
gr_polaraxes(rmin, rmax)
@@ -690,9 +646,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# spine (border) and tick marks
gr_set_line(1, :solid, sp[:xaxis][:foreground_color_axis])
GR.setclip(0)
gr_polyline(coords(spine_segs)...)
GR.setclip(1)
if !(xticks in (nothing, false))
# x labels
@@ -707,7 +661,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# use xor ($) to get the right y coords
xi, yi = GR.wctondc(cv, (flip $ mirror) ? ymax : ymin)
# @show cv dv ymin xi yi flip mirror (flip $ mirror)
gr_text(xi, yi + (mirror ? 1 : -1) * 5e-3, string(dv))
gr_text(xi, yi + (mirror ? 1 : -1) * 2e-3, string(dv))
end
end
@@ -724,9 +678,22 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# use xor ($) to get the right y coords
xi, yi = GR.wctondc((flip $ mirror) ? xmax : xmin, cv)
# @show cv dv xmin xi yi
gr_text(xi + (mirror ? 1 : -1) * 1e-2, yi, string(dv))
gr_text(xi + (mirror ? 1 : -1) * 2e-3, yi, string(dv))
end
end
# window_diag = sqrt(gr_view_xdiff()^2 + gr_view_ydiff()^2)
# ticksize = 0.0075 * window_diag
# if outside_ticks
# ticksize = -ticksize
# end
# # TODO: this should be done for each axis separately
# gr_set_linecolor(xaxis[:foreground_color_axis])
# x1, x2 = xaxis[:flip] ? (xmax,xmin) : (xmin,xmax)
# y1, y2 = yaxis[:flip] ? (ymax,ymin) : (ymin,ymax)
# GR.axes(xtick, ytick, x1, y1, 1, 1, ticksize)
# GR.axes(xtick, ytick, x2, y2, -1, -1, -ticksize)
end
# end
@@ -792,6 +759,10 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# recompute data
if typeof(z) <: Surface
# if st == :heatmap
# expand_extrema!(sp[:xaxis], (x[1]-0.5*(x[2]-x[1]), x[end]+0.5*(x[end]-x[end-1])))
# expand_extrema!(sp[:yaxis], (y[1]-0.5*(y[2]-y[1]), y[end]+0.5*(y[end]-y[end-1])))
# end
z = vec(transpose_z(series, z.surf, false))
elseif ispolar(sp)
if frng != nothing
@@ -836,12 +807,12 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
isfinite(clims[1]) && (zmin = clims[1])
isfinite(clims[2]) && (zmax = clims[2])
end
GR.setspace(zmin, zmax, 0, 90)
if typeof(series[:levels]) <: Array
h = series[:levels]
else
h = linspace(zmin, zmax, series[:levels])
end
GR.setspace(zmin, zmax, 0, 90)
if series[:fillrange] != nothing
GR.surface(x, y, z, GR.OPTION_CELL_ARRAY)
else
@@ -851,7 +822,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
# create the colorbar of contour levels
if sp[:colorbar] != :none
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 - minimum(h)) / (maximum(h) - minimum(h)) * 255)
GR.setwindow(xmin, xmax, zmin, zmax)
GR.cellarray(xmin, xmax, zmax, zmin, 1, length(l), l)
ztick = 0.5 * GR.tick(zmin, zmax)
@@ -879,7 +850,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
isfinite(clims[1]) && (zmin = clims[1])
isfinite(clims[2]) && (zmax = clims[2])
end
GR.setspace(zmin, zmax, 0, 90)
grad = isa(series[:fillcolor], ColorGradient) ? series[:fillcolor] : cgrad()
colors = [grad[clamp((zi-zmin) / (zmax-zmin), 0, 1)] for zi=z]
rgba = map(c -> UInt32( round(Int, alpha(c) * 255) << 24 +
@@ -909,7 +879,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
GR.selntran(0)
GR.setfillintstyle(GR.INTSTYLE_SOLID)
xmin, xmax, ymin, ymax = viewport_plotarea
ymax -= 0.1 * (xmax - xmin)
ymax -= 0.05 * (xmax - xmin)
xcenter = 0.5 * (xmin + xmax)
ycenter = 0.5 * (ymin + ymax)
if xmax - xmin > ymax - ymin
@@ -973,8 +943,8 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
elseif st == :image
z = transpose_z(series, series[:z].surf, true)'
w, h = size(z)
z = transpose_z(series, series[:z].surf, true)
h, w = size(z)
if eltype(z) <: Colors.AbstractGray
grey = round(UInt8, float(z) * 255)
rgba = map(c -> UInt32( 0xff000000 + Int(c)<<16 + Int(c)<<8 + Int(c) ), grey)
@@ -1007,11 +977,6 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
w = 0
i = 0
n = 0
if sp[:legendtitle] != nothing
tbx, tby = gr_inqtext(0, 0, string(sp[:legendtitle]))
w = tbx[3] - tbx[1]
n += 1
end
for series in series_list(sp)
should_add_to_legend(series) || continue
n += 1
@@ -1025,9 +990,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
w = max(w, tbx[3] - tbx[1])
end
if w > 0
xpos = viewport_plotarea[2] - 0.05 - w
ypos = viewport_plotarea[4] - 0.06
dy = _gr_point_mult[1] * sp[:legendfont].pointsize * 1.75
h = dy*n
(xpos,ypos) = gr_legend_pos(sp[:legend],w,h)
GR.setfillintstyle(GR.INTSTYLE_SOLID)
gr_set_fillcolor(sp[:background_color_legend])
GR.fillrect(xpos - 0.08, xpos + w + 0.02, ypos + dy, ypos - dy * n)
@@ -1035,19 +1000,13 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
GR.setlinewidth(1)
GR.drawrect(xpos - 0.08, xpos + w + 0.02, ypos + dy, ypos - dy * n)
i = 0
if sp[:legendtitle] != nothing
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF)
gr_set_textcolor(sp[:foreground_color_legend])
gr_text(xpos - 0.03 + 0.5*w, ypos, string(sp[:legendtitle]))
ypos -= dy
end
for series in series_list(sp)
should_add_to_legend(series) || continue
st = series[:seriestype]
gr_set_line(series[:linewidth], series[:linestyle], series[:linecolor]) #, series[:linealpha])
if st == :path && series[:fillrange] == nothing
if st == :path
GR.polyline([xpos - 0.07, xpos - 0.01], [ypos, ypos])
elseif st == :shape || series[:fillrange] != nothing
elseif st == :shape
gr_set_fill(series[:fillcolor]) #, series[:fillalpha])
l, r = xpos-0.07, xpos-0.01
b, t = ypos-0.4dy, ypos+0.4dy
@@ -1144,7 +1103,7 @@ function _display(plt::Plot{GRBackend})
ENV["GKS_FILEPATH"] = filepath
gr_display(plt)
GR.emergencyclosegks()
content = string("\033]1337;File=inline=1;preserveAspectRatio=0:", base64encode(open(read, filepath)), "\a")
content = string("\033]1337;File=inline=1;preserveAspectRatio=0:", base64encode(open(readbytes, filepath)), "\a")
println(content)
rm(filepath)
else
-655
View File
@@ -1,655 +0,0 @@
#HDF5 Plots: Save/replay plots to/from HDF5
#-------------------------------------------------------------------------------
#==Usage
===============================================================================
Write to .hdf5 file using:
p = plot(...)
Plots.hdf5plot_write(p, "plotsave.hdf5")
Read from .hdf5 file using:
pyplot() #Must first select backend
pread = Plots.hdf5plot_read("plotsave.hdf5")
display(pread)
==#
#==TODO
===============================================================================
1. Support more features
- SeriesAnnotations & GridLayout known to be missing.
3. Improve error handling.
- Will likely crash if file format is off.
2. Save data in a folder parallel to "plot".
- Will make it easier for users to locate data.
- Use HDF5 reference to link data?
3. Develop an actual versioned file format.
- Should have some form of backward compatibility.
- Should be reliable for archival purposes.
==#
import FixedPointNumbers: N0f8 #In core Julia
#Dispatch types:
immutable HDF5PlotNative; end #Indentifies a data element that can natively be handled by HDF5
immutable HDF5CTuple; end #Identifies a "complex" tuple structure
type HDF5Plot_PlotRef
ref::Union{Plot, Void}
end
#==Useful constants
===============================================================================#
const _hdf5_plotroot = "plot"
const _hdf5_dataroot = "data" #TODO: Eventually move data to different root (easier to locate)?
const _hdf5plot_datatypeid = "TYPE" #Attribute identifying type
const _hdf5plot_countid = "COUNT" #Attribute for storing count
#Dict has problems using "Types" as keys. Initialize in "_initialize_backend":
const HDF5PLOT_MAP_STR2TELEM = Dict{String, Type}()
const HDF5PLOT_MAP_TELEM2STR = Dict{Type, String}()
#Don't really like this global variable... Very hacky
const HDF5PLOT_PLOTREF = HDF5Plot_PlotRef(nothing)
#Simple sub-structures that can just be written out using _hdf5plot_gwritefields:
const HDF5PLOT_SIMPLESUBSTRUCT = Union{Font, BoundingBox,
GridLayout, RootLayout, ColorGradient, SeriesAnnotations, PlotText
}
#==
===============================================================================#
const _hdf5_attr = merge_with_base_supported([
:annotations,
:background_color_legend, :background_color_inside, :background_color_outside,
:foreground_color_grid, :foreground_color_legend, :foreground_color_title,
:foreground_color_axis, :foreground_color_border, :foreground_color_guide, :foreground_color_text,
:label,
:linecolor, :linestyle, :linewidth, :linealpha,
:markershape, :markercolor, :markersize, :markeralpha,
:markerstrokewidth, :markerstrokecolor, :markerstrokealpha,
:fillrange, :fillcolor, :fillalpha,
:bins, :bar_width, :bar_edges, :bar_position,
:title, :title_location, :titlefont,
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar,
:marker_z, :line_z, :fill_z,
:levels,
:ribbon, :quiver, :arrow,
:orientation,
:overwrite_figure,
:polar,
:normalize, :weights,
:contours, :aspect_ratio,
:match_dimensions,
:clims,
:inset_subplots,
:dpi,
:colorbar_title,
])
const _hdf5_seriestype = [
:path, :steppre, :steppost, :shape,
:scatter, :hexbin, #:histogram2d, :histogram,
# :bar,
:heatmap, :pie, :image,
:contour, :contour3d, :path3d, :scatter3d, :surface, :wireframe
]
const _hdf5_style = [:auto, :solid, :dash, :dot, :dashdot]
const _hdf5_marker = vcat(_allMarkers, :pixel)
const _hdf5_scale = [:identity, :ln, :log2, :log10]
is_marker_supported(::HDF5Backend, shape::Shape) = true
function add_backend_string(::HDF5Backend)
"""
if !Plots.is_installed("HDF5")
Pkg.add("HDF5")
end
"""
end
#==Helper functions
===============================================================================#
_hdf5_plotelempath(subpath::String) = "$_hdf5_plotroot/$subpath"
_hdf5_datapath(subpath::String) = "$_hdf5_dataroot/$subpath"
_hdf5_map_str2telem(k::String) = HDF5PLOT_MAP_STR2TELEM[k]
_hdf5_map_str2telem(v::Vector) = HDF5PLOT_MAP_STR2TELEM[v[1]]
function _hdf5_merge!(dest::Dict, src::Dict)
for (k, v) in src
if isa(v, Axis)
_hdf5_merge!(dest[k].d, v.d)
else
dest[k] = v
end
end
return
end
#==
===============================================================================#
function _initialize_backend(::HDF5Backend)
@eval begin
import HDF5
export HDF5
if length(HDF5PLOT_MAP_TELEM2STR) < 1
#Possible element types of high-level data types:
const telem2str = Dict{String, Type}(
"NATIVE" => HDF5PlotNative,
"VOID" => Void,
"BOOL" => Bool,
"SYMBOL" => Symbol,
"TUPLE" => Tuple,
"CTUPLE" => HDF5CTuple, #Tuple of complex structures
"RGBA" => ARGB{N0f8},
"EXTREMA" => Extrema,
"LENGTH" => Length,
"ARRAY" => Array, #Dict won't allow Array to be key in HDF5PLOT_MAP_TELEM2STR
#Sub-structure types:
"FONT" => Font,
"BOUNDINGBOX" => BoundingBox,
"GRIDLAYOUT" => GridLayout,
"ROOTLAYOUT" => RootLayout,
"SERIESANNOTATIONS" => SeriesAnnotations,
# "PLOTTEXT" => PlotText,
"COLORGRADIENT" => ColorGradient,
"AXIS" => Axis,
"SUBPLOT" => Subplot,
"NULLABLE" => Nullable,
)
merge!(HDF5PLOT_MAP_STR2TELEM, telem2str)
merge!(HDF5PLOT_MAP_TELEM2STR, Dict{Type, String}(v=>k for (k,v) in HDF5PLOT_MAP_STR2TELEM))
end
end
end
# ---------------------------------------------------------------------------
# Create the window/figure for this backend.
function _create_backend_figure(plt::Plot{HDF5Backend})
#Do nothing
end
# ---------------------------------------------------------------------------
# # this is called early in the pipeline, use it to make the plot current or something
# function _prepare_plot_object(plt::Plot{HDF5Backend})
# end
# ---------------------------------------------------------------------------
# Set up the subplot within the backend object.
function _initialize_subplot(plt::Plot{HDF5Backend}, sp::Subplot{HDF5Backend})
#Do nothing
end
# ---------------------------------------------------------------------------
# Add one series to the underlying backend object.
# Called once per series
# NOTE: Seems to be called when user calls plot()... even if backend
# plot, sp.o has not yet been constructed...
function _series_added(plt::Plot{HDF5Backend}, series::Series)
#Do nothing
end
# ---------------------------------------------------------------------------
# When series data is added/changed, this callback can do dynamic updates to the backend object.
# note: if the backend rebuilds the plot from scratch on display, then you might not do anything here.
function _series_updated(plt::Plot{HDF5Backend}, series::Series)
#Do nothing
end
# ---------------------------------------------------------------------------
# called just before updating layout bounding boxes... in case you need to prep
# for the calcs
function _before_layout_calcs(plt::Plot{HDF5Backend})
#Do nothing
end
# ----------------------------------------------------------------
# Set the (left, top, right, bottom) minimum padding around the plot area
# to fit ticks, tick labels, guides, colorbars, etc.
function _update_min_padding!(sp::Subplot{HDF5Backend})
#Do nothing
end
# ----------------------------------------------------------------
# Override this to update plot items (title, xlabel, etc), and add annotations (d[:annotations])
function _update_plot_object(plt::Plot{HDF5Backend})
#Do nothing
end
# ----------------------------------------------------------------
_show(io::IO, mime::MIME"text/plain", plt::Plot{HDF5Backend}) = nothing #Don't show
# ----------------------------------------------------------------
# Display/show the plot (open a GUI window, or browser page, for example).
function _display(plt::Plot{HDF5Backend})
msg = "HDF5 interface does not support `display()` function."
msg *= "\nUse `Plots.hdf5plot_write(::String)` method to write to .HDF5 \"plot\" file instead."
warn(msg)
return
end
#==HDF5 write functions
===============================================================================#
function _hdf5plot_writetype(grp, k::String, tstr::Array{String})
d = HDF5.d_open(grp, k)
HDF5.a_write(d, _hdf5plot_datatypeid, tstr)
end
function _hdf5plot_writetype(grp, k::String, T::Type)
tstr = HDF5PLOT_MAP_TELEM2STR[T]
d = HDF5.d_open(grp, k)
HDF5.a_write(d, _hdf5plot_datatypeid, tstr)
end
function _hdf5plot_overwritetype(grp, k::String, T::Type)
tstr = HDF5PLOT_MAP_TELEM2STR[T]
d = HDF5.d_open(grp, k)
HDF5.a_delete(d, _hdf5plot_datatypeid)
HDF5.a_write(d, _hdf5plot_datatypeid, tstr)
end
function _hdf5plot_writetype(grp, T::Type) #Write directly to group
tstr = HDF5PLOT_MAP_TELEM2STR[T]
HDF5.a_write(grp, _hdf5plot_datatypeid, tstr)
end
function _hdf5plot_overwritetype(grp, T::Type) #Write directly to group
tstr = HDF5PLOT_MAP_TELEM2STR[T]
HDF5.a_delete(grp, _hdf5plot_datatypeid)
HDF5.a_write(grp, _hdf5plot_datatypeid, tstr)
end
function _hdf5plot_writetype{T<:Any}(grp, ::Type{Array{T}})
tstr = HDF5PLOT_MAP_TELEM2STR[Array] #ANY
HDF5.a_write(grp, _hdf5plot_datatypeid, tstr)
end
function _hdf5plot_writetype{T<:BoundingBox}(grp, ::Type{T})
tstr = HDF5PLOT_MAP_TELEM2STR[BoundingBox]
HDF5.a_write(grp, _hdf5plot_datatypeid, tstr)
end
function _hdf5plot_writecount(grp, n::Int) #Write directly to group
HDF5.a_write(grp, _hdf5plot_countid, n)
end
function _hdf5plot_gwritefields(grp, k::String, v)
grp = HDF5.g_create(grp, k)
for _k in fieldnames(v)
_v = getfield(v, _k)
kstr = string(_k)
_hdf5plot_gwrite(grp, kstr, _v)
end
_hdf5plot_writetype(grp, typeof(v))
return
end
# Write data
# ----------------------------------------------------------------
function _hdf5plot_gwrite(grp, k::String, v) #Default
grp[k] = v
_hdf5plot_writetype(grp, k, HDF5PlotNative)
end
function _hdf5plot_gwrite{T<:Number}(grp, k::String, v::Array{T}) #Default for arrays
grp[k] = v
_hdf5plot_writetype(grp, k, HDF5PlotNative)
end
#=
function _hdf5plot_gwrite(grp, k::String, v::Array{Any})
# @show grp, k
warn("Cannot write Array: $k=$v")
end
=#
function _hdf5plot_gwrite(grp, k::String, v::Void)
grp[k] = 0
_hdf5plot_writetype(grp, k, Void)
end
function _hdf5plot_gwrite(grp, k::String, v::Bool)
grp[k] = Int(v)
_hdf5plot_writetype(grp, k, Bool)
end
function _hdf5plot_gwrite(grp, k::String, v::Symbol)
grp[k] = string(v)
_hdf5plot_writetype(grp, k, Symbol)
end
function _hdf5plot_gwrite(grp, k::String, v::Tuple)
varr = [v...]
elt = eltype(varr)
# if isleaftype(elt)
_hdf5plot_gwrite(grp, k, varr)
if elt <: Number
#We just wrote a simple dataset
_hdf5plot_overwritetype(grp, k, Tuple)
else #Used a more complex scheme (using subgroups):
_hdf5plot_overwritetype(grp[k], HDF5CTuple)
end
#NOTE: _hdf5plot_overwritetype overwrites "Array" type with "Tuple".
end
function _hdf5plot_gwrite(grp, k::String, d::Dict)
# warn("Cannot write dict: $k=$d")
end
function _hdf5plot_gwrite(grp, k::String, v::Range)
_hdf5plot_gwrite(grp, k, collect(v)) #For now
end
function _hdf5plot_gwrite(grp, k::String, v::ARGB{N0f8})
grp[k] = [v.r.i, v.g.i, v.b.i, v.alpha.i]
_hdf5plot_writetype(grp, k, ARGB{N0f8})
end
function _hdf5plot_gwrite(grp, k::String, v::Colorant)
_hdf5plot_gwrite(grp, k, ARGB{N0f8}(v))
end
#Custom vector (when not using simple numeric type):
function _hdf5plot_gwritearray{T}(grp, k::String, v::Array{T})
if "annotations" == k;
return #Hack. Does not yet support annotations.
end
vgrp = HDF5.g_create(grp, k)
_hdf5plot_writetype(vgrp, Array) #ANY
sz = size(v)
for iter in eachindex(v)
coord = ind2sub(sz, iter)
elem = v[iter]
idxstr = join(coord, "_")
_hdf5plot_gwrite(vgrp, "v$idxstr", v[iter])
end
_hdf5plot_gwrite(vgrp, "dim", [sz...])
return
end
_hdf5plot_gwrite(grp, k::String, v::Array) =
_hdf5plot_gwritearray(grp, k, v)
function _hdf5plot_gwrite(grp, k::String, v::Extrema)
grp[k] = [v.emin, v.emax]
_hdf5plot_writetype(grp, k, Extrema)
end
function _hdf5plot_gwrite{T}(grp, k::String, v::Length{T})
grp[k] = v.value
_hdf5plot_writetype(grp, k, [HDF5PLOT_MAP_TELEM2STR[Length], string(T)])
end
# Write more complex structures:
# ----------------------------------------------------------------
function _hdf5plot_gwrite(grp, k::String, v::Plot)
#Don't write plot references
end
function _hdf5plot_gwrite(grp, k::String, v::HDF5PLOT_SIMPLESUBSTRUCT)
_hdf5plot_gwritefields(grp, k, v)
return
end
function _hdf5plot_gwrite(grp, k::String, v::Axis)
grp = HDF5.g_create(grp, k)
for (_k, _v) in v.d
kstr = string(_k)
_hdf5plot_gwrite(grp, kstr, _v)
end
_hdf5plot_writetype(grp, Axis)
return
end
#TODO: "Properly" support Nullable using _hdf5plot_writetype?
function _hdf5plot_gwrite(grp, k::String, v::Nullable)
if isnull(v)
_hdf5plot_gwrite(grp, k, nothing)
else
_hdf5plot_gwrite(grp, k, v.value)
end
return
end
function _hdf5plot_gwrite(grp, k::String, v::SeriesAnnotations)
#Currently no support for SeriesAnnotations
return
end
function _hdf5plot_gwrite(grp, k::String, v::Subplot)
grp = HDF5.g_create(grp, k)
_hdf5plot_gwrite(grp, "index", v[:subplot_index])
_hdf5plot_writetype(grp, Subplot)
return
end
function _hdf5plot_write(grp, d::Dict)
for (k, v) in d
kstr = string(k)
_hdf5plot_gwrite(grp, kstr, v)
end
return
end
# Write main plot structures:
# ----------------------------------------------------------------
function _hdf5plot_write(sp::Subplot{HDF5Backend}, subpath::String, f)
f = f::HDF5.HDF5File #Assert
grp = HDF5.g_create(f, _hdf5_plotelempath("$subpath/attr"))
_hdf5plot_write(grp, sp.attr)
grp = HDF5.g_create(f, _hdf5_plotelempath("$subpath/series_list"))
_hdf5plot_writecount(grp, length(sp.series_list))
for (i, series) in enumerate(sp.series_list)
grp = HDF5.g_create(f, _hdf5_plotelempath("$subpath/series_list/series$i"))
_hdf5plot_write(grp, series.d)
end
return
end
function _hdf5plot_write(plt::Plot{HDF5Backend}, f)
f = f::HDF5.HDF5File #Assert
grp = HDF5.g_create(f, _hdf5_plotelempath("attr"))
_hdf5plot_write(grp, plt.attr)
grp = HDF5.g_create(f, _hdf5_plotelempath("subplots"))
_hdf5plot_writecount(grp, length(plt.subplots))
for (i, sp) in enumerate(plt.subplots)
_hdf5plot_write(sp, "subplots/subplot$i", f)
end
return
end
function hdf5plot_write(plt::Plot{HDF5Backend}, path::AbstractString)
HDF5.h5open(path, "w") do file
_hdf5plot_write(plt, file)
end
end
hdf5plot_write(path::AbstractString) = hdf5plot_write(current(), path)
#==HDF5 playback (read) functions
===============================================================================#
function _hdf5plot_readcount(grp) #Read directly from group
return HDF5.a_read(grp, _hdf5plot_countid)
end
_hdf5plot_convert(T::Type{HDF5PlotNative}, v) = v
_hdf5plot_convert(T::Type{Void}, v) = nothing
_hdf5plot_convert(T::Type{Bool}, v) = (v!=0)
_hdf5plot_convert(T::Type{Symbol}, v) = Symbol(v)
_hdf5plot_convert(T::Type{Tuple}, v) = tuple(v...) #With Vector{T<:Number}
function _hdf5plot_convert(T::Type{ARGB{N0f8}}, v)
r, g, b, a = reinterpret(N0f8, v)
return Colors.ARGB{N0f8}(r, g, b, a)
end
_hdf5plot_convert(T::Type{Extrema}, v) = Extrema(v[1], v[2])
# Read data structures:
# ----------------------------------------------------------------
function _hdf5plot_read(grp, k::String, T::Type, dtid)
v = HDF5.d_read(grp, k)
return _hdf5plot_convert(T, v)
end
function _hdf5plot_read(grp, k::String, T::Type{Length}, dtid::Vector)
v = HDF5.d_read(grp, k)
TU = Symbol(dtid[2])
T = typeof(v)
return Length{TU,T}(v)
end
# Read more complex data structures:
# ----------------------------------------------------------------
function _hdf5plot_read(grp, k::String, T::Type{Font}, dtid)
grp = HDF5.g_open(grp, k)
family = _hdf5plot_read(grp, "family")
pointsize = _hdf5plot_read(grp, "pointsize")
halign = _hdf5plot_read(grp, "halign")
valign = _hdf5plot_read(grp, "valign")
rotation = _hdf5plot_read(grp, "rotation")
color = _hdf5plot_read(grp, "color")
return Font(family, pointsize, halign, valign, rotation, color)
end
function _hdf5plot_read(grp, k::String, T::Type{Array}, dtid) #ANY
grp = HDF5.g_open(grp, k)
sz = _hdf5plot_read(grp, "dim")
if [0] == sz; return []; end
sz = tuple(sz...)
result = Array{Any}(sz)
for iter in eachindex(result)
coord = ind2sub(sz, iter)
idxstr = join(coord, "_")
result[iter] = _hdf5plot_read(grp, "v$idxstr")
end
#Hack: Implicitly make Julia detect element type.
# (Should probably write it explicitly to file)
result = [result[iter] for iter in eachindex(result)] #Potentially make more specific
return reshape(result, sz)
end
function _hdf5plot_read(grp, k::String, T::Type{HDF5CTuple}, dtid)
v = _hdf5plot_read(grp, k, Array, dtid)
return tuple(v...)
end
function _hdf5plot_read(grp, k::String, T::Type{ColorGradient}, dtid)
grp = HDF5.g_open(grp, k)
colors = _hdf5plot_read(grp, "colors")
values = _hdf5plot_read(grp, "values")
return ColorGradient(colors, values)
end
function _hdf5plot_read(grp, k::String, T::Type{BoundingBox}, dtid)
grp = HDF5.g_open(grp, k)
x0 = _hdf5plot_read(grp, "x0")
a = _hdf5plot_read(grp, "a")
return BoundingBox(x0, a)
end
_hdf5plot_read(grp, k::String, T::Type{RootLayout}, dtid) = RootLayout()
function _hdf5plot_read(grp, k::String, T::Type{GridLayout}, dtid)
grp = HDF5.g_open(grp, k)
# parent = _hdf5plot_read(grp, "parent")
parent = RootLayout()
minpad = _hdf5plot_read(grp, "minpad")
bbox = _hdf5plot_read(grp, "bbox")
grid = _hdf5plot_read(grp, "grid")
widths = _hdf5plot_read(grp, "widths")
heights = _hdf5plot_read(grp, "heights")
attr = KW() #TODO support attr: _hdf5plot_read(grp, "attr")
return GridLayout(parent, minpad, bbox, grid, widths, heights, attr)
end
function _hdf5plot_read(grp, k::String, T::Type{Axis}, dtid)
grp = HDF5.g_open(grp, k)
kwlist = KW()
_hdf5plot_read(grp, kwlist)
return Axis([], kwlist)
end
function _hdf5plot_read(grp, k::String, T::Type{Subplot}, dtid)
grp = HDF5.g_open(grp, k)
idx = _hdf5plot_read(grp, "index")
return HDF5PLOT_PLOTREF.ref.subplots[idx]
end
function _hdf5plot_read(grp, k::String)
dtid = HDF5.a_read(grp[k], _hdf5plot_datatypeid)
T = _hdf5_map_str2telem(dtid) #expect exception
return _hdf5plot_read(grp, k, T, dtid)
end
#Read in values in group to populate d:
function _hdf5plot_read(grp, d::Dict)
gnames = names(grp)
for k in gnames
try
v = _hdf5plot_read(grp, k)
d[Symbol(k)] = v
catch e
@show e
@show grp
warn("Could not read field $k")
end
end
return
end
# Read main plot structures:
# ----------------------------------------------------------------
function _hdf5plot_read(sp::Subplot, subpath::String, f)
f = f::HDF5.HDF5File #Assert
grp = HDF5.g_open(f, _hdf5_plotelempath("$subpath/attr"))
kwlist = KW()
_hdf5plot_read(grp, kwlist)
_hdf5_merge!(sp.attr, kwlist)
grp = HDF5.g_open(f, _hdf5_plotelempath("$subpath/series_list"))
nseries = _hdf5plot_readcount(grp)
for i in 1:nseries
grp = HDF5.g_open(f, _hdf5_plotelempath("$subpath/series_list/series$i"))
kwlist = KW()
_hdf5plot_read(grp, kwlist)
plot!(sp, kwlist[:x], kwlist[:y]) #Add data & create data structures
_hdf5_merge!(sp.series_list[end].d, kwlist)
end
return
end
function _hdf5plot_read(plt::Plot, f)
f = f::HDF5.HDF5File #Assert
#Assumpltion: subplots are already allocated (plt.subplots)
HDF5PLOT_PLOTREF.ref = plt #Used when reading "layout"
grp = HDF5.g_open(f, _hdf5_plotelempath("attr"))
_hdf5plot_read(grp, plt.attr)
for (i, sp) in enumerate(plt.subplots)
_hdf5plot_read(sp, "subplots/subplot$i", f)
end
return
end
function hdf5plot_read(path::AbstractString)
plt = nothing
HDF5.h5open(path, "r") do file
grp = HDF5.g_open(file, _hdf5_plotelempath("subplots"))
n = _hdf5plot_readcount(grp)
plt = plot(layout=n) #Get reference to a new plot
_hdf5plot_read(plt, file)
end
return plt
end
#Last line
+10 -8
View File
@@ -213,10 +213,14 @@ end
# Set up the subplot within the backend object.
function _initialize_subplot(plt::Plot{InspectDRBackend}, sp::Subplot{InspectDRBackend})
plot = sp.o
#Don't do anything without a "subplot" object: Will process later.
if nothing == plot; return; end
plot.data = []
plot.userannot = [] #Clear old markers/text annotation/polyline "annotation"
plot.markers = [] #Clear old markers
plot.atext = [] #Clear old annotation
plot.apline = [] #Clear old poly lines
return plot
end
@@ -273,7 +277,7 @@ For st in :shape:
apline = InspectDR.PolylineAnnotation(
x[rng], y[rng], line=line, fillcolor=fillcolor
)
InspectDR.add(plot, apline)
push!(plot.apline, apline)
end
end
@@ -349,7 +353,7 @@ function _inspectdr_setupsubplot(sp::Subplot{InspectDRBackend})
ymin, ymax = axis_limits(yaxis)
if ispolar(sp)
#Plots.jl appears to give (xmin,xmax) ≜ (Θmin,Θmax) & (ymin,ymax) ≜ (rmin,rmax)
rmax = NaNMath.max(abs(ymin), abs(ymax))
rmax = max(abs(ymin), abs(ymax))
xmin, xmax = -rmax, rmax
ymin, ymax = -rmax, rmax
end
@@ -411,6 +415,8 @@ function _before_layout_calcs(plt::Plot{InspectDRBackend})
plot = sp.o
_initialize_subplot(plt, sp)
_inspectdr_setupsubplot(sp)
graphbb = _inspectdr_to_pixels(plotarea(sp))
plot.plotbb = InspectDR.plotbounds(plot.layout, graphbb)
# add the annotations
for ann in sp[:annotations]
@@ -465,11 +471,7 @@ function _update_plot_object(plt::Plot{InspectDRBackend})
mplot = _inspectdr_getmplot(plt.o)
if nothing == mplot; return; end
for (i, sp) in enumerate(plt.subplots)
graphbb = _inspectdr_to_pixels(plotarea(sp))
plot = mplot.subplots[i]
plot.plotbb = InspectDR.plotbounds(plot.layout, graphbb)
end
#TODO: should plotbb be computed here??
gplot = _inspectdr_getgui(plt.o)
if nothing == gplot; return; end
+4 -51
View File
@@ -22,8 +22,8 @@ const _pgfplots_attr = merge_with_base_supported([
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend,
:colorbar,
:marker_z, #:levels,
# :colorbar,
# :marker_z, :levels,
# :ribbon, :quiver, :arrow,
# :orientation,
# :overwrite_figure,
@@ -98,8 +98,6 @@ const _pgf_series_extrastyle = KW(
:xsticks => "xcomb",
)
# PGFPlots uses the anchors to define orientations for example to align left
# one needs to use the right edge as anchor
const _pgf_annotation_halign = KW(
:center => "",
:left => "right",
@@ -109,24 +107,11 @@ const _pgf_annotation_halign = KW(
# --------------------------------------------------------------------------------------
# takes in color,alpha, and returns color and alpha appropriate for pgf style
function pgf_color(c::Colorant)
function pgf_color(c)
cstr = @sprintf("{rgb,1:red,%.8f;green,%.8f;blue,%.8f}", red(c), green(c), blue(c))
cstr, alpha(c)
end
function pgf_color(grad::ColorGradient)
# Can't handle ColorGradient here, fallback to defaults.
cstr = @sprintf("{rgb,1:red,%.8f;green,%.8f;blue,%.8f}", 0.0, 0.60560316,0.97868012)
cstr, 1
end
# Generates a colormap for pgfplots based on a ColorGradient
function pgf_colormap(grad::ColorGradient)
join(map(grad.colors) do c
@sprintf("rgb=(%.8f,%.8f,%.8f)", red(c), green(c),blue(c))
end,", ")
end
function pgf_fillstyle(d::KW)
cstr,a = pgf_color(d[:fillcolor])
"fill = $cstr, fill opacity=$a"
@@ -177,6 +162,7 @@ function pgf_series(sp::Subplot, series::Series)
st = d[:seriestype]
style = []
kw = KW()
push!(style, pgf_linestyle(d))
push!(style, pgf_marker(d))
@@ -196,10 +182,6 @@ function pgf_series(sp::Subplot, series::Series)
d[:z].surf, d[:x], d[:y]
elseif is3d(st)
d[:x], d[:y], d[:z]
elseif d[:marker_z] != nothing
# If a marker_z is used pass it as third coordinate to a 2D plot.
# See "Scatter Plots" in PGFPlots documentation
d[:x], d[:y], d[:marker_z]
else
d[:x], d[:y]
end
@@ -292,7 +274,6 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
# Obtain the total height of the plot by extracting the maximal bottom
# coordinate from the bounding box.
total_height = bottom(bbox(plt.layout))
for sp in plt.subplots
# first build the PGFPlots.Axis object
style = ["unbounded coords=jump"]
@@ -338,34 +319,6 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
if sp[:projection] == :polar
axisf = PGFPlots.PolarAxis
end
# Search series for any gradient. In case one series uses a gradient set
# the colorbar and colomap.
# The reasoning behind doing this on the axis level is that pgfplots
# colorbar seems to only works on axis level and needs the proper colormap for
# correctly displaying it.
# It's also possible to assign the colormap to the series itself but
# then the colormap needs to be added twice, once for the axis and once for the
# series.
# As it is likely that all series within the same axis use the same
# colormap this should not cause any problem.
for series in series_list(sp)
for col in (:markercolor, :fillcolor)
if typeof(series.d[col]) == ColorGradient
push!(style,"colormap={plots}{$(pgf_colormap(series.d[col]))}")
if sp[:colorbar] == :none
kw[:colorbar] = "false"
else
kw[:colorbar] = "true"
end
# goto is needed to break out of col and series for
@goto colorbar_end
end
end
end
@label colorbar_end
o = axisf(; style = style, kw...)
# add the series object to the PGFPlots.Axis
+5 -12
View File
@@ -19,7 +19,7 @@ const _plotly_attr = merge_with_base_supported([
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :colorbar, :colorbar_title,
:grid, :legend, :colorbar,
:marker_z, :fill_z, :levels,
:ribbon, :quiver,
:orientation,
@@ -269,7 +269,7 @@ function plotly_layout(plt::Plot)
w, h = plt[:size]
d_out[:width], d_out[:height] = w, h
d_out[:paper_bgcolor] = rgba_string(plt[:background_color_outside])
d_out[:margin] = KW(:l=>0, :b=>20, :r=>0, :t=>20)
d_out[:margin] = KW(:l=>0, :b=>0, :r=>0, :t=>20)
d_out[:annotations] = KW[]
@@ -409,10 +409,6 @@ 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::Surface) = plotly_surface_data(series, a.surf)
#ensures that a gradient is called if a single color is supplied where a gradient is needed (e.g. if a series recipe defines marker_z)
as_gradient(grad::ColorGradient, α) = grad
as_gradient(grad, α) = cgrad(alpha = α)
# get a dictionary representing the series params (d is the Plots-dict, d_out is the Plotly-dict)
function plotly_series(plt::Plot, series::Series)
st = series[:seriestype]
@@ -443,8 +439,6 @@ function plotly_series(plt::Plot, series::Series)
end
end
d_out[:colorbar] = KW(:title => sp[:colorbar_title])
clims = sp[:clims]
if is_2tuple(clims)
d_out[:zmin], d_out[:zmax] = clims
@@ -545,10 +539,9 @@ function plotly_series(plt::Plot, series::Series)
rgba_string(series[:markercolor])
else
# grad = ColorGradient(series[:markercolor], alpha=series[:markeralpha])
grad = as_gradient(series[:markercolor], series[:markeralpha])
zmin, zmax = ignoreNaN_extrema(series[:marker_z])
zrange = zmax == zmin ? 1 : zmax - zmin # if all marker_z values are the same, plot all markers same color (avoids division by zero in next line)
[rgba_string(grad[(zi - zmin) / zrange]) for zi in series[:marker_z]]
grad = series[:markercolor]
zmin, zmax = extrema(series[:marker_z])
[rgba_string(grad[(zi - zmin) / (zmax - zmin)]) for zi in series[:marker_z]]
end
end
+26 -26
View File
@@ -17,7 +17,7 @@ const _pyplot_attr = merge_with_base_supported([
:window_title,
:guide, :lims, :ticks, :scale, :flip, :rotation,
:tickfont, :guidefont, :legendfont,
:grid, :legend, :legendtitle, :colorbar,
:grid, :legend, :colorbar,
:marker_z, :line_z, :fill_z,
:levels,
:ribbon, :quiver, :arrow,
@@ -55,6 +55,8 @@ function add_backend_string(::PyPlotBackend)
withenv("PYTHON" => "") do
Pkg.build("PyPlot")
end
import Conda
Conda.add("qt=4.8.5")
# now restart julia!
"""
@@ -82,10 +84,20 @@ function _initialize_backend(::PyPlotBackend)
const pytransforms = PyPlot.pywrap(PyPlot.pyimport("matplotlib.transforms"))
const pycollections = PyPlot.pywrap(PyPlot.pyimport("matplotlib.collections"))
const pyart3d = PyPlot.pywrap(PyPlot.pyimport("mpl_toolkits.mplot3d.art3d"))
# we don't want every command to update the figure
PyPlot.ioff()
end
if is_linux()
@eval begin
# avoid Conda update that causes Segfault with qt >=4.8.6 on Ubuntu https://github.com/JuliaPy/PyPlot.jl/issues/234
import Conda
kw = Conda._installed_packages_dict()
if (!haskey(kw,"qt") || (qt_version=get(kw,"qt",0)[1]!=v"4.8.5"))
print("\n If the code has a Segmentation fault error switch to qt v4.8.5 by pasting the following code into julia: \n \n")
print(add_backend_string(PyPlotBackend()))
end
end
end
# we don't want every command to update the figure
PyPlot.ioff()
end
# --------------------------------------------------------------------------------------
@@ -219,12 +231,6 @@ function py_stepstyle(seriestype::Symbol)
return "default"
end
function py_fillstepstyle(seriestype::Symbol)
seriestype == :steppost && return "post"
seriestype == :steppre && return "pre"
return nothing
end
# # untested... return a FontProperties object from a Plots.Font
# function py_font(font::Font)
# pyfont.pymember("FontProperties")(
@@ -677,11 +683,6 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
end
z = transpose_z(series, z)
if st == :surface
clims = sp[:clims]
if is_2tuple(clims)
isfinite(clims[1]) && (extrakw[:vmin] = clims[1])
isfinite(clims[2]) && (extrakw[:vmax] = clims[2])
end
if series[:fill_z] != nothing
# the surface colors are different than z-value
extrakw[:facecolors] = py_shading(series[:fillcolor], transpose_z(series, series[:fill_z].surf))
@@ -705,11 +706,11 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
# contours on the axis planes
if series[:contours]
for (zdir,mat) in (("x",x), ("y",y), ("z",z))
offset = (zdir == "y" ? ignoreNaN_maximum : ignoreNaN_minimum)(mat)
offset = (zdir == "y" ? maximum : minimum)(mat)
handle = ax[:contourf](x, y, z, levelargs...;
zdir = zdir,
cmap = py_fillcolormap(series),
offset = (zdir == "y" ? ignoreNaN_maximum : ignoreNaN_minimum)(mat) # where to draw the contour plane
offset = (zdir == "y" ? maximum : minimum)(mat) # where to draw the contour plane
)
push!(handles, handle)
needs_colorbar = true
@@ -778,7 +779,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
end
clims = sp[:clims]
zmin, zmax = ignoreNaN_extrema(z)
zmin, zmax = extrema(z)
extrakw[:vmin] = (is_2tuple(clims) && isfinite(clims[1])) ? clims[1] : zmin
extrakw[:vmax] = (is_2tuple(clims) && isfinite(clims[2])) ? clims[2] : zmax
@@ -872,7 +873,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series)
dim1, expand_data(fillrange[1], n), expand_data(fillrange[2], n)
end
handle = ax[f](args..., trues(n), false, py_fillstepstyle(st);
handle = ax[f](args...;
zorder = series[:series_plotindex],
facecolor = py_fillcolor(series),
linewidths = 0
@@ -926,14 +927,14 @@ function py_compute_axis_minval(axis::Axis)
for series in series_list(sp)
v = series.d[axis[:letter]]
if !isempty(v)
minval = NaNMath.min(minval, ignoreNaN_minimum(abs(v)))
minval = min(minval, minimum(abs(v)))
end
end
end
# now if the axis limits go to a smaller abs value, use that instead
vmin, vmax = axis_limits(axis)
minval = NaNMath.min(minval, abs(vmin), abs(vmax))
minval = min(minval, abs(vmin), abs(vmax))
minval
end
@@ -954,7 +955,7 @@ function py_set_scale(ax, axis::Axis)
elseif scale == :log10
10
end
kw[Symbol(:linthresh,letter)] = NaNMath.max(1e-16, py_compute_axis_minval(axis))
kw[Symbol(:linthresh,letter)] = max(1e-16, py_compute_axis_minval(axis))
"symlog"
end
func(arg; kw...)
@@ -1058,7 +1059,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
end
if sp[:grid]
fgcolor = py_color(sp[:foreground_color_grid])
pyaxis[:grid](true, color = fgcolor, linestyle = ":")
pyaxis[:grid](true, color = fgcolor)
ax[:set_axisbelow](true)
end
py_set_axis_colors(ax, axis)
@@ -1074,7 +1075,7 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
py_add_legend(plt, sp, ax)
# this sets the bg color inside the grid
ax[:set_facecolor](py_color(sp[:background_color_inside]))
ax[:set_axis_bgcolor](py_color(sp[:background_color_inside]))
end
py_drawfig(fig)
end
@@ -1106,7 +1107,7 @@ function _update_min_padding!(sp::Subplot{PyPlotBackend})
# optionally add the width of colorbar labels and colorbar to rightpad
if haskey(sp.attr, :cbar_ax)
bb = py_bbox(sp.attr[:cbar_handle][:ax][:get_yticklabels]())
sp.attr[:cbar_width] = _cbar_width + width(bb) + 2.3mm + (sp[:colorbar_title] == "" ? 0px : 30px)
sp.attr[:cbar_width] = _cbar_width + width(bb) + 1mm + (sp[:colorbar_title] == "" ? 0px : 30px)
rightpad = rightpad + sp.attr[:cbar_width]
end
@@ -1187,7 +1188,6 @@ function py_add_legend(plt::Plot, sp::Subplot, ax)
# framealpha = 0.6
)
leg[:set_zorder](1000)
sp[:legendtitle] != nothing && leg[:set_title](sp[:legendtitle])
fgcolor = py_color(sp[:foreground_color_legend])
for txt in leg[:get_texts]()
+1 -1
View File
@@ -23,7 +23,7 @@ function open_browser_window(filename::AbstractString)
@static if is_apple()
return run(`open $(filename)`)
end
@static if is_linux() || is_bsd() # is_bsd() addition is as yet untested, but based on suggestion in https://github.com/JuliaPlots/Plots.jl/issues/681
@static if is_linux()
return run(`xdg-open $(filename)`)
end
@static if is_windows()
+9 -9
View File
@@ -1,7 +1,7 @@
const P2 = FixedSizeArrays.Vec{2,Float64}
const P3 = FixedSizeArrays.Vec{3,Float64}
typealias P2 FixedSizeArrays.Vec{2,Float64}
typealias P3 FixedSizeArrays.Vec{3,Float64}
nanpush!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); push!(a, b))
nanappend!(a::AbstractVector{P2}, b) = (push!(a, P2(NaN,NaN)); append!(a, b))
@@ -174,7 +174,7 @@ function center(shape::Shape)
Cx / 6A, Cy / 6A
end
function scale!(shape::Shape, x::Real, y::Real = x, c = center(shape))
function Base.scale!(shape::Shape, x::Real, y::Real = x, c = center(shape))
sx, sy = coords(shape)
cx, cy = c
for i=1:length(sx)
@@ -184,7 +184,7 @@ function scale!(shape::Shape, x::Real, y::Real = x, c = center(shape))
shape
end
function scale(shape::Shape, x::Real, y::Real = x, c = center(shape))
function Base.scale(shape::Shape, x::Real, y::Real = x, c = center(shape))
shapecopy = deepcopy(shape)
scale!(shapecopy, x, y, c)
end
@@ -501,7 +501,7 @@ immutable ZValues
zrange::Tuple{Float64,Float64}
end
function zvalues{T<:Real}(values::AVec{T}, zrange::Tuple{T,T} = (ignoreNaN_minimum(values), ignoreNaN_maximum(values)))
function zvalues{T<:Real}(values::AVec{T}, zrange::Tuple{T,T} = (minimum(values), maximum(values)))
ZValues(collect(float(values)), map(Float64, zrange))
end
@@ -521,7 +521,7 @@ Base.Array(surf::Surface) = surf.surf
for f in (:length, :size)
@eval Base.$f(surf::Surface, args...) = $f(surf.surf, args...)
end
Base.copy(surf::Surface) = Surface(copy(surf.surf))
Base.copy(surf::Surface) = Surface{typeof(surf.surf)}(copy(surf.surf))
Base.eltype{T}(surf::Surface{T}) = eltype(T)
function expand_extrema!(a::Axis, surf::Surface)
@@ -645,8 +645,8 @@ function (bc::BezierCurve)(t::Real)
p
end
# mean(x::Real, y::Real) = 0.5*(x+y) #commented out as I cannot see this used anywhere and it overwrites a Base method with different functionality
# mean{N,T<:Real}(ps::FixedSizeArrays.Vec{N,T}...) = sum(ps) / length(ps) # I also could not see this used anywhere, and it's type piracy - implementing a NaNMath version for this would just involve converting to a standard array
Base.mean(x::Real, y::Real) = 0.5*(x+y)
Base.mean{N,T<:Real}(ps::FixedSizeArrays.Vec{N,T}...) = sum(ps) / length(ps)
@deprecate curve_points coords
@@ -659,7 +659,7 @@ function directed_curve(args...; kw...)
end
function extrema_plus_buffer(v, buffmult = 0.2)
vmin,vmax = ignoreNaN_extrema(v)
vmin,vmax = extrema(v)
vdiff = vmax-vmin
buffer = vdiff * buffmult
vmin - buffer, vmax + buffer
+1 -1
View File
@@ -5,7 +5,7 @@
# 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
const FuncOrFuncs = @compat(Union{Function, AVec{Function}})
typealias FuncOrFuncs @compat(Union{Function, AVec{Function}})
all3D(d::KW) = trueOrAllTrue(st -> st in (:contour, :contourf, :heatmap, :surface, :wireframe, :contour3d, :image), get(d, :seriestype, :none))
+2 -28
View File
@@ -115,8 +115,7 @@ PlotExample("Line types",
PlotExample("Line styles",
"",
[:(begin
styles = filter(s -> s in Plots.supported_styles(), [:solid, :dash, :dot, :dashdot, :dashdotdot])
styles = reshape(styles, 1, length(styles)) # Julia 0.6 unfortunately gives an error when transposing symbol vectors
styles = filter(s -> s in Plots.supported_styles(), [:solid, :dash, :dot, :dashdot, :dashdotdot])'
n = length(styles)
y = cumsum(randn(20,n),1)
plot(y, line = (5, styles), label = map(string,styles))
@@ -301,32 +300,7 @@ PlotExample("Boxplot and Violin series recipes",
violin(singers, :VoicePart, :Height, line = 0, fill = (0.2, :blue))
boxplot!(singers, :VoicePart, :Height, line = (2,:black), fill = (0.3, :orange))
end)]
),
PlotExample("Animation with subplots",
"The `layout` macro can be used to create an animation with subplots.",
[:(begin
l = @layout([[a; b] c])
p = plot(plot([sin,cos],1,leg=false),
scatter([atan,cos],1,leg=false),
plot(log,1,xlims=(1,10π),ylims=(0,5),leg=false),layout=l)
anim = Animation()
for x = linspace(1,10π,100)
plot(push!(p,x,Float64[sin(x),cos(x),atan(x),cos(x),log(x)]))
frame(anim)
end
end)]
),
PlotExample("Spy",
"For a matrix `mat` with unique nonzeros `spy(mat)` returns a colorless plot. If `mat` has various different nonzero values, a colorbar is added. The colorbar can be disabled with `legend = nothing`. As always, the marker shape and size can be changed with `spy(mat, markersize = 3, markershape = :star)`",
[:(begin
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))
plot(spy(a, markershape = :dtriangle), spy(b), markersize = 3, title = ["Unique nonzeros" "Different nonzeros"])
end)]
),
)
]
+1 -1
View File
@@ -704,7 +704,7 @@ function link_axes!(axes::Axis...)
a1 = axes[1]
for i=2:length(axes)
a2 = axes[i]
expand_extrema!(a1, ignoreNaN_extrema(a2))
expand_extrema!(a1, extrema(a2))
for k in (:extrema, :discrete_values, :continuous_values, :discrete_map)
a2[k] = a1[k]
end
+2 -2
View File
@@ -271,7 +271,7 @@ function setup_ijulia()
show(io, MIME("text/html"), plt)
end
end
@eval set_ijulia_output("text/html")
set_ijulia_output("text/html")
end
end
@@ -318,7 +318,7 @@ function setup_atom()
# special handling for plotly... use PlotsDisplay
function Media.render(pane::Atom.PlotPane, plt::Plot{PlotlyBackend})
display(Plots.PlotsDisplay(), plt)
s = "PlotPane turned off. The plotly backend cannot render in the PlotPane due to javascript issues. Plotlyjs is similar to plotly and is compatible with the plot pane."
s = "PlotPane turned off. The plotly and plotlyjs backends cannot render in the PlotPane due to javascript issues."
Media.render(pane, Atom.div(Atom.HTML(s)))
end
end
+2 -9
View File
@@ -153,7 +153,7 @@ function _add_smooth_kw(kw_list::Vector{KW}, kw::KW)
if get(kw, :smooth, false)
x, y = kw[:x], kw[:y]
β, α = convert(Matrix{Float64}, [x ones(length(x))]) \ convert(Vector{Float64}, y)
sx = [ignoreNaN_minimum(x), ignoreNaN_maximum(x)]
sx = [minimum(x), maximum(x)]
sy = β * sx + α
push!(kw_list, merge(copy(kw), KW(
:seriestype => :path,
@@ -277,13 +277,6 @@ function _subplot_setup(plt::Plot, d::KW, kw_list::Vector{KW})
attr[Symbol(letter,k)] = v
end
end
for k in (:scale,), letter in (:x,:y,:z)
# Series recipes may need access to this information
lk = Symbol(letter,k)
if haskey(attr, lk)
kw[lk] = attr[lk]
end
end
end
sp_attrs[sp] = attr
end
@@ -364,7 +357,7 @@ function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
expand_extrema!(sp[:xaxis], (0,w))
expand_extrema!(sp[:yaxis], (0,h))
sp[:yaxis].d[:flip] = true
elseif !(st in (:pie, :histogram, :bins2d, :histogram2d))
elseif !(st in (:pie, :histogram, :histogram2d))
expand_extrema!(sp, d)
end
end
+60 -194
View File
@@ -225,7 +225,7 @@ end
fr = if yaxis[:scale] == :identity
0.0
else
NaNMath.min(axis_limits(yaxis)[1], ignoreNaN_minimum(y))
min(axis_limits(yaxis)[1], minimum(y))
end
end
newx, newy = zeros(3n), zeros(3n)
@@ -323,11 +323,10 @@ end
# create a bar plot as a filled step function
@recipe function f(::Type{Val{:bar}}, x, y, z)
procx, procy, xscale, yscale, baseline = _preprocess_barlike(d, x, y)
nx, ny = length(procx), length(procy)
nx, ny = length(x), length(y)
axis = d[:subplot][isvertical(d) ? :xaxis : :yaxis]
cv = [discrete_value!(axis, xi)[1] for xi=procx]
procx = if nx == ny
cv = [discrete_value!(axis, xi)[1] for xi=x]
x = if nx == ny
cv
elseif nx == ny + 1
0.5diff(cv) + cv[1:end-1]
@@ -338,9 +337,9 @@ end
# compute half-width of bars
bw = d[:bar_width]
hw = if bw == nothing
0.5ignoreNaN_mean(diff(procx))
0.5mean(diff(x))
else
Float64[0.5cycle(bw,i) for i=1:length(procx)]
Float64[0.5cycle(bw,i) for i=1:length(x)]
end
# make fillto a vector... default fills to 0
@@ -348,25 +347,20 @@ end
if fillto == nothing
fillto = 0
end
if (yscale in _logScales) && !all(_is_positive, fillto)
fillto = map(x -> _is_positive(x) ? typeof(baseline)(x) : baseline, fillto)
end
# create the bar shapes by adding x/y segments
xseg, yseg = Segments(), Segments()
for i=1:ny
yi = procy[i]
if !isnan(yi)
center = procx[i]
hwi = cycle(hw,i)
fi = cycle(fillto,i)
push!(xseg, center-hwi, center-hwi, center+hwi, center+hwi, center-hwi)
push!(yseg, yi, fi, fi, yi, yi)
end
center = x[i]
hwi = cycle(hw,i)
yi = y[i]
fi = cycle(fillto,i)
push!(xseg, center-hwi, center-hwi, center+hwi, center+hwi, center-hwi)
push!(yseg, yi, fi, fi, yi, yi)
end
# widen limits out a bit
expand_extrema!(axis, widen(ignoreNaN_extrema(xseg.pts)...))
expand_extrema!(axis, widen(extrema(xseg.pts)...))
# switch back
if !isvertical(d)
@@ -390,55 +384,9 @@ end
_bin_centers(v::AVec) = (v[1:end-1] + v[2:end]) / 2
_is_positive(x) = (x > 0) && !(x 0)
_positive_else_nan{T}(::Type{T}, x::Real) = _is_positive(x) ? T(x) : T(NaN)
function _scale_adjusted_values{T<:AbstractFloat}(::Type{T}, V::AbstractVector, scale::Symbol)
if scale in _logScales
[_positive_else_nan(T, x) for x in V]
else
[T(x) for x in V]
end
end
function _binbarlike_baseline{T<:Real}(min_value::T, scale::Symbol)
if (scale in _logScales)
!isnan(min_value) ? min_value / T(_logScaleBases[scale]^log10(2)) : T(1E-3)
else
zero(T)
end
end
function _preprocess_binbarlike_weights{T<:AbstractFloat}(::Type{T}, w, wscale::Symbol)
w_adj = _scale_adjusted_values(T, w, wscale)
w_min = ignoreNaN_minimum(w_adj)
w_max = ignoreNaN_maximum(w_adj)
baseline = _binbarlike_baseline(w_min, wscale)
w_adj, baseline
end
function _preprocess_barlike(d, x, y)
xscale = get(d, :xscale, :identity)
yscale = get(d, :yscale, :identity)
weights, baseline = _preprocess_binbarlike_weights(float(eltype(y)), y, yscale)
x, weights, xscale, yscale, baseline
end
function _preprocess_binlike(d, x, y)
xscale = get(d, :xscale, :identity)
yscale = get(d, :yscale, :identity)
T = float(promote_type(eltype(x), eltype(y)))
edge = T.(x)
weights, baseline = _preprocess_binbarlike_weights(T, y, yscale)
edge, weights, xscale, yscale, baseline
end
@recipe function f(::Type{Val{:barbins}}, x, y, z)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, x, y)
edge, weights = x, y
if (d[:bar_width] == nothing)
bar_width := diff(edge)
end
@@ -447,11 +395,11 @@ end
seriestype := :bar
()
end
@deps barbins bar
@deps barbins bins
@recipe function f(::Type{Val{:scatterbins}}, x, y, z)
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, x, y)
edge, weights = x, y
xerror := diff(edge)/2
x := _bin_centers(edge)
y := weights
@@ -461,65 +409,43 @@ end
@deps scatterbins scatter
function _stepbins_path(edge, weights, baseline::Real, xscale::Symbol, yscale::Symbol)
log_scale_x = xscale in _logScales
log_scale_y = yscale in _logScales
function _stepbins_path(edge, weights)
nbins = length(linearindices(weights))
if length(linearindices(edge)) != nbins + 1
error("Edge vector must be 1 longer than weight vector")
end
x = eltype(edge)[]
y = eltype(weights)[]
it_e, it_w = start(edge), start(weights)
a, it_e = next(edge, it_e)
last_w = eltype(weights)(NaN)
i = 1
while (!done(edge, it_e) && !done(edge, it_e))
b, it_e = next(edge, it_e)
w, it_w = next(weights, it_w)
px, it_e = next(edge, it_e)
py = zero(eltype(weights))
if (log_scale_x && a 0)
a = b/_logScaleBases[xscale]^3
end
npathpts = 2 * nbins + 2
x = Vector{eltype(px)}(npathpts)
y = Vector{eltype(py)}(npathpts)
if isnan(w)
if !isnan(last_w)
push!(x, a)
push!(y, baseline)
end
else
if isnan(last_w)
push!(x, a)
push!(y, baseline)
end
push!(x, a)
push!(y, w)
push!(x, b)
push!(y, w)
end
a = b
last_w = w
end
if (last_w != baseline)
push!(x, a)
push!(y, baseline)
x[1], y[1] = px, py
i = 2
while (i < npathpts - 1)
py, it_w = next(weights, it_w)
x[i], y[i] = px, py
i += 1
px, it_e = next(edge, it_e)
x[i], y[i] = px, py
i += 1
end
assert(i == npathpts)
x[end], y[end] = px, zero(py)
(x, y)
end
@recipe function f(::Type{Val{:stepbins}}, x, y, z)
edge, weights = x, y
axis = d[:subplot][Plots.isvertical(d) ? :xaxis : :yaxis]
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, x, y)
xpts, ypts = _stepbins_path(edge, weights, baseline, xscale, yscale)
if !isvertical(d)
xpts, ypts = _stepbins_path(edge, weights)
if !Plots.isvertical(d)
xpts, ypts = ypts, xpts
end
@@ -527,7 +453,7 @@ end
if d[:markershape] != :none
@series begin
seriestype := :scatter
x := _bin_centers(edge)
x := Plots._bin_centers(edge)
y := weights
fillrange := nothing
label := ""
@@ -542,15 +468,16 @@ end
x := xpts
y := ypts
seriestype := :path
ylims --> [0, 1.1 * maximum(weights)]
()
end
Plots.@deps stepbins path
function _auto_binning_nbins{N}(vs::NTuple{N,AbstractVector}, dim::Integer; mode::Symbol = :auto)
_cl(x) = ceil(Int, NaNMath.max(x, one(x)))
_cl(x) = max(ceil(Int, x), 1)
_iqr(v) = quantile(v, 0.75) - quantile(v, 0.25)
_span(v) = ignoreNaN_maximum(v) - ignoreNaN_minimum(v)
_span(v) = maximum(v) - minimum(v)
n_samples = length(linearindices(first(vs)))
# Estimator for number of samples in one row/column of bins along each axis:
@@ -558,11 +485,9 @@ function _auto_binning_nbins{N}(vs::NTuple{N,AbstractVector}, dim::Integer; mode
v = vs[dim]
if mode == :auto
30
elseif mode == :sqrt # Square-root choice
if mode == :sqrt # Square-root choice
_cl(sqrt(n))
elseif mode == :sturges # Sturges' formula
elseif mode == :sturges || mode ==:auto # Sturges' formula
_cl(log2(n)) + 1
elseif mode == :rice # Rice Rule
_cl(2 * n^(1/3))
@@ -572,7 +497,7 @@ function _auto_binning_nbins{N}(vs::NTuple{N,AbstractVector}, dim::Integer; mode
_cl(_span(v) / (2 * _iqr(v) / n^(1/3)))
else
error("Unknown auto-binning mode $mode")
end::Int
end
end
_hist_edge{N}(vs::NTuple{N,AbstractVector}, dim::Integer, binning::Integer) = StatsBase.histrange(vs[dim], binning, :left)
@@ -586,13 +511,13 @@ _hist_edges{N}(vs::NTuple{N,AbstractVector}, binning::Union{Integer, Symbol, Abs
map(dim -> _hist_edge(vs, dim, binning), (1:N...))
_hist_norm_mode(mode::Symbol) = mode
_hist_norm_mode(mode::Bool) = mode ? :pdf : :none
_hist_norm_mode(mode::Bool) = mode ? :norm : :none
function _make_hist{N}(vs::NTuple{N,AbstractVector}, binning; normed = false, weights = nothing)
edges = _hist_edges(vs, binning)
h = float( weights == nothing ?
StatsBase.fit(StatsBase.Histogram, vs, edges, closed = :left) :
StatsBase.fit(StatsBase.Histogram, vs, weights, edges, closed = :left)
StatsBase.fit(StatsBase.Histogram, vs, edges) :
StatsBase.fit(StatsBase.Histogram, vs, weights, edges)
)
normalize!(h, mode = _hist_norm_mode(normed))
end
@@ -643,10 +568,9 @@ end
if d[:seriestype] == :scatterbins
# Workaround, error bars currently not set correctly by scatterbins
edge, weights, xscale, yscale, baseline = _preprocess_binlike(d, h.edges[1], h.weights)
xerror --> diff(h.edges[1])/2
seriestype := :scatter
(Plots._bin_centers(edge), weights)
(Plots._bin_centers(h.edges[1]), h.weights)
else
(h.edges[1], h.weights)
end
@@ -919,7 +843,7 @@ end
# get the joined vector
function get_xy(v::AVec{OHLC}, x = 1:length(v))
xdiff = 0.3ignoreNaN_mean(abs(diff(x)))
xdiff = 0.3mean(abs(diff(x)))
x_out, y_out = zeros(0), zeros(0)
for (i,ohlc) in enumerate(v)
ox,oy = get_xy(ohlc, x[i], xdiff)
@@ -976,9 +900,6 @@ end
@assert length(g.args) == 1 && typeof(g.args[1]) <: AbstractMatrix
seriestype := :spy
mat = g.args[1]
if length(unique(mat[mat .!= 0])) < 2
legend --> nothing
end
n,m = size(mat)
Plots.SliceIt, 1:m, 1:n, Surface(mat)
end
@@ -987,8 +908,8 @@ end
yflip := true
aspect_ratio := 1
rs, cs, zs = findnz(z.surf)
xlim := ignoreNaN_extrema(cs)
ylim := ignoreNaN_extrema(rs)
xlim := extrema(cs)
ylim := extrema(rs)
if d[:markershape] == :none
markershape := :circle
end
@@ -1002,7 +923,6 @@ end
y := rs
z := nothing
seriestype := :scatter
grid --> false
()
end
@@ -1010,7 +930,7 @@ end
"Adds a+bx... straight line over the current plot"
function abline!(plt::Plot, a, b; kw...)
plot!(plt, [ignoreNaN_extrema(plt)...], x -> b + a*x; kw...)
plot!(plt, [extrema(plt)...], x -> b + a*x; kw...)
end
abline!(args...; kw...) = abline!(current(), args...; kw...)
@@ -1019,70 +939,16 @@ abline!(args...; kw...) = abline!(current(), args...; kw...)
# -------------------------------------------------
# Dates
dateformatter(dt) = string(convert(Date, dt))
datetimeformatter(dt) = string(convert(DateTime, dt))
@recipe f(::Type{Date}, dt::Date) = (dt -> convert(Int, dt), dateformatter)
@recipe f(::Type{DateTime}, dt::DateTime) = (dt -> convert(Int, dt), datetimeformatter)
@recipe f(::Type{Date}, dt::Date) = (dt -> convert(Int,dt), dt -> string(convert(Date,dt)))
@recipe f(::Type{DateTime}, dt::DateTime) = (dt -> convert(Int,dt), dt -> string(convert(DateTime,dt)))
# -------------------------------------------------
# Complex Numbers
@recipe function f{T<:Number}(A::Array{Complex{T}})
xguide --> "Re(x)"
yguide --> "Im(x)"
real.(A), imag.(A)
end
# Splits a complex matrix to its real and complex parts
# Reals defaults solid, imaginary defaults dashed
# Label defaults are changed to match the real-imaginary reference / indexing
@recipe function f{T<:Real,T2}(x::AbstractArray{T},y::Array{Complex{T2}})
ylabel --> "Re(y)"
zlabel --> "Im(y)"
x,real.(y),imag.(y)
end
# --------------------------------------------------
# Color Gradients
@userplot ShowLibrary
@recipe function f(cl::ShowLibrary)
if !(length(cl.args) == 1 && isa(cl.args[1], Symbol))
error("showlibrary takes the name of a color library as a Symbol")
end
library = PlotUtils.color_libraries[cl.args[1]]
z = sqrt.((1:15)*(1:20)')
seriestype := :heatmap
ticks := nothing
legend := false
layout --> length(library.lib)
i = 0
for grad in sort(collect(keys(library.lib)))
@series begin
seriescolor := cgrad(grad, cl.args[1])
title := string(grad)
subplot := i += 1
z
end
end
end
@userplot ShowGradient
@recipe function f(grad::ShowGradient)
if !(length(grad.args) == 1 && isa(grad.args[1], Symbol))
error("showgradient takes the name of a color gradient as a Symbol")
end
z = sqrt.((1:15)*(1:20)')
seriestype := :heatmap
ticks := nothing
legend := false
seriescolor := grad.args[1]
title := string(grad.args[1])
z
@userplot ComplexPlot
@recipe function f(cp::ComplexPlot)
xguide --> "Real Part"
yguide --> "Imaginary Part"
seriestype --> :scatter
real(cp.args[1]), imag(cp.args[1])
end
+1 -2
View File
@@ -317,10 +317,9 @@ end
# # images - colors
@recipe function f{T<:Colorant}(mat::AMat{T})
n, m = size(mat)
if is_seriestype_supported(:image)
seriestype := :image
n, m = size(mat)
SliceIt, 1:m, 1:n, Surface(mat)
else
seriestype := :heatmap
+1 -1
View File
@@ -39,7 +39,7 @@ series_list(sp::Subplot) = sp.series_list # filter(series -> series.d[:subplot]
function should_add_to_legend(series::Series)
series.d[:primary] && series.d[:label] != "" &&
!(series.d[:seriestype] in (
:hexbin,:bins2d,:histogram2d,:hline,:vline,
:hexbin,:histogram2d,:hline,:vline,
:contour,:contourf,:contour3d,:surface,:wireframe,
:heatmap, :pie, :image
))
+2 -4
View File
@@ -2,8 +2,7 @@
function theme(s::Symbol; kw...)
# reset?
if s == :none || s == :default
PlotUtils.clibrary(:Plots)
PlotUtils.default_cgrad(default = :sequential, sequential = :inferno)
PlotUtils._default_gradient[] = :inferno
default(;
bg = :white,
bglegend = :match,
@@ -24,8 +23,7 @@ function theme(s::Symbol; kw...)
# update the default gradient and other defaults
thm = PlotThemes._themes[s]
if thm.gradient != nothing
PlotUtils.clibrary(:misc)
PlotUtils.default_cgrad(default = :sequential, sequential = PlotThemes.gradient_name(s))
PlotUtils._default_gradient[] = PlotThemes.gradient_name(s)
end
default(;
bg = thm.bg_secondary,
+4 -4
View File
@@ -2,9 +2,9 @@
# TODO: I declare lots of types here because of the lacking ability to do forward declarations in current Julia
# I should move these to the relevant files when something like "extern" is implemented
const AVec = AbstractVector
const AMat = AbstractMatrix
const KW = Dict{Symbol,Any}
typealias AVec AbstractVector
typealias AMat AbstractMatrix
typealias KW Dict{Symbol,Any}
immutable PlotsDisplay <: Display end
@@ -62,7 +62,7 @@ Extrema() = Extrema(Inf, -Inf)
# -----------------------------------------------------------
const SubplotMap = Dict{Any, Subplot}
typealias SubplotMap Dict{Any, Subplot}
# -----------------------------------------------------------
+15 -15
View File
@@ -3,7 +3,7 @@ calcMidpoints(edges::AbstractVector) = Float64[0.5 * (edges[i] + edges[i+1]) for
"Make histogram-like bins of data"
function binData(data, nbins)
lo, hi = ignoreNaN_extrema(data)
lo, hi = extrema(data)
edges = collect(linspace(lo, hi, nbins+1))
midpoints = calcMidpoints(edges)
buckets = Int[max(2, min(searchsortedfirst(edges, x), length(edges)))-1 for x in data]
@@ -109,7 +109,7 @@ function regressionXY(x, y)
β, α = convert(Matrix{Float64}, [x ones(length(x))]) \ convert(Vector{Float64}, y)
# make a line segment
regx = [ignoreNaN_minimum(x), ignoreNaN_maximum(x)]
regx = [minimum(x), maximum(x)]
regy = β * regx + α
regx, regy
end
@@ -283,9 +283,9 @@ unzip{T}(xyuv::FixedSizeArrays.Vec{4,T}) = T[xyuv[1]], T[xyuv[2]], T[xyuv[
# given 2-element lims and a vector of data x, widen lims to account for the extrema of x
function _expand_limits(lims, x)
try
e1, e2 = ignoreNaN_extrema(x)
lims[1] = NaNMath.min(lims[1], e1)
lims[2] = NaNMath.max(lims[2], e2)
e1, e2 = extrema(x)
lims[1] = min(lims[1], e1)
lims[2] = max(lims[2], e2)
# catch err
# warn(err)
end
@@ -334,23 +334,23 @@ sortedkeys(d::Dict) = sort(collect(keys(d)))
"create an (n+1) list of the outsides of heatmap rectangles"
function heatmap_edges(v::AVec)
vmin, vmax = ignoreNaN_extrema(v)
vmin, vmax = extrema(v)
extra = 0.5 * (vmax-vmin) / (length(v)-1)
vcat(vmin-extra, 0.5 * (v[1:end-1] + v[2:end]), vmax+extra)
end
function calc_r_extrema(x, y)
xmin, xmax = ignoreNaN_extrema(x)
ymin, ymax = ignoreNaN_extrema(y)
r = 0.5 * NaNMath.min(xmax - xmin, ymax - ymin)
ignoreNaN_extrema(r)
xmin, xmax = extrema(x)
ymin, ymax = extrema(y)
r = 0.5 * min(xmax - xmin, ymax - ymin)
extrema(r)
end
function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y))
rmin, rmax = r_extrema
phi, r = x, y
r = (r - rmin) / (rmax - rmin)
r = 0.5 * (r - rmin) / (rmax - rmin)
n = max(length(phi), length(r))
x = zeros(n)
y = zeros(n)
@@ -645,7 +645,7 @@ end
# used in updating an existing series
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) + maximum(v))
extendSeriesData{T}(v::Range{T}, z::Real) = extendSeriesData(float(collect(v)), z)
extendSeriesData{T}(v::Range{T}, z::AVec) = extendSeriesData(float(collect(v)), z)
extendSeriesData{T}(v::AVec{T}, z::Real) = (push!(v, convert(T, z)); v)
@@ -871,9 +871,9 @@ mm2px(mm::Real) = float(px / MM_PER_PX)
"Smallest x in plot"
xmin(plt::Plot) = ignoreNaN_minimum([ignoreNaN_minimum(series.d[:x]) for series in plt.series_list])
xmin(plt::Plot) = minimum([minimum(series.d[:x]) for series in plt.series_list])
"Largest x in plot"
xmax(plt::Plot) = ignoreNaN_maximum([ignoreNaN_maximum(series.d[:x]) for series in plt.series_list])
xmax(plt::Plot) = maximum([maximum(series.d[:x]) for series in plt.series_list])
"Extrema of x-values in plot"
ignoreNaN_extrema(plt::Plot) = (xmin(plt), xmax(plt))
Base.extrema(plt::Plot) = (xmin(plt), xmax(plt))
+2 -2
View File
@@ -13,7 +13,7 @@ try
end
# using Plots # reexported by StatPlots
using Plots
using StatPlots
using FactCheck
using Glob
@@ -24,7 +24,7 @@ default(size=(500,300))
# TODO: use julia's Condition type and the wait() and notify() functions to initialize a Window, then wait() on a condition that
# is referenced in a button press callback (the button clicked callback will call notify() on that condition)
const _current_plots_version = v"0.11.3"
const _current_plots_version = v"0.9.6"
function image_comparison_tests(pkg::Symbol, idx::Int; debug = false, popup = isinteractive(), sigma = [1,1], eps = 1e-2)
+3 -5
View File
@@ -5,11 +5,9 @@ set -ex
sudo apt-get -qq update
# sudo apt-get install -y wkhtmltopdf
sudo apt-get install -y xfonts-75dpi xfonts-base
wget https://downloads.wkhtmltopdf.org/0.12/0.12.2/wkhtmltox-0.12.2_linux-precise-amd64.deb
sudo dpkg -i wkhtmltox-0.12.2_linux-precise-amd64.deb
# wget http://download.gna.org/wkhtmltopdf/0.12/0.12.2/wkhtmltox-0.12.2_linux-trusty-amd64.deb
# sudo dpkg -i wkhtmltox-0.12.2_linux-trusty-amd64.deb
sudo apt-get install -y xfonts-75dpi
wget http://download.gna.org/wkhtmltopdf/0.12/0.12.2/wkhtmltox-0.12.2_linux-trusty-amd64.deb
sudo dpkg -i wkhtmltox-0.12.2_linux-trusty-amd64.deb
wkhtmltoimage http://www.google.com test.png
ls
+16 -59
View File
@@ -19,74 +19,31 @@ img_eps = isinteractive() ? 1e-2 : 10e-2
# image_comparison_facts(:gadfly, skip=[4,6,23,24,27], eps=img_eps)
# end
facts("PyPlot") do
@fact pyplot() --> Plots.PyPlotBackend()
@fact backend() --> Plots.PyPlotBackend()
image_comparison_facts(:pyplot, skip=[6,25,30], eps=img_eps)
end
facts("GR") do
@fact gr() --> Plots.GRBackend()
@fact backend() --> Plots.GRBackend()
image_comparison_facts(:gr, eps=img_eps)
if is_linux() && isinteractive()
image_comparison_facts(:gr, skip=[2,25,30], eps=img_eps)
end
end
facts("Plotly") do
@fact plotly() --> Plots.PlotlyBackend()
@fact backend() --> Plots.PlotlyBackend()
facts("PyPlot") do
@fact pyplot() --> Plots.PyPlotBackend()
@fact backend() --> Plots.PyPlotBackend()
image_comparison_facts(:pyplot, eps=img_eps)
# # until png generation is reliable on OSX, just test on linux
# @static is_linux() && image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], eps=img_eps)
end
# The plotlyjs testimages return a connection error on travis:
# connect: connection refused (ECONNREFUSED)
# facts("PlotlyJS") do
# @fact plotlyjs() --> Plots.PlotlyJSBackend()
# @fact backend() --> Plots.PlotlyJSBackend()
#
# if is_linux() && isinteractive()
# image_comparison_facts(:plotlyjs,
# skip=[
# 2, # animation (skipped for speed)
# 27, # (polar plots) takes very long / not working
# 31, # animation (skipped for speed)
# ],
# eps=img_eps)
# end
# end
# InspectDR returns that error on travis:
# ERROR: LoadError: InitError: Cannot open display:
# in Gtk.GLib.GError(::Gtk.##229#230) at /home/travis/.julia/v0.5/Gtk/src/GLib/gerror.jl:17
# facts("InspectDR") do
# @fact inspectdr() --> Plots.InspectDRBackend()
# @fact backend() --> Plots.InspectDRBackend()
#
# image_comparison_facts(:inspectdr,
# skip=[
# 2, # animation
# 6, # heatmap not defined
# 10, # heatmap not defined
# 22, # contour not defined
# 23, # pie not defined
# 27, # polar plot not working
# 28, # heatmap not defined
# 31, # animation
# ],
# eps=img_eps)
# end
# facts("Plotly") do
# @fact plotly() --> Plots.PlotlyBackend()
# @fact backend() --> Plots.PlotlyBackend()
#
# # # until png generation is reliable on OSX, just test on linux
# # @static is_linux() && image_comparison_facts(:plotly, only=[1,3,4,7,8,9,10,11,12,14,15,20,22,23,27], eps=img_eps)
# end
# facts("Immerse") do
# @fact immerse() --> Plots.ImmerseBackend()
# @fact backend() --> Plots.ImmerseBackend()
@@ -121,12 +78,12 @@ facts("Axes") do
@fact typeof(axis) --> Plots.Axis
@fact Plots.discrete_value!(axis, "HI") --> (0.5, 1)
@fact Plots.discrete_value!(axis, :yo) --> (1.5, 2)
@fact Plots.ignoreNaN_extrema(axis) --> (0.5,1.5)
@fact extrema(axis) --> (0.5,1.5)
@fact axis[:discrete_map] --> Dict{Any,Any}(:yo => 2, "HI" => 1)
Plots.discrete_value!(axis, ["x$i" for i=1:5])
Plots.discrete_value!(axis, ["x$i" for i=0:2])
@fact Plots.ignoreNaN_extrema(axis) --> (0.5, 7.5)
@fact extrema(axis) --> (0.5, 7.5)
end
+6 -9
View File
@@ -1,8 +1,8 @@
Pkg.clone("ImageMagick")
Pkg.build("ImageMagick")
# Pkg.clone("ImageMagick")
# Pkg.build("ImageMagick")
Pkg.clone("GR")
Pkg.build("GR")
# Pkg.clone("GR")
# Pkg.build("GR")
Pkg.clone("https://github.com/JuliaPlots/PlotReferenceImages.jl.git")
@@ -11,12 +11,11 @@ Pkg.clone("https://github.com/JuliaPlots/PlotReferenceImages.jl.git")
Pkg.clone("StatPlots")
Pkg.checkout("PlotUtils")
# Pkg.clone("Blink")
# Pkg.clone("https://github.com/JunoLab/Blink.jl.git")
# Pkg.build("Blink")
# import Blink
# Blink.AtomShell.install()
# Pkg.add("Rsvg")
# Pkg.add("PlotlyJS")
# Pkg.clone("https://github.com/spencerlyon2/PlotlyJS.jl.git")
# Pkg.checkout("RecipesBase")
# Pkg.clone("VisualRegressionTests")
@@ -26,6 +25,4 @@ ENV["PYTHON"] = ""
Pkg.add("PyPlot")
Pkg.build("PyPlot")
# Pkg.add("InspectDR")
Pkg.test("Plots"; coverage=false)